[pypy-commit] pypy nogil-unsafe-2: add threadsan target and make tracebacks threadlocal
Raemi
pypy.commits at gmail.com
Thu Mar 23 05:53:43 EDT 2017
Author: Remi Meier <remi.meier at 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
More information about the pypy-commit
mailing list