Author: Remi Meier <remi.me...@gmail.com>
Branch: nogil-unsafe-2
Changeset: r90494:ea1fd293ee24
Date: 2017-03-02 18:21 +0100
http://bitbucket.org/pypy/pypy/changeset/ea1fd293ee24/

Log:    (arigo, remi) deal with new threads popping up randomly

        if a new thread shows up and all others are waiting in a safepoint,
        it should also wait (by entering the slowpath of acquire GIL)

diff --git a/rpython/translator/c/src/thread.h 
b/rpython/translator/c/src/thread.h
--- a/rpython/translator/c/src/thread.h
+++ b/rpython/translator/c/src/thread.h
@@ -52,18 +52,43 @@
 //RPY_EXTERN long rpy_fastgil;
 #include "threadlocal.h"
 
-#define _RPyGilAcquire() do { \
-        if (!__sync_bool_compare_and_swap(                  \
-                &RPY_THREADLOCALREF_GET(synclock), 0L, 1L)) \
-            RPyGilAcquireSlowPath();                        \
-    } while (0)
+/*
+  synclock is 3 bits:
+    bit 0: GIL acquired
+    bit 1: safepoint requested
+    bit 2: thread known and initialised (old)
 
-#define _RPyGilRelease() do { \
-        assert(RPY_THREADLOCALREF_GET(synclock) != 0L); \
-    if (!__sync_bool_compare_and_swap(                  \
-            &RPY_THREADLOCALREF_GET(synclock), 1L, 0L)) \
-        RPyGilReleaseSlowPath();                        \
-    } while (0)
+  synclock possible values:
+    000: new thread; GIL released; safepoint requested
+    010: INVALID VALUE
+    0?1: INVALID VALUE
+    100: old thread; GIL released
+    101: old thread; GIL acquired
+    110: old thread; GIL released; safepoint requested
+    111: old thread; GIL acquired; safepoint requested
+
+  synclock transitions:
+    acquire: (possible values: ??0)
+      FASTPATH: 100 -> 101
+      SLOWPATH: check safepoint; initialise new thread; ??? -> 101
+    release: (possible values: 1?1):
+      FASTPATH: 101 -> 100
+      SLOWPATH: signal "now at safepoint"; 111 -> 110
+ */
+
+#define _RPyGilAcquire() do {                                           \
+        assert((RPY_THREADLOCALREF_GET(synclock) & 0b001) == 0b0);      \
+    if (!__sync_bool_compare_and_swap(                                  \
+                &RPY_THREADLOCALREF_GET(synclock), 0b100L, 0b101L))     \
+        RPyGilAcquireSlowPath();                                        \
+        } while (0)
+
+#define _RPyGilRelease() do {                                       \
+        assert((RPY_THREADLOCALREF_GET(synclock) & 0b101) == 0b101);  \
+    if (!__sync_bool_compare_and_swap(                              \
+                &RPY_THREADLOCALREF_GET(synclock), 0b101L, 0b100L)) \
+        RPyGilReleaseSlowPath();                                    \
+        } while (0)
 
 static inline long *_RPyFetchFastGil(void) {
     abort();
@@ -72,7 +97,7 @@
 
 #define RPyGilYieldThread() do { \
     assert(RPY_THREADLOCALREF_GET(synclock) & 1L); \
-    if (RPY_THREADLOCALREF_GET(synclock) == 3L) { \
+    if (RPY_THREADLOCALREF_GET(synclock) == 0b111L) { \
         RPyGilYieldThreadSlowPath(); \
     } \
     } while (0)
diff --git a/rpython/translator/c/src/thread_gil.c 
b/rpython/translator/c/src/thread_gil.c
--- a/rpython/translator/c/src/thread_gil.c
+++ b/rpython/translator/c/src/thread_gil.c
@@ -1,13 +1,14 @@
 #include <pthread.h>
 #include <stdlib.h>
 #include <assert.h>
+#include <stdbool.h>
 #include "threadlocal.h"
 
 static pthread_mutex_t master_mutex;
 static pthread_mutex_t sync_mutex;
 static pthread_cond_t  sync_cond;
 
-static long counter_of_threes = 0;
+static long counter_of_sevens = 0;
 
 static long rpy_initialize = -42;
 
@@ -26,7 +27,7 @@
     if (err)
         abort();
 
-    counter_of_threes = 0; // XXX: fork?
+    counter_of_sevens = 0; // XXX: fork?
     rpy_initialize = 0;
 }
 
@@ -44,29 +45,35 @@
 
 void RPyGilAcquireSlowPath(void)
 {
-    assert(RPY_THREADLOCALREF_GET(synclock) == 2);
-
     /* wait until the master leaves the safe point */
     pthread_mutex_lock(&master_mutex);
-    RPY_THREADLOCALREF_GET(synclock) = 1;
+
+    long synclock = RPY_THREADLOCALREF_GET(synclock);
+    assert(synclock == 0b110 || synclock == 0b000);
+
+    bool is_new_thread = synclock == 000;
+    if (is_new_thread) {
+        // TODO
+    }
+
+    RPY_THREADLOCALREF_GET(synclock) = 0b101L;
     pthread_mutex_unlock(&master_mutex);
 }
 
 void RPyGilReleaseSlowPath(void)
 {
-    assert(RPY_THREADLOCALREF_GET(synclock) == 3);
+    pthread_mutex_lock(&sync_mutex);
+    assert(RPY_THREADLOCALREF_GET(synclock) == 0b111L);
 
-    pthread_mutex_lock(&sync_mutex);
-
-    /* we are one of the THREES that the master is waiting for. Decrease the
+    /* we are one of the SEVENs that the master is waiting for. Decrease the
      * counter and signal the master if we are the last. */
-    counter_of_threes--;
-    if (counter_of_threes == 0)
+    counter_of_sevens--;
+    if (counter_of_sevens == 0)
         pthread_cond_signal(&sync_cond);
 
-    /* set to TWO, so that Acquire above will wait until the master is finished
+    /* set to 110, so that Acquire above will wait until the master is finished
      * with its safe point */
-    RPY_THREADLOCALREF_GET(synclock) = 2;
+    RPY_THREADLOCALREF_GET(synclock) = 0b110L;
     pthread_mutex_unlock(&sync_mutex);
     // continue without GIL
 }
@@ -92,7 +99,7 @@
 void RPyGilMasterRequestSafepoint(void)
 {
     pthread_mutex_lock(&sync_mutex);
-    assert(counter_of_threes == 0);
+    assert(counter_of_sevens == 0);
 
     /* signal all threads to enter safepoints */
     OP_THREADLOCALREF_ACQUIRE(/* */);
@@ -105,22 +112,25 @@
 
       retry:
         switch (t->synclock) {
-        case 3:
-            assert(!"unexpected synclock=3 found");
+        default:
+            fprintf(stderr, "ERROR: found synclock=%ld\n", t->synclock);
             abort();
-        case 2:
+        case 0b000L:
+            /* new thread, no need to explicitly request safepoint */
+            break;
+        case 0b110L:
             /* thread running in C code, already knows we want a safepoint */
             break;
-        case 0:
+        case 0b100L:
             /* thread running in C code, make sure it checks for and enters
              * the safepoint before acquiring the "gil" again */
-            if (__sync_bool_compare_and_swap(&t->synclock, 0, 2))
+            if (__sync_bool_compare_and_swap(&t->synclock, 0b100L, 0b110L))
                 break;
             goto retry;
-        case 1:
+        case 0b101L:
             /* thread running normally, place request to enter safepoint */
-            if (__sync_bool_compare_and_swap(&t->synclock, 1, 3)) {
-                counter_of_threes++;
+            if (__sync_bool_compare_and_swap(&t->synclock, 0b101L, 0b111L)) {
+                counter_of_sevens++;
                 t->nursery_top = NULL;
                 break;
             }
@@ -129,8 +139,8 @@
     }
     OP_THREADLOCALREF_RELEASE(/* */);
 
-    /* wait until all THREES entered their safepoints */
-    while (counter_of_threes > 0) {
+    /* wait until all SEVENs entered their safepoints */
+    while (counter_of_sevens > 0) {
         pthread_cond_wait(&sync_cond, &sync_mutex);
     }
 
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to