Author: Armin Rigo <[email protected]>
Branch: c7-refactor
Changeset: r737:c773165c8774
Date: 2014-02-14 19:01 +0100
http://bitbucket.org/pypy/stmgc/changeset/c773165c8774/

Log:    Copy the complete logic for _stm_write_slowpath()

diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -2,20 +2,60 @@
 # error "must be compiled via stmgc.c"
 #endif
 
+#include <unistd.h>
+
 
 static uint8_t write_locks[READMARKER_END - READMARKER_START];
 
+static void teardown_core(void)
+{
+    memset(write_locks, 0, sizeof(write_locks));
+}
+
+
+static void contention_management(uint8_t current_lock_owner)
+{
+    /* A simple contention manager.  Called when we do stm_write()
+       on an object, but some other thread already holds the write
+       lock on the same object. */
+
+    /* By construction it should not be possible that the owner
+       of the object is precisely us */
+    assert(current_lock_owner != STM_PSEGMENT->write_lock_num);
+
+    /* Who should abort here: this thread, or the other thread? */
+    struct stm_priv_segment_info_s* other_pseg;
+    other_pseg = get_priv_segment(current_lock_owner - 1);
+    assert(other_pseg->write_lock_num == current_lock_owner);
+
+    if ((STM_PSEGMENT->approximate_start_time <
+            other_pseg->approximate_start_time) || is_inevitable()) {
+        /* we are the thread that must succeed */
+        other_pseg->need_abort = 1;
+        _stm_start_safe_point(0);
+        /* XXX: not good, maybe should be signalled by other thread */
+        usleep(1);
+        _stm_stop_safe_point(0);
+        /* done, will retry */
+    }
+    else {
+        /* we are the thread that must abort */
+        stm_abort_transaction();
+    }
+}
+
 
 void _stm_write_slowpath(object_t *obj)
 {
     assert(_running_transaction());
 
     LIST_APPEND(STM_PSEGMENT->old_objects_to_trace, obj);
-    obj->stm_flags |= GCFLAG_WRITE_BARRIER_CALLED;
 
     /* for old objects from the same transaction, we are done now */
-    if (obj_from_same_transaction(obj))
+    if (obj_from_same_transaction(obj)) {
+        obj->stm_flags |= GCFLAG_WRITE_BARRIER_CALLED;
         return;
+    }
 
     /* otherwise, we need to privatize the pages containing the object,
        if they are still SHARED_PAGE.  The common case is that there is
@@ -28,8 +68,27 @@
         pages_privatize(((uintptr_t)obj) / 4096UL, 1);
     }
 
-    //... write_locks
+    /* claim the write-lock for this object */
+    do {
+        uintptr_t lock_idx = (((uintptr_t)obj) >> 4) - READMARKER_START;
+        uint8_t lock_num = STM_PSEGMENT->write_lock_num;
+        uint8_t prev_owner;
+        prev_owner = __sync_val_compare_and_swap(&write_locks[lock_idx],
+                                                 0, lock_num);
+
+        /* if there was no lock-holder, we are done */
+        if (LIKELY(prev_owner == 0))
+            break;
+
+        /* otherwise, call the contention manager, and then possibly retry */
+        contention_management(prev_owner);
+    } while (1);
+
+    /* add the write-barrier-already-called flag ONLY if we succeeded in
+       getting the write-lock */
     stm_read(obj);
+    obj->stm_flags |= GCFLAG_WRITE_BARRIER_CALLED;
+    LIST_APPEND(STM_PSEGMENT->modified_objects, obj);
 }
 
 static void reset_transaction_read_version(void)
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -54,6 +54,10 @@
 struct stm_priv_segment_info_s {
     struct stm_segment_info_s pub;
     struct list_s *old_objects_to_trace;
+    struct list_s *modified_objects;
+    uint64_t approximate_start_time;
+    uint8_t write_lock_num;
+    uint8_t need_abort;
 };
 
 static char *stm_object_pages;
@@ -88,3 +92,9 @@
 static inline bool obj_from_same_transaction(object_t *obj) {
     return ((stm_creation_marker_t *)(((uintptr_t)obj) >> 8))->cm != 0;
 }
+
+static inline bool is_inevitable(void) {
+    return STM_SEGMENT->jmpbuf_ptr == NULL;
+}
+
+static void teardown_core(void);
diff --git a/c7/stm/setup.c b/c7/stm/setup.c
--- a/c7/stm/setup.c
+++ b/c7/stm/setup.c
@@ -60,9 +60,12 @@
                      PROT_NONE);
 
         struct stm_priv_segment_info_s *pr = get_priv_segment(i);
+        assert(i + 1 < 256);
+        pr->write_lock_num = i + 1;
         pr->pub.segment_num = i;
         pr->pub.segment_base = segment_base;
         pr->old_objects_to_trace = list_create();
+        pr->modified_objects = list_create();
     }
 
     /* Make the nursery pages shared.  The other pages are
@@ -100,6 +103,7 @@
 
     memset(flag_page_private, 0, sizeof(flag_page_private));
 
+    teardown_core();
     teardown_sync();
 }
 
diff --git a/c7/stm/sync.c b/c7/stm/sync.c
--- a/c7/stm/sync.c
+++ b/c7/stm/sync.c
@@ -8,6 +8,7 @@
     struct {
         sem_t semaphore;
         uint8_t in_use[NB_SEGMENTS + 1];   /* 1 if running a pthread */
+        uint64_t global_time;     /* approximate */
     };
     char reserved[64];
 } segments_ctl __attribute__((aligned(64)));
@@ -69,6 +70,9 @@
  exit:
     assert(STM_SEGMENT->running_thread == NULL);
     STM_SEGMENT->running_thread = tl;
+
+    /* global_time is approximate -> no synchronization required */
+    STM_PSEGMENT->approximate_start_time = ++segments_ctl.global_time;
 }
 
 static void release_thread_segment(stm_thread_local_t *tl)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to