Author: Remi Meier <remi.me...@gmail.com> Branch: nogil-unsafe-2 Changeset: r90793:fb471557c36c Date: 2017-03-23 10:53 +0100 http://bitbucket.org/pypy/pypy/changeset/fb471557c36c/
Log: add threadsan target and make tracebacks threadlocal Add support for gcc's thread sanitizer by adding a makefile target. Avoid some data races by making the traceback buffer thread-local. diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -198,6 +198,9 @@ BoolOption("lldebug0", "If true, makes an lldebug0 build", default=False, cmdline="--lldebug0"), + BoolOption("threadsan", + "If true, makes an thread-sanitizer build", default=False, + cmdline="--threadsan"), StrOption("icon", "Path to the (Windows) icon to use for the executable"), StrOption("libname", "Windows: name and possibly location of the lib file to create"), diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py --- a/rpython/translator/c/genc.py +++ b/rpython/translator/c/genc.py @@ -397,6 +397,8 @@ extra_opts += ["lldebug"] elif self.config.translation.lldebug0: extra_opts += ["lldebug0"] + elif self.config.translation.threadsan: + extra_opts += ["threadsan"] self.translator.platform.execute_makefile(self.targetdir, extra_opts) if shared: @@ -433,6 +435,9 @@ ('llsafer', '', '$(MAKE) CFLAGS="-O2 -DRPY_LL_ASSERT" $(DEFAULT_TARGET)'), ('lldebug', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DRPY_LL_ASSERT" debug_target'), ('profile', '', '$(MAKE) CFLAGS="-g -O1 -pg $(CFLAGS) -fno-omit-frame-pointer" LDFLAGS="-pg $(LDFLAGS)" $(DEFAULT_TARGET)'), + ('threadsan', '', + '$(MAKE) CFLAGS="-g -O1 $(CFLAGS) -fno-omit-frame-pointer -fsanitize=thread" ' + + 'LDFLAGS="-g $(LDFLAGS) -fsanitize=thread" $(DEFAULT_TARGET)'), ] if self.has_profopt(): rules.append( diff --git a/rpython/translator/c/src/debug_traceback.c b/rpython/translator/c/src/debug_traceback.c --- a/rpython/translator/c/src/debug_traceback.c +++ b/rpython/translator/c/src/debug_traceback.c @@ -6,8 +6,8 @@ #include <stdio.h> #include <stdlib.h> -int pypydtcount = 0; -struct pypydtentry_s pypy_debug_tracebacks[PYPY_DEBUG_TRACEBACK_DEPTH]; +__thread int pypydtcount = 0; +__thread struct pypydtentry_s pypy_debug_tracebacks[PYPY_DEBUG_TRACEBACK_DEPTH]; void pypy_debug_traceback_print(void) { diff --git a/rpython/translator/c/src/debug_traceback.h b/rpython/translator/c/src/debug_traceback.h --- a/rpython/translator/c/src/debug_traceback.h +++ b/rpython/translator/c/src/debug_traceback.h @@ -60,8 +60,8 @@ void *exctype; }; -RPY_EXTERN int pypydtcount; -RPY_EXTERN struct pypydtentry_s pypy_debug_tracebacks[PYPY_DEBUG_TRACEBACK_DEPTH]; +RPY_EXTERN __thread int pypydtcount; +RPY_EXTERN __thread struct pypydtentry_s pypy_debug_tracebacks[PYPY_DEBUG_TRACEBACK_DEPTH]; RPY_EXTERN void pypy_debug_traceback_print(void); RPY_EXTERN void pypy_debug_catch_fatal_exception(void); 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 @@ -76,17 +76,20 @@ */ #define _RPyGilAcquire() do { \ - assert((RPY_THREADLOCALREF_GET(synclock) & 0b001) == 0b0); \ + assert((__sync_fetch_and_add( \ + &RPY_THREADLOCALREF_GET(synclock), 0) \ + & 0b001) == 0b0); \ if (!__sync_bool_compare_and_swap( \ - &RPY_THREADLOCALREF_GET(synclock), 0b100L, 0b101L)) \ + &RPY_THREADLOCALREF_GET(synclock), 0b100L, 0b101L)) \ RPyGilAcquireSlowPath(); \ - } while (0) + } 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(); \ +#define _RPyGilRelease() do { \ + assert((__sync_fetch_and_add( \ + &RPY_THREADLOCALREF_GET(synclock), 0) & 0b101) == 0b101); \ + if (!__sync_bool_compare_and_swap( \ + &RPY_THREADLOCALREF_GET(synclock), 0b101L, 0b100L)) \ + RPyGilReleaseSlowPath(); \ } while (0) static inline long *_RPyFetchFastGil(void) { @@ -94,12 +97,12 @@ // return &rpy_fastgil; } -#define RPyGilYieldThread() do { \ - assert(RPY_THREADLOCALREF_GET(synclock) & 1L); \ - if (RPY_THREADLOCALREF_GET(synclock) == 0b111L) { \ - RPyGilYieldThreadSlowPath(); \ - } \ - } while (0) +#define RPyGilYieldThread() do { \ + assert(__sync_fetch_and_add(&RPY_THREADLOCALREF_GET(synclock), 0) & 1L); \ + if (RPY_THREADLOCALREF_GET(synclock) == 0b111L) { \ + RPyGilYieldThreadSlowPath(); \ + } \ + } while (0) typedef unsigned char rpy_spinlock_t; static inline void rpy_spinlock_acquire(rpy_spinlock_t *p) 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 @@ -97,6 +97,7 @@ RPyGilAcquire(); } +__attribute__((no_sanitize_thread)) void RPyGilMasterRequestSafepoint(void) { pthread_mutex_lock(&sync_mutex); @@ -111,10 +112,13 @@ if (t == NULL) break; - retry: - switch (t->synclock) { + retry:; + /* this read and the setting of nursery_top make thread sanitizer + * unhappy */ + long synclock = t->synclock; + switch (synclock) { default: - fprintf(stderr, "ERROR: found synclock=%ld\n", t->synclock); + fprintf(stderr, "ERROR: found synclock=%ld\n", synclock); abort(); case 0b000L: /* new thread, no need to explicitly request safepoint */ diff --git a/rpython/translator/c/test/test_nogil.py b/rpython/translator/c/test/test_nogil.py --- a/rpython/translator/c/test/test_nogil.py +++ b/rpython/translator/c/test/test_nogil.py @@ -22,6 +22,7 @@ t.config.translation.gcrootfinder = self.gcrootfinder t.config.translation.thread = True t.config.translation.no__thread = no__thread + # t.config.translation.threadsan = True t.buildannotator().build_types(entry_point, [s_list_of_strings]) t.buildrtyper().specialize() # @@ -46,7 +47,7 @@ pass state = State() - def thread(): + def worker(): rthread.gc_thread_start() x = None for i in range(100000000): @@ -74,16 +75,16 @@ state.counter = TS for _ in range(TS): - rthread.start_new_thread(thread, ()) + rthread.start_new_thread(worker, ()) - i = 0 while True: - x = X(None, i) time.sleep(0.1) - assert x.i == i + state.lock.acquire(True) if state.counter == 0: + state.lock.release() break - i += 1 + state.lock.release() + os.write(1, "all threads done\n") return 0 @@ -152,8 +153,11 @@ while True: time.sleep(0.1) + state.lock.acquire(True) if state.counter == 0: + state.lock.release() break + state.lock.release() os.write(1, "all threads done\n") return 0 _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit