[pypy-commit] pypy ec-keepalive: - fix the 'ready = 0', which should be after memset(), otherwise it
arigo
pypy.commits at gmail.com
Mon Jan 4 19:59:05 EST 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: ec-keepalive
Changeset: r81565:c9440e002f09
Date: 2016-01-05 01:58 +0100
http://bitbucket.org/pypy/pypy/changeset/c9440e002f09/
Log: - fix the 'ready = 0', which should be after memset(), otherwise it
is overridden
- fix a rare case of concurrent changes to the doubly-linked list by
adding a lock
diff --git a/rpython/rlib/rthread.py b/rpython/rlib/rthread.py
--- a/rpython/rlib/rthread.py
+++ b/rpython/rlib/rthread.py
@@ -394,11 +394,13 @@
def _trace_tlref(gc, obj, callback, arg):
p = llmemory.NULL
+ llop.threadlocalref_acquire(lltype.Void)
while True:
p = llop.threadlocalref_enum(llmemory.Address, p)
if not p:
break
gc._trace_callback(callback, arg, p + offset)
+ llop.threadlocalref_release(lltype.Void)
_lambda_trace_tlref = lambda: _trace_tlref
TRACETLREF = lltype.GcStruct('TRACETLREF')
_tracetlref_obj = lltype.malloc(TRACETLREF, immortal=True)
diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py
--- a/rpython/rtyper/llinterp.py
+++ b/rpython/rtyper/llinterp.py
@@ -950,6 +950,10 @@
return self.op_raw_load(RESTYPE, _address_of_thread_local(), offset)
op_threadlocalref_get.need_result_type = True
+ def op_threadlocalref_acquire(self, prev):
+ raise NotImplementedError
+ def op_threadlocalref_release(self, prev):
+ raise NotImplementedError
def op_threadlocalref_enum(self, prev):
raise NotImplementedError
diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -547,6 +547,8 @@
'threadlocalref_addr': LLOp(), # get (or make) addr of tl
'threadlocalref_get': LLOp(sideeffects=False), # read field (no check)
+ 'threadlocalref_acquire': LLOp(), # lock for enum
+ 'threadlocalref_release': LLOp(), # lock for enum
'threadlocalref_enum': LLOp(sideeffects=False), # enum all threadlocalrefs
# __________ debugging __________
diff --git a/rpython/translator/c/src/threadlocal.c b/rpython/translator/c/src/threadlocal.c
--- a/rpython/translator/c/src/threadlocal.c
+++ b/rpython/translator/c/src/threadlocal.c
@@ -6,6 +6,20 @@
#include "src/threadlocal.h"
+/* this is a spin-lock that must be acquired around each doubly-linked-list
+ manipulation (because such manipulations can occur without the GIL) */
+static long pypy_threadlocal_lock = 0;
+
+void _RPython_ThreadLocals_Acquire(void) {
+ while (!lock_test_and_set(&pypy_threadlocal_lock, 1)) {
+ /* busy loop */
+ }
+}
+void _RPython_ThreadLocals_Release(void) {
+ lock_release(&pypy_threadlocal_lock);
+}
+
+
pthread_key_t pypy_threadlocal_key
#ifdef _WIN32
= TLS_OUT_OF_INDEXES
@@ -48,23 +62,29 @@
where it is not the case are rather old nowadays. */
# endif
#endif
+ _RPython_ThreadLocals_Acquire();
oldnext = linkedlist_head.next;
tls->prev = &linkedlist_head;
tls->next = oldnext;
linkedlist_head.next = tls;
oldnext->prev = tls;
tls->ready = 42;
+ _RPython_ThreadLocals_Release();
}
static void threadloc_unlink(void *p)
{
+ /* warning: this can be called at completely random times without
+ the GIL. */
struct pypy_threadlocal_s *tls = (struct pypy_threadlocal_s *)p;
+ _RPython_ThreadLocals_Acquire();
if (tls->ready == 42) {
- tls->ready = 0;
tls->next->prev = tls->prev;
tls->prev->next = tls->next;
memset(tls, 0xDD, sizeof(struct pypy_threadlocal_s)); /* debug */
+ tls->ready = 0;
}
+ _RPython_ThreadLocals_Release();
#ifndef USE___THREAD
free(p);
#endif
@@ -110,6 +130,7 @@
a non-null thread-local value). This is needed even in the
case where we use '__thread' below, for the destructor.
*/
+ assert(pypy_threadlocal_lock == 0);
#ifdef _WIN32
pypy_threadlocal_key = TlsAlloc();
if (pypy_threadlocal_key == TLS_OUT_OF_INDEXES)
@@ -122,6 +143,12 @@
abort();
}
_RPython_ThreadLocals_Build();
+
+#ifndef _WIN32
+ pthread_atfork(_RPython_ThreadLocals_Acquire,
+ _RPython_ThreadLocals_Release,
+ _RPython_ThreadLocals_Release);
+#endif
}
@@ -136,7 +163,7 @@
char *_RPython_ThreadLocals_Build(void)
{
- RPyAssert(pypy_threadlocal.ready == 0, "corrupted thread-local");
+ RPyAssert(pypy_threadlocal.ready == 0, "unclean thread-local");
_RPy_ThreadLocals_Init(&pypy_threadlocal);
/* we also set up &pypy_threadlocal as a POSIX thread-local variable,
diff --git a/rpython/translator/c/src/threadlocal.h b/rpython/translator/c/src/threadlocal.h
--- a/rpython/translator/c/src/threadlocal.h
+++ b/rpython/translator/c/src/threadlocal.h
@@ -19,11 +19,17 @@
current thread, and if not, calls the following helper. */
RPY_EXTERN char *_RPython_ThreadLocals_Build(void);
+RPY_EXTERN void _RPython_ThreadLocals_Acquire(void);
+RPY_EXTERN void _RPython_ThreadLocals_Release(void);
+
+/* Must acquire/release the thread-local lock around a series of calls
+ to the following function */
RPY_EXTERN struct pypy_threadlocal_s *
_RPython_ThreadLocals_Enum(struct pypy_threadlocal_s *prev);
-#define OP_THREADLOCALREF_ENUM(p, r) \
- r = _RPython_ThreadLocals_Enum(p)
+#define OP_THREADLOCALREF_ACQUIRE(r) _RPython_ThreadLocals_Acquire()
+#define OP_THREADLOCALREF_RELEASE(r) _RPython_ThreadLocals_Release()
+#define OP_THREADLOCALREF_ENUM(p, r) r = _RPython_ThreadLocals_Enum(p)
/* ------------------------------------------------------------ */
More information about the pypy-commit
mailing list