Author: Armin Rigo <[email protected]>
Branch: c7-refactor
Changeset: r742:d8f51cf89286
Date: 2014-02-15 23:13 +0100
http://bitbucket.org/pypy/stmgc/changeset/d8f51cf89286/

Log:    Mostly compilation fixes

diff --git a/c7/stm/contention.c b/c7/stm/contention.c
new file mode 100644
--- /dev/null
+++ b/c7/stm/contention.c
@@ -0,0 +1,60 @@
+#ifndef _STM_CORE_H_
+# error "must be compiled via stmgc.c"
+#endif
+
+
+static void contention_management(uint8_t other_segment_num)
+{
+    /* 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. */
+
+    assert_has_mutex();
+    assert(other_segment_num != STM_SEGMENT->segment_num);
+
+    /* Who should abort here: this thread, or the other thread? */
+    struct stm_priv_segment_info_s* other_pseg;
+    other_pseg = get_priv_segment(other_segment_num);
+
+    /* note: other_pseg is currently running a transaction, and it cannot
+       commit or abort unexpectedly, because to do that it would need to
+       suspend us.  So the reading of other_pseg->start_time and
+       other_pseg->transaction_state is stable, with one exception: the
+       'transaction_state' can go from TS_REGULAR to TS_INEVITABLE under
+       our feet. */
+    if (STM_PSEGMENT->transaction_state == TS_INEVITABLE) {
+        /* I'm inevitable, so the other is not. */
+        assert(other_pseg->transaction_state != TS_INEVITABLE);
+        other_pseg->transaction_state = TS_MUST_ABORT;
+    }
+    else if (other_pseg->start_time < STM_PSEGMENT->start_time) {
+        /* The other thread started before us, so I should abort, as I'm
+           the least long-running transaction. */
+    }
+    else if (other_pseg->transaction_state == TS_REGULAR) {
+        /* The other thread started strictly after us.  We tell it
+           to abort if we can (e.g. if it's not TS_INEVITABLE). */
+        other_pseg->transaction_state = TS_MUST_ABORT;
+    }
+
+    if (other_pseg->transaction_state != TS_MUST_ABORT) {
+        /* if the other thread is not in aborting-soon mode, then we must
+           abort. */
+        abort_with_mutex();
+    }
+    else {
+        /* otherwise, we will issue a safe point and wait: */
+        STM_PSEGMENT->safe_point = SP_SAFE_POINT;
+
+        /* signal the other thread; it must abort */
+        cond_broadcast();
+
+        /* then wait, hopefully until the other thread broadcasts "I'm
+           done aborting" (spurious wake-ups are ok) */
+        cond_wait();
+
+        /* now we return into _stm_write_slowpath() and will try again
+           to acquire the write lock on our object. */
+        STM_PSEGMENT->safe_point = SP_RUNNING;
+    }
+}
diff --git a/c7/stm/contention.h b/c7/stm/contention.h
new file mode 100644
--- /dev/null
+++ b/c7/stm/contention.h
@@ -0,0 +1,2 @@
+
+static void contention_management(uint8_t other_segment_num);
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -7,75 +7,14 @@
 
 static uint8_t write_locks[READMARKER_END - READMARKER_START];
 
+static void abort_with_mutex(void) __attribute__((noreturn));
+
 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 already 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);
-
-    /* note: other_pseg is currently running a transaction, and it cannot
-       commit or abort unexpectedly, because to do that it would need to
-       suspend us.  So the reading of other_pseg->start_time and
-       other_pseg->transaction_state is stable, with one exception: the
-       'transaction_state' can go from TS_REGULAR to TS_INEVITABLE under
-       our feet. */
-    if (STM_PSEGMENT->transaction_state == TS_INEVITABLE) {
-        /* I'm inevitable, so the other is not. */
-        assert(other_pseg->transaction_state != TS_INEVITABLE);
-        other_pseg->transaction_state = TS_MUST_ABORT;
-    }
-    else if (STM_PSEGMENT->start_time >= other_pseg->start_time) {
-        /* The other thread started before us, so I should abort, as I'm
-           the least long-running transaction. */
-    }
-    else {
-        /* The other thread started strictly after us.  We try to tell
-           it to abort, using compare_and_swap().  This fails if its
-           'transaction_state' is already TS_INEVITABLE. */
-        __sync_bool_compare_and_swap(
-                    &other_pseg->transaction_state, TS_REGULAR, TS_MUST_ABORT);
-    }
-
-    if (other_pseg->transaction_state != TS_MUST_ABORT) {
-        /* if the other thread is not in aborting-soon mode, then we must
-           abort. */
-        stm_abort_transaction();
-    }
-    else {
-        /* otherwise, we will issue a safe point and wait: */
-        mutex_lock();
-        STM_PSEGMENT->safe_point = SP_SAFE_POINT;
-
-        /* signal the other thread; it must abort */
-        cond_broadcast();
-
-        /* then wait, hopefully until the other thread broadcasts "I'm
-           done aborting" (spurious wake-ups are ok) */
-        cond_wait();
-
-        /* now we return into _stm_write_slowpath() and will try again
-           to acquire the write lock on our object. */
-        STM_PSEGMENT->safe_point = SP_RUNNING;
-        mutex_unlock();
-    }
-}
-
-
 void _stm_write_slowpath(object_t *obj)
 {
     assert(_running_transaction());
@@ -115,8 +54,12 @@
         if (LIKELY(prev_owner == 0))
             break;
 
-        /* otherwise, call the contention manager, and then possibly retry */
-        contention_management(prev_owner);
+        /* otherwise, call the contention manager, and then possibly retry.
+           By construction it should not be possible that the owner
+           of the object is already us */
+        mutex_lock();
+        contention_management(prev_owner - 1);
+        mutex_unlock();
     } while (1);
 
     /* add the write-barrier-already-called flag ONLY if we succeeded in
@@ -158,11 +101,11 @@
     /* GS invalid before this point! */
     acquire_thread_segment(tl);
 
-    assert(STM_SEGMENT->safe_point == SP_NO_TRANSACTION);
-    assert(STM_SEGMENT->transaction_state == TS_NONE);
-    STM_SEGMENT->safe_point = SP_RUNNING;
-    STM_SEGMENT->transaction_state = (jmpbuf != NULL ? TS_REGULAR
-                                                     : TS_INEVITABLE);
+    assert(STM_PSEGMENT->safe_point == SP_NO_TRANSACTION);
+    assert(STM_PSEGMENT->transaction_state == TS_NONE);
+    STM_PSEGMENT->safe_point = SP_RUNNING;
+    STM_PSEGMENT->transaction_state = (jmpbuf != NULL ? TS_REGULAR
+                                                      : TS_INEVITABLE);
     STM_SEGMENT->jmpbuf_ptr = jmpbuf;
 
     mutex_unlock();
@@ -172,79 +115,101 @@
     if (UNLIKELY(old_rv == 0xff))
         reset_transaction_read_version();
 
-    assert(list_is_empty(STM_PSEGMENT->old_objects_to_trace));
     assert(list_is_empty(STM_PSEGMENT->modified_objects));
     assert(list_is_empty(STM_PSEGMENT->creation_markers));
 }
 
 
-static void push_modified_to_other_threads()
+static bool detect_write_read_conflicts(void)
 {
     long remote_num = 1 - STM_SEGMENT->segment_num;
-    char *local_base = STM_SEGMENT->segment_base;
     char *remote_base = get_segment_base(remote_num);
-    bool conflicted = false;
     uint8_t remote_version = get_segment(remote_num)->transaction_read_version;
 
+#if NB_SEGMENTS != 2
+# error "This logic only works with two segments"
+#endif
+
     LIST_FOREACH_R(
         STM_PSEGMENT->modified_objects,
         object_t * /*item*/,
         ({
-            if (!conflicted)
-                conflicted = was_read_remote(remote_base, item,
-                                             remote_version);
+            if (was_read_remote(remote_base, item, remote_version)) {
+                /* A write-read conflict! */
+                contention_management(remote_num);
+                return true;
+            }
+        }));
+    return false;
+}
+
+static void push_modified_to_other_segments(void)
+{
+    long remote_num = 1 - STM_SEGMENT->segment_num;
+    char *local_base = STM_SEGMENT->segment_base;
+    char *remote_base = get_segment_base(remote_num);
+
+#if NB_SEGMENTS != 2
+# error "This logic only works with two segments"
+#endif
+
+    LIST_FOREACH_R(
+        STM_PSEGMENT->modified_objects,
+        object_t * /*item*/,
+        ({
+            assert(!was_read_remote(remote_base, item,
+                          get_segment(remote_num)->transaction_read_version));
 
             /* clear the write-lock */
             uintptr_t lock_idx = (((uintptr_t)item) >> 4) - READMARKER_START;
-            assert(write_locks[lock_idx] == _STM_TL->thread_num + 1);
+            assert(write_locks[lock_idx] == STM_PSEGMENT->write_lock_num);
             write_locks[lock_idx] = 0;
 
-            _stm_move_object(item,
-                             REAL_ADDRESS(local_base, item),
-                             REAL_ADDRESS(remote_base, item));
+            char *src = REAL_ADDRESS(local_base, item);
+            ssize_t size = stmcb_size_rounded_up((struct object_s *)src);
+            memcpy(REAL_ADDRESS(remote_base, item), src, size);
         }));
 
     list_clear(STM_PSEGMENT->modified_objects);
-
-    if (conflicted) {
-        ...;  contention management again!
-        get_segment(remote_num)->transaction_state = TS_MUST_ABORT;
-    }
 }
 
 void stm_commit_transaction(void)
 {
     mutex_lock();
 
-    assert(STM_SEGMENT->safe_point = SP_RUNNING);
-    stm_thread_local_t *tl = STM_SEGMENT->running_thread;
+ restart:
+    assert(STM_PSEGMENT->safe_point = SP_RUNNING);
 
-    switch (STM_SEGMENT->transaction_state) {
+    switch (STM_PSEGMENT->transaction_state) {
 
     case TS_REGULAR:
-        /* cannot abort any more */
-        STM_SEGMENT->jmpbuf_ptr = NULL;
-        break;
-
     case TS_INEVITABLE:
-        //...
-        abort();   // XXX do it
         break;
 
     case TS_MUST_ABORT:
-        mutex_unlock();
-        stm_abort_transaction();
+        abort_with_mutex();
 
     default:
         assert(!"commit: bad transaction_state");
     }
 
+    /* detect conflicts */
+    if (detect_write_read_conflicts())
+        goto restart;
+
+    /* cannot abort any more from here */
+    assert(STM_PSEGMENT->transaction_state != TS_MUST_ABORT);
+    STM_SEGMENT->jmpbuf_ptr = NULL;
+
     /* copy modified object versions to other threads */
-    push_modified_to_other_threads();
+    push_modified_to_other_segments();
 
+    /* done */
+    stm_thread_local_t *tl = STM_SEGMENT->running_thread;
     release_thread_segment(tl);   /* includes the cond_broadcast(); */
-    STM_SEGMENT->safe_point = SP_NO_TRANSACTION;
-    STM_SEGMENT->transaction_state = TS_NONE;
+    STM_PSEGMENT->safe_point = SP_NO_TRANSACTION;
+    STM_PSEGMENT->transaction_state = TS_NONE;
+
     mutex_unlock();
 
     reset_all_creation_markers();
@@ -253,11 +218,15 @@
 void stm_abort_transaction(void)
 {
     mutex_lock();
+    abort_with_mutex();
+}
 
+static void abort_with_mutex(void)
+{
     stm_thread_local_t *tl = STM_SEGMENT->running_thread;
     stm_jmpbuf_t *jmpbuf_ptr = STM_SEGMENT->jmpbuf_ptr;
 
-    switch (STM_SEGMENT->transaction_state) {
+    switch (STM_PSEGMENT->transaction_state) {
     case TS_REGULAR:
     case TS_MUST_ABORT:
         break;
@@ -268,11 +237,12 @@
     }
 
     release_thread_segment(tl);   /* includes the cond_broadcast(); */
-    STM_SEGMENT->safe_point = SP_NO_TRANSACTION;
-    STM_SEGMENT->transaction_state = TS_NONE;
+    STM_PSEGMENT->safe_point = SP_NO_TRANSACTION;
+    STM_PSEGMENT->transaction_state = TS_NONE;
     mutex_unlock();
 
     reset_all_creation_markers();
+    list_clear(STM_PSEGMENT->modified_objects);
 
     assert(jmpbuf_ptr != NULL);
     assert(jmpbuf_ptr != (stm_jmpbuf_t *)-1);    /* for tests only */
diff --git a/c7/stm/misc.c b/c7/stm/misc.c
--- a/c7/stm/misc.c
+++ b/c7/stm/misc.c
@@ -50,7 +50,7 @@
 static inline bool was_read_remote(char *base, object_t *obj,
                                    uint8_t other_transaction_read_version)
 {
-    struct read_marker_s *marker = (struct read_marker_s *)
+    struct stm_read_marker_s *marker = (struct stm_read_marker_s *)
         (base + (((uintptr_t)obj) >> 4));
     return (marker->rm == other_transaction_read_version);
 }
diff --git a/c7/stm/sync.c b/c7/stm/sync.c
--- a/c7/stm/sync.c
+++ b/c7/stm/sync.c
@@ -46,7 +46,7 @@
         perror("mutex/cond destroy");
         abort();
     }
-    memset(sync_ctl, 0, sizeof(sync_ctl.in_use));
+    memset(&sync_ctl, 0, sizeof(sync_ctl.in_use));
 }
 
 static void set_gs_register(char *value)
@@ -102,7 +102,7 @@
     assert_has_mutex();
     assert(_is_tl_registered(tl));
 
- retry:
+ retry:;
     int num = tl->associated_segment_num;
     if (sync_ctl.in_use[num] == 0) {
         /* fast-path: we can get the same segment number than the one
@@ -129,7 +129,7 @@
     sync_ctl.in_use[num] = 1;
     assert(STM_SEGMENT->running_thread == NULL);
     STM_SEGMENT->running_thread = tl;
-    STM_PSEGMENT->start_time = ++segments_ctl.global_time;
+    STM_PSEGMENT->start_time = ++sync_ctl.global_time;
 }
 
 static void release_thread_segment(stm_thread_local_t *tl)
diff --git a/c7/stmgc.c b/c7/stmgc.c
--- a/c7/stmgc.c
+++ b/c7/stmgc.c
@@ -9,6 +9,7 @@
 #include "stm/sync.h"
 #include "stm/largemalloc.h"
 #include "stm/nursery.h"
+#include "stm/contention.h"
 
 #include "stm/misc.c"
 #include "stm/list.c"
@@ -21,3 +22,4 @@
 #include "stm/sync.c"
 #include "stm/setup.c"
 #include "stm/core.c"
+#include "stm/contention.c"
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to