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