Commits

Remi Meier committed 578f115

import stmgc with various fixes

Comments (0)

Files changed (7)

rpython/translator/stm/src_stm/et.c

       W = LocalizePublic(d, R);
       assert(is_private(W));
 
-      if (W->h_tid & GCFLAG_OLD)
+      if (W->h_tid & GCFLAG_OLD) {
+        /* XXX: probably unnecessary as it is done in allocate_next_section
+           already */
         gcptrlist_insert(&d->old_objects_to_trace, W);
-      else
+      } else
         gcptrlist_insert(&d->public_with_young_copy, R);
     }
   else
   smp_spinloop();
 }
 
+static void purge_private_objs_from_old_objects_to_trace()
+{
+  struct tx_descriptor *d = thread_descriptor;
+  int i, size = d->old_objects_to_trace.size;
+  gcptr *items = d->old_objects_to_trace.items;
+
+  for(i = 0; i < size; i++) {
+    if (items[i] && items[i]->h_revision == stm_private_rev_num) {
+      /* private objects from the same aborting transaction */
+      items[i] = NULL;
+      dprintf(("purge old private object %p\n", items[i]));
+    }
+  }
+}
+
 void stm_abort_and_retry(void)
 {
     AbortTransaction(ABRT_MANUAL);
   stm_thread_local_obj = d->old_thread_local_obj;
   d->old_thread_local_obj = NULL;
 
+  /* remove old private objects from old_objects_to_trace
+     because they never have to be traced (also because
+     weakrefs are kept alive even when their target is not
+     and stm_move_young_weakrefs doesn't handle that). */
+  purge_private_objs_from_old_objects_to_trace();
+
   // notifies the CPU that we're potentially in a spin loop
   SpinLoop(SPLP_ABORT);
 
           /* there may be a thread holding the collection lock
              because it steals a stub belonging to the thread
              that previously owned this descriptor.
+             (not currently, as we do a start_exclusivelock()
+             before calling DescriptorInit)
           */
       }
       else {
     gcptrlist_delete(&d->public_descriptor->stolen_objects);
     gcptrlist_delete(&d->public_descriptor->stolen_young_stubs);
 
+    assert(d->young_weakrefs.size == 0);
+    assert(d->public_with_young_copy.size == 0);
+    assert(d->old_objects_to_trace.size == 0);
+
     stmgcpage_done_tls();
     i = d->public_descriptor_index;
     assert(stm_descriptor_array[i] == d->public_descriptor);

rpython/translator/stm/src_stm/et.h

 #define SPLP_LOCKED_INFLIGHT      1
 #define SPLP_LOCKED_VALIDATE      2
 #define SPLP_LOCKED_COMMIT        3
-#define SPINLOOP_REASONS      4
+#define SPLP_LOCKED_COLLECT       4
+#define SPINLOOP_REASONS      5
 
 /* this struct contains thread-local data that may be occasionally
  * accessed by a foreign thread and that must stay around after the

rpython/translator/stm/src_stm/nursery.c

            || *d->nursery_current_ref == d->nursery_end);
     stm_free(d->nursery_base);
 
+    assert(d->public_with_young_copy.size == 0);
+    assert(d->old_objects_to_trace.size == 0);
+    assert(d->young_weakrefs.size == 0);
     gcptrlist_delete(&d->old_objects_to_trace);
     gcptrlist_delete(&d->public_with_young_copy);
     gcptrlist_delete(&d->young_weakrefs);
 
 static void trace_stub(struct tx_descriptor *d, gcptr S)
 {
-    revision_t w = ACCESS_ONCE(S->h_revision);
+    /* ignore stub if it is outdated, because then the transaction
+       will abort (or has been aborted long ago) */
+
+    revision_t w;
+
+ retry:
+    w = ACCESS_ONCE(S->h_revision);    
+    if (!IS_POINTER(w) && w >= LOCKED) {
+        /* check again when unlocked */
+        SpinLoop(SPLP_LOCKED_COLLECT);
+        goto retry;
+    }
+
     if ((w & 3) != 2) {
         /* P has a ptr in h_revision, but this object is not a stub
            with a protected pointer.  It has likely been the case
     */
     long i, size = d->public_with_young_copy.size;
     gcptr *items = d->public_with_young_copy.items;
+    revision_t v;
 
     for (i = 0; i < size; i++) {
         gcptr P = items[i];
         assert(P->h_tid & GCFLAG_OLD);
         assert(P->h_tid & GCFLAG_PUBLIC_TO_PRIVATE);
 
-        revision_t v = ACCESS_ONCE(P->h_revision);
+        v = ACCESS_ONCE(P->h_revision);
         wlog_t *item;
         G2L_FIND(d->public_to_private, P, item, goto not_in_public_to_private);
 
                  item->addr, item->val));
         assert(_stm_is_private(item->val));
         visit_if_young(&item->val);
+        assert(item->val->h_tid & GCFLAG_OLD);
         continue;
 
     not_in_public_to_private:
+        /* re-read because of possible spinloop */
+        v = ACCESS_ONCE(P->h_revision);
+
         if (!IS_POINTER(v)) {
+            if (v >= LOCKED) {
+                /* check again when unlocked */
+                SpinLoop(SPLP_LOCKED_COLLECT);
+                goto not_in_public_to_private;
+            }
             /* P is neither a key in public_to_private nor outdated.
                It must come from an older transaction that aborted.
                Nothing to do now.
 {
     while (gcptrlist_size(&d->old_objects_to_trace) > 0) {
         gcptr obj = gcptrlist_pop(&d->old_objects_to_trace);
-
+        if (!obj)
+            continue;
         assert(obj->h_tid & GCFLAG_OLD);
         assert(!(obj->h_tid & GCFLAG_WRITE_BARRIER));
 

rpython/translator/stm/src_stm/revision

-b89b61f0df98
+b820cff55e7a

rpython/translator/stm/src_stm/steal.c

     memset(&sd.all_stubs, 0, sizeof(sd.all_stubs));
     steal_data = &sd;
     stmgc_trace(L, &replace_ptr_to_protected_with_stub);
-    if (L->h_tid & GCFLAG_WEAKREF)
+    if (L->h_tid & GCFLAG_WEAKREF) {
+        /* We have to trace the weakref manually because stmgc_trace
+           doesn't */
         replace_ptr_to_protected_with_stub(WEAKREF_PTR(L, stmgc_size(L)));
+    }
     g2l_delete_not_used_any_more(&sd.all_stubs);
 
     /* If another thread (the foreign or a 3rd party) does a read

rpython/translator/stm/src_stm/stmsync.c

            XXX: remove again when sure it is not needed
                 (interaction with stop_all_other_threads()) */
         start_exclusivelock();
+        assert(stm_active == 0);
         stmgcpage_acquire_global_lock();
 #ifdef STM_BARRIER_COUNT
         static int seen = 0;
 
     if (token == 1) {
         start_exclusivelock();
+        assert(stm_active == 0);
         stmgcpage_acquire_global_lock();
         done_shadowstack();
         stmgc_done_nursery();
     ACCESS_ONCE(sync_required) = -1;
     stm_stop_sharedlock();
     start_exclusivelock();
+    if (stm_active < 0) {
+        /* we have to give up and abort. Another thread did
+           a major collect and makes us abort now */
+        stop_exclusivelock();
+        stm_start_sharedlock();
+        assert(stm_active < 0);
+        AbortNowIfDelayed();
+    }
     ACCESS_ONCE(sync_required) = 0;
 
     assert(in_single_thread == NULL);
 
     stop_exclusivelock();
     stm_start_sharedlock();
+
+    /* another thread may commit, start a major collect, and
+       make us abort */
+    AbortNowIfDelayed();
 }
 
 void stm_possible_safe_point(void)

rpython/translator/stm/src_stm/weakref.c

 
         if (stmgc_is_in_nursery(d, pointing_to)) {
             if (pointing_to->h_tid & GCFLAG_MOVED) {
+                gcptr to = (gcptr)pointing_to->h_revision;
                 dprintf(("weakref ptr moved %p->%p\n", 
-                         *WEAKREF_PTR(weakref, size),
-                         (gcptr)pointing_to->h_revision));
-                *WEAKREF_PTR(weakref, size) = (gcptr)pointing_to->h_revision;
+                         *WEAKREF_PTR(weakref, size), to));
+                *WEAKREF_PTR(weakref, size) = to;
+                assert(to->h_tid & GCFLAG_OLD);
+                assert(!(to->h_tid & GCFLAG_MOVED));
+                assert(!(pointing_to->h_tid & GCFLAG_OLD));
             }
             else {
                 assert(!IS_POINTER(pointing_to->h_revision));
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.