Author: Armin Rigo <[email protected]>
Branch: c7-refactor
Changeset: r830:f661c584decd
Date: 2014-02-24 16:17 +0100
http://bitbucket.org/pypy/stmgc/changeset/f661c584decd/

Log:    synchronize_overflow_object_now().

diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -171,6 +171,7 @@
     assert(list_is_empty(STM_PSEGMENT->modified_old_objects));
     assert(STM_PSEGMENT->old_objects_pointing_to_nursery == NULL);
     assert(STM_PSEGMENT->overflow_objects_pointing_to_nursery == NULL);
+    assert(STM_PSEGMENT->large_overflow_objects == NULL);
 
 #ifdef STM_TESTS
     check_nursery_at_transaction_start();
@@ -214,6 +215,60 @@
         }));
 }
 
+static void synchronize_overflow_object_now(object_t *obj)
+{
+    assert(!_is_in_nursery(obj));
+    assert((obj->stm_flags & GCFLAG_SMALL_UNIFORM) == 0);
+
+    char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
+    ssize_t obj_size = stmcb_size_rounded_up((struct object_s *)realobj);
+    uintptr_t start = (uintptr_t)obj;
+    uintptr_t end = start + obj_size;
+    uintptr_t first_page = start / 4096UL;
+    uintptr_t last_page = (end - 1) / 4096UL;
+
+    do {
+        if (flag_page_private[first_page] != SHARED_PAGE) {
+            /* The page is a PRIVATE_PAGE.  We need to diffuse this fragment
+               of our object from our own segment to all other segments. */
+
+            uintptr_t copy_size;
+            if (first_page == last_page) {
+                /* this is the final fragment */
+                copy_size = end - start;
+            }
+            else {
+                /* this is a non-final fragment, going up to the page's end */
+                copy_size = 4096 - (start & 4095);
+            }
+
+            /* double-check that the result fits in one page */
+            assert(copy_size > 0);
+            assert(copy_size + (start & 4095) <= 4096);
+
+            long i;
+            char *src = REAL_ADDRESS(STM_SEGMENT->segment_base, start);
+            for (i = 0; i < NB_SEGMENTS; i++) {
+                if (i != STM_SEGMENT->segment_num) {
+                    char *dst = REAL_ADDRESS(get_segment_base(i), start);
+                    memcpy(dst, src, copy_size);
+                }
+            }
+        }
+
+        start = (start + 4096) & ~4095;
+    } while (first_page++ < last_page);
+}
+
+static void push_overflow_objects_from_privatized_pages(void)
+{
+    if (STM_PSEGMENT->large_overflow_objects == NULL)
+        return;
+
+    LIST_FOREACH_R(STM_PSEGMENT->large_overflow_objects, object_t *,
+                   synchronize_overflow_object_now(item));
+}
+
 static void push_modified_to_other_segments(void)
 {
     long remote_num = 1 - STM_SEGMENT->segment_num;
@@ -261,6 +316,7 @@
     /* reset these lists to NULL for the next transaction */
     LIST_FREE(STM_PSEGMENT->old_objects_pointing_to_nursery);
     LIST_FREE(STM_PSEGMENT->overflow_objects_pointing_to_nursery);
+    LIST_FREE(STM_PSEGMENT->large_overflow_objects);
 
     stm_thread_local_t *tl = STM_SEGMENT->running_thread;
     release_thread_segment(tl);
@@ -292,7 +348,10 @@
     assert(STM_PSEGMENT->transaction_state != TS_MUST_ABORT);
     STM_SEGMENT->jmpbuf_ptr = NULL;
 
-    /* copy modified object versions to other threads */
+    /* synchronize overflow objects living in privatized pages */
+    push_overflow_objects_from_privatized_pages();
+
+    /* synchronize modified old objects to other threads */
     push_modified_to_other_segments();
 
     /* update 'overflow_number' if needed */
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -82,6 +82,10 @@
        collection so far. */
     struct list_s *overflow_objects_pointing_to_nursery;
 
+    /* List of all large, overflowed objects.  Only non-NULL after the
+       current transaction spanned a minor collection. */
+    struct list_s *large_overflow_objects;
+
     /* Start time: to know approximately for how long a transaction has
        been running, in contention management */
     uint64_t start_time;
@@ -108,6 +112,9 @@
        only accessed when we hold the mutex. */
     uint8_t transaction_state;
 
+    /* Temp for minor collection */
+    bool minor_collect_will_commit_now;
+
     /* In case of abort, we restore the 'shadowstack' field. */
     object_t **shadowstack_at_start_of_transaction;
 };
@@ -190,3 +197,5 @@
         assert(!"commit: bad transaction_state");
     }
 }
+
+static void synchronize_overflow_object_now(object_t *obj);
diff --git a/c7/stm/list.h b/c7/stm/list.h
--- a/c7/stm/list.h
+++ b/c7/stm/list.h
@@ -40,7 +40,7 @@
     return (lst->count == 0);
 }
 
-static inline bool list_count(struct list_s *lst)
+static inline uintptr_t list_count(struct list_s *lst)
 {
     return lst->count;
 }
diff --git a/c7/stm/nursery.c b/c7/stm/nursery.c
--- a/c7/stm/nursery.c
+++ b/c7/stm/nursery.c
@@ -53,20 +53,6 @@
 #define GCWORD_MOVED  ((object_t *) -42)
 
 
-static inline void minor_copy_in_page_to_other_segments(uintptr_t p,
-                                                        size_t size)
-{
-    uintptr_t dataofs = (char *)p - stm_object_pages;
-    assert((dataofs & 4095) + size <= 4096);   /* fits in one page */
-
-    if (flag_page_private[dataofs / 4096UL] != SHARED_PAGE) {
-        long i;
-        for (i = 1; i < NB_SEGMENTS; i++) {
-            memcpy(get_segment_base(i) + dataofs, (char *)p, size);
-        }
-    }
-}
-
 static void minor_trace_if_young(object_t **pobj)
 {
     /* takes a normal pointer to a thread-local pointer to an object */
@@ -104,6 +90,11 @@
         /* Copy the object  */
         char *realnobj = REAL_ADDRESS(STM_SEGMENT->segment_base, nobj);
         memcpy(realnobj, realobj, size);
+
+        if (STM_PSEGMENT->minor_collect_will_commit_now)
+            synchronize_overflow_object_now(nobj);
+        else
+            LIST_APPEND(STM_PSEGMENT->large_overflow_objects, nobj);
     }
     else {
         /* case "small enough" */
@@ -181,8 +172,11 @@
 
     dprintf(("minor_collection commit=%d\n", (int)commit));
 
+    STM_PSEGMENT->minor_collect_will_commit_now = commit;
     if (STM_PSEGMENT->old_objects_pointing_to_nursery == NULL)
         STM_PSEGMENT->old_objects_pointing_to_nursery = list_create();
+    if (!commit && STM_PSEGMENT->large_overflow_objects == NULL)
+        STM_PSEGMENT->large_overflow_objects = list_create();
 
     collect_roots_in_nursery();
 
diff --git a/c7/stm/pages.c b/c7/stm/pages.c
--- a/c7/stm/pages.c
+++ b/c7/stm/pages.c
@@ -92,6 +92,7 @@
     void *localpg = stm_object_pages + localpgoff * 4096UL;
     void *otherpg = stm_object_pages + otherpgoff * 4096UL;
 
+    memset(flag_page_private + pagenum, PRIVATE_PAGE, count);
     d_remap_file_pages(localpg, count * 4096, pgoff2);
     uintptr_t i;
     if (full) {
@@ -104,8 +105,6 @@
         if (count > 1)
             pagecopy(localpg + 4096 * (count-1), otherpg + 4096 * (count-1));
     }
-    write_fence();
-    memset(flag_page_private + pagenum, PRIVATE_PAGE, count);
 }
 
 static void _pages_privatize(uintptr_t pagenum, uintptr_t count, bool full)
@@ -143,7 +142,7 @@
 }
 
 #if 0
-static bool is_in_shared_pages(object_t *obj)
+static bool is_fully_in_shared_pages(object_t *obj)
 {
     uintptr_t first_page = ((uintptr_t)obj) / 4096UL;
 
@@ -155,9 +154,11 @@
 
     uintptr_t last_page = (((uintptr_t)obj) + obj_size - 1) / 4096UL;
 
-    while (first_page <= last_page)
+    do {
         if (flag_page_private[first_page++] != SHARED_PAGE)
             return false;
+    } while (first_page <= last_page);
+
     return true;
 }
 #endif
diff --git a/c7/stm/pages.h b/c7/stm/pages.h
--- a/c7/stm/pages.h
+++ b/c7/stm/pages.h
@@ -7,10 +7,9 @@
        physical page (the one that is within the segment 0 mmap address). */
     SHARED_PAGE,
 
-    /* Page being in the process of privatization */
-    REMAPPING_PAGE,
-
-    /* Page is private for each segment. */
+    /* Page is private for each segment.  If we obtain this value outside
+       a mutex_pages_lock(), there might be a race: the value can say
+       PRIVATE_PAGE before the page is really un-shared. */
     PRIVATE_PAGE,
 };
 
@@ -33,4 +32,4 @@
 static void mutex_pages_lock(void);
 static void mutex_pages_unlock(void);
 
-//static bool is_in_shared_pages(object_t *obj);
+//static bool is_fully_in_shared_pages(object_t *obj);  -- not needed?
diff --git a/c7/stm/setup.c b/c7/stm/setup.c
--- a/c7/stm/setup.c
+++ b/c7/stm/setup.c
@@ -54,6 +54,7 @@
         pr->pub.segment_num = i;
         pr->pub.segment_base = segment_base;
         pr->overflow_objects_pointing_to_nursery = NULL;
+        pr->large_overflow_objects = NULL;
         pr->modified_old_objects = list_create();
         pr->overflow_number = GCFLAG_OVERFLOW_NUMBER_bit0 * (i + 1);
         highest_overflow_number = pr->overflow_number;
@@ -85,6 +86,7 @@
     for (i = 0; i < NB_SEGMENTS; i++) {
         struct stm_priv_segment_info_s *pr = get_priv_segment(i);
         assert(pr->overflow_objects_pointing_to_nursery == NULL);
+        assert(pr->large_overflow_objects == NULL);
         assert(pr->old_objects_pointing_to_nursery == NULL);
         list_free(pr->modified_old_objects);
     }
diff --git a/c7/test/test_basic.py b/c7/test/test_basic.py
--- a/c7/test/test_basic.py
+++ b/c7/test/test_basic.py
@@ -180,6 +180,7 @@
         lpy = stm_allocate(16)
         stm_set_char(lpy, 'y')
         self.push_root(lpy)
+        assert modified_old_objects() == []
         self.commit_transaction()
         lpy = self.pop_root()
 
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to