[pypy-commit] stmgc default: progress

Raemi noreply at buildbot.pypy.org
Thu Sep 4 17:31:35 CEST 2014


Author: Remi Meier <remi.meier at inf.ethz.ch>
Branch: 
Changeset: r1352:6db6026fb9a6
Date: 2014-09-04 17:32 +0200
http://bitbucket.org/pypy/stmgc/changeset/6db6026fb9a6/

Log:	progress

diff --git a/c8/stm/core.c b/c8/stm/core.c
--- a/c8/stm/core.c
+++ b/c8/stm/core.c
@@ -7,6 +7,28 @@
 
 /* ############# signal handler ############# */
 
+static void bring_page_up_to_date(uintptr_t pagenum)
+{
+    /* pagecopy from somewhere readable, then update
+       all written objs from that segment */
+    long i;
+    int my_segnum = STM_SEGMENT->segment_num;
+
+    for (i = 0; i < NB_SEGMENTS; i++) {
+        if (i == my_segnum)
+            continue;
+        if (!is_readable_page(i, first_page))
+            continue;
+
+        acquire_privatization_lock(i);
+
+        /* copy the content from there to our segment */
+        pagecopy(new_page, get_segment_base(from_segnum) + pagenum * 4096UL);
+
+        release_privatization_lock(i);
+    }
+}
+
 void _signal_handler(int sig, siginfo_t *siginfo, void *context)
 {
     char *addr = siginfo->si_addr;
@@ -31,7 +53,7 @@
        so it needs additional synchronisation.*/
     pages_set_protection(segnum, pagenum, 1, PROT_READ|PROT_WRITE);
 
-    page_privatize(pagenum);
+    bring_page_up_to_date(pagenum);
 
     /* XXX: ... what can go wrong when we abort from inside
        the signal handler? */
@@ -143,20 +165,11 @@
 
 /* ############# STM ############# */
 
-void _stm_write_slowpath(object_t *obj)
+void _privatize_and_protect_other_segments(object_t *obj)
 {
-    assert(_seems_to_be_running_transaction());
-    assert(!_is_in_nursery(obj));
-    assert(obj->stm_flags & GCFLAG_WRITE_BARRIER);
+    assert(STM_PSEGMENT->privatization_lock); /* we hold it */
+    assert(obj_size < 4096); /* too lazy right now (part of the code is ready) */
 
-    stm_read(obj);
-
-    /* XXX: misses synchronisation with other write_barriers
-       on same page */
-    /* XXX: make backup copy */
-    /* XXX: privatize pages if necessary */
-
-    /* make other segments trap if accessing this object */
     uintptr_t first_page = ((uintptr_t)obj) / 4096UL;
     char *realobj;
     size_t obj_size;
@@ -167,24 +180,85 @@
     obj_size = stmcb_size_rounded_up((struct object_s *)realobj);
     end_page = (((uintptr_t)obj) + obj_size - 1) / 4096UL;
 
+    /* privatize pages: */
+    /* get the last page containing data from the object */
+    end_page = (((uintptr_t)obj) + obj_size - 1) / 4096UL;
+    for (i = first_page; i <= end_page; i++) {
+        if (is_private_page(my_segnum, i))
+            continue;
+        page_privatize(i);
+        bring_page_up_to_date(i);
+    }
+
+    /* then PROT_NONE everyone else that doesn't have a private
+       page already */
     for (i = 0; i < NB_SEGMENTS; i++) {
         if (i == my_segnum)
             continue;
-        if (!is_readable_page(i, first_page))
+        if (!is_readable_page(i, first_page) || is_private_page(i, first_page))
             continue;
-        /* XXX: only do it if not already PROT_NONE */
-        char *segment_base = get_segment_base(i);
+
+        acquire_privatization_lock(i);
         pages_set_protection(i, first_page, end_page - first_page + 1,
                              PROT_NONE);
+        release_privatization_lock(i);
+
         dprintf(("prot %lu, len=%lu in seg %lu\n", first_page, (end_page - first_page + 1), i));
     }
+}
 
+void _stm_write_slowpath(object_t *obj)
+{
+    assert(_seems_to_be_running_transaction());
+    assert(!_is_in_nursery(obj));
+    assert(obj->stm_flags & GCFLAG_WRITE_BARRIER);
+
+    int my_segnum = STM_SEGMENT->segment_num;
+    uintptr_t first_page = ((uintptr_t)obj) / 4096UL;
+    char *realobj;
+    size_t obj_size;
+
+    realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
+    obj_size = stmcb_size_rounded_up((struct object_s *)realobj);
+
+    /* add to read set: */
+    stm_read(obj);
+
+    /* create backup copy: */
+    struct object_s *bk_obj = malloc(obj_size);
+    memcpy(bk_obj, realobj, obj_size);
+
+    assert(obj_size < 4096); /* too lazy right now (part of the code is ready) */
+
+ retry:
+    acquire_privatization_lock(my_segnum);
+    if (!is_readable_page(my_segnum, first_page)) {
+        release_privatization_lock(my_segnum);
+
+        bring_page_up_to_date(first_page);
+
+        spin_loop();
+        goto retry;
+    }
+    /* page is not PROT_NONE for us, we can PROT_NONE all others */
+    _privatize_and_protect_other_segments(obj);
+
+    /* remove the WRITE_BARRIER flag (could be done later, but I
+       think we find more bugs this way) */
+    obj->stm_flags &= ~GCFLAG_WRITE_BARRIER;
+
+    /* done fiddling with protection and privatization */
+    release_privatization_lock(my_segnum);
+
+    /* phew, now add the obj to the write-set and register the
+       backup copy. */
     acquire_modified_objs_lock(my_segnum);
-    tree_insert(STM_PSEGMENT->modified_old_objects, (uintptr_t)obj, 0);
+    tree_insert(STM_PSEGMENT->modified_old_objects,
+                (uintptr_t)obj, (uintptr_t)bk_obj);
     release_modified_objs_lock(my_segnum);
 
+    /* also add it to the GC list for minor collections */
     LIST_APPEND(STM_PSEGMENT->objects_pointing_to_nursery, obj);
-    obj->stm_flags &= ~GCFLAG_WRITE_BARRIER;
 }
 
 static void reset_transaction_read_version(void)
diff --git a/c8/stm/core.h b/c8/stm/core.h
--- a/c8/stm/core.h
+++ b/c8/stm/core.h
@@ -115,30 +115,22 @@
     asm("/* workaround for llvm bug */");
 }
 
-static inline void acquire_privatization_lock(void)
+static inline void acquire_privatization_lock(int segnum)
 {
-    uint8_t *lock = (uint8_t *)REAL_ADDRESS(STM_SEGMENT->segment_base,
-                                            &STM_PSEGMENT->privatization_lock);
-    spinlock_acquire(*lock);
+    spinlock_acquire(get_priv_segment(segnum)->privatization_lock);
 }
 
-static inline void release_privatization_lock(void)
+static inline void release_privatization_lock(int segnum)
 {
-    uint8_t *lock = (uint8_t *)REAL_ADDRESS(STM_SEGMENT->segment_base,
-                                            &STM_PSEGMENT->privatization_lock);
-    spinlock_release(*lock);
+    spinlock_release(get_priv_segment(segnum)->privatization_lock);
 }
 
 static inline void acquire_modified_objs_lock(int segnum)
 {
-    uint8_t *lock = (uint8_t *)REAL_ADDRESS(get_segment_base(segnum),
-                                            &STM_PSEGMENT->modified_objs_lock);
-    spinlock_acquire(*lock);
+    spinlock_acquire(get_priv_segment(segnum)->modified_objs_lock);
 }
 
 static inline void release_modified_objs_lock(int segnum)
 {
-    uint8_t *lock = (uint8_t *)REAL_ADDRESS(get_segment_base(segnum),
-                                            &STM_PSEGMENT->modified_objs_lock);
-    spinlock_release(*lock);
+    spinlock_release(get_priv_segment(segnum)->modified_objs_lock);
 }
diff --git a/c8/stm/pages.c b/c8/stm/pages.c
--- a/c8/stm/pages.c
+++ b/c8/stm/pages.c
@@ -74,12 +74,17 @@
         while (amount-->0) {
             volatile struct page_shared_s *ps = (volatile struct page_shared_s *)
                 &pages_readable[pagenum + amount - PAGE_FLAG_START];
+            volatile struct page_shared_s *ps2 = (volatile struct page_shared_s *)
+                &pages_privatized[pagenum + amount - PAGE_FLAG_START];
+
             if (i == 0) {
-                /* readable */
+                /* readable & private */
                 ps->by_segment |= bitmask;
+                ps2->by_segment |= bitmask;
             } else {
-                /* not readable (ensured in setup.c) */
+                /* not readable (ensured in setup.c), not private */
                 ps->by_segment &= ~bitmask;
+                ps2->by_segment &= ~bitmask;
             }
         }
     }
@@ -87,6 +92,9 @@
 
 static void page_privatize(uintptr_t pagenum)
 {
+    /* hopefully holding the lock */
+    assert(STM_PSEGMENT->privatization_lock);
+
     /* check this thread's 'pages_privatized' bit */
     uint64_t bitmask = 1UL << STM_SEGMENT->segment_num;
     volatile struct page_shared_s *ps = (volatile struct page_shared_s *)
@@ -96,11 +104,6 @@
         return;
     }
 
-    long i;
-    for (i = 0; i < NB_SEGMENTS; i++) {
-        spinlock_acquire(get_priv_segment(i)->privatization_lock);
-    }
-
     /* add this thread's 'pages_privatized' bit */
     ps->by_segment |= bitmask;
 
@@ -111,18 +114,14 @@
     uintptr_t pagenum_in_file = NB_PAGES * STM_SEGMENT->segment_num + pagenum;
     char *new_page = stm_object_pages + pagenum_in_file * 4096UL;
     d_remap_file_pages(new_page, 4096, pagenum_in_file);
-
-    /* copy the content from the shared (segment 0) source */
-    pagecopy(new_page, stm_object_pages + pagenum * 4096UL);
-
-    for (i = NB_SEGMENTS-1; i >= 0; i--) {
-        spinlock_release(get_priv_segment(i)->privatization_lock);
-    }
 }
 
 static void pages_set_protection(int segnum, uintptr_t pagenum,
                                  uintptr_t count, int prot)
 {
+    /* we hopefully hold the privatization lock: */
+    assert(get_priv_segment(segnum)->privatization_lock);
+
     char *addr = get_segment_base(segnum) + pagenum * 4096UL;
     mprotect(addr, count * 4096UL, prot);
 


More information about the pypy-commit mailing list