[pypy-commit] pypy portable-threadlocal: in-progress

arigo noreply at buildbot.pypy.org
Sat Nov 22 20:22:30 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: portable-threadlocal
Changeset: r74639:2d35c55a318d
Date: 2014-11-22 20:22 +0100
http://bitbucket.org/pypy/pypy/changeset/2d35c55a318d/

Log:	in-progress

diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py
--- a/rpython/memory/gctransform/framework.py
+++ b/rpython/memory/gctransform/framework.py
@@ -1080,6 +1080,9 @@
             assert not livevars, "live GC var around %s!" % (hop.spaceop,)
             hop.genop("direct_call", [self.root_walker.thread_run_ptr])
             self.pop_roots(hop, livevars)
+        else:
+            hop.rename("gc_thread_run")     # keep it around for c/gc.py,
+                                            # unless handled specially above
 
     def gct_gc_thread_start(self, hop):
         assert self.translator.config.translation.thread
@@ -1095,6 +1098,7 @@
             assert not livevars, "live GC var around %s!" % (hop.spaceop,)
             hop.genop("direct_call", [self.root_walker.thread_die_ptr])
             self.pop_roots(hop, livevars)
+        hop.rename("gc_thread_die")     # keep it around for c/gc.py
 
     def gct_gc_thread_before_fork(self, hop):
         if (self.translator.config.translation.thread
diff --git a/rpython/memory/gctransform/shadowstack.py b/rpython/memory/gctransform/shadowstack.py
--- a/rpython/memory/gctransform/shadowstack.py
+++ b/rpython/memory/gctransform/shadowstack.py
@@ -132,8 +132,12 @@
             gcdata.root_stack_top/root_stack_base is the one corresponding
             to the current thread.
             No GC operation here, e.g. no mallocs or storing in a dict!
+
+            Note that here specifically we don't call rthread.get_ident(),
+            but rthread.get_or_make_ident().  We are possibly in a fresh
+            new thread, so we need to be careful.
             """
-            tid = get_tid()
+            tid = rthread.get_or_make_ident()
             if gcdata.active_tid != tid:
                 switch_shadow_stacks(tid)
 
diff --git a/rpython/rlib/rthread.py b/rpython/rlib/rthread.py
--- a/rpython/rlib/rthread.py
+++ b/rpython/rlib/rthread.py
@@ -90,6 +90,10 @@
         import thread
         return thread.get_ident()
 
+def get_or_make_ident():
+    assert we_are_translated()
+    return tlfield_thread_ident.get_or_make_raw()
+
 @specialize.arg(0)
 def start_new_thread(x, y):
     """In RPython, no argument can be passed.  You have to use global
@@ -283,12 +287,18 @@
             addr = llop.threadlocalref_addr(rffi.CCHARP)
             return llop.raw_load(FIELDTYPE, addr, offset)
 
+        def get_or_make_raw():
+            _threadlocalref_seeme(self)
+            addr = llop.threadlocalref_make(rffi.CCHARP)
+            return llop.raw_load(FIELDTYPE, addr, offset)
+
         def setraw(value):
             _threadlocalref_seeme(self)
             addr = llop.threadlocalref_addr(rffi.CCHARP)
             llop.raw_store(lltype.Void, addr, offset, value)
 
         self.getraw = getraw
+        self.get_or_make_raw = get_or_make_raw
         self.setraw = setraw
 
     def _freeze_(self):
diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py
--- a/rpython/rtyper/llinterp.py
+++ b/rpython/rtyper/llinterp.py
@@ -920,12 +920,7 @@
         return 0
 
     def op_threadlocalref_addr(self, key, value):
-        raise NotImplementedError("threadlocalref_addr")  # XXX implement me?
-        try:
-            d = self.llinterpreter.tlrefsdict
-        except AttributeError:
-            d = self.llinterpreter.tlrefsdict = {}
-        d[key._obj] = value
+        raise NotImplementedError("threadlocalref_addr")
 
     # __________________________________________________________
     # operations on addresses
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,7 @@
     'check_and_clear_exc':  LLOp(),
 
     'threadlocalref_addr':  LLOp(sideeffects=False),
+    'threadlocalref_make':  LLOp(),
 
     # __________ debugging __________
     'debug_view':           LLOp(),
diff --git a/rpython/translator/c/gc.py b/rpython/translator/c/gc.py
--- a/rpython/translator/c/gc.py
+++ b/rpython/translator/c/gc.py
@@ -71,13 +71,13 @@
         return ''
 
     def OP_GC_THREAD_RUN(self, funcgen, op):
-        return ''
+        return '{ char *r; OP_THREADLOCALREF_MAKE(r); (void)r; } '
 
     def OP_GC_THREAD_START(self, funcgen, op):
         return ''
 
     def OP_GC_THREAD_DIE(self, funcgen, op):
-        return ''
+        return 'RPython_ThreadLocals_ThreadDie();'
 
     def OP_GC_THREAD_BEFORE_FORK(self, funcgen, op):
         return '%s = NULL;' % funcgen.expr(op.result)
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
@@ -716,6 +716,7 @@
         print >> f, ('#define RPY_TLOFS_%s  offsetof(' % field.fieldname +
                      'struct pypy_threadlocal_s, %s)' % field.fieldname)
     print >> f, 'struct pypy_threadlocal_s {'
+    print >> f, '\tint ready;'
     print >> f, '\tchar *stack_end;'
     for field in fields:
         typename = database.gettype(field.FIELDTYPE)
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
@@ -18,7 +18,7 @@
 #endif
 
 
-static void _RPython_ThreadLocals_Init(void *p)
+static void _RPy_ThreadLocals_Init(void *p)
 {
     memset(p, 0, sizeof(struct pypy_threadlocal_s));
 #ifdef RPY_TLOFS_p_errno
@@ -27,6 +27,7 @@
 #ifdef RPY_TLOFS_thread_ident
     ((struct pypy_threadlocal_s *)p)->thread_ident = RPyThreadGetIdent();
 #endif
+    ((struct pypy_threadlocal_s *)p)->ready = 1;
 }
 
 
@@ -35,20 +36,24 @@
 /* ------------------------------------------------------------ */
 
 
+/* in this situation, we always have one full 'struct pypy_threadlocal_s'
+   available, managed by gcc. */
 __thread struct pypy_threadlocal_s pypy_threadlocal;
 
 void RPython_ThreadLocals_ProgramInit(void)
 {
-    RPython_ThreadLocals_ThreadStart();
+    _RPy_ThreadLocals_Init(&pypy_threadlocal);
 }
 
-void RPython_ThreadLocals_ThreadStart(void)
+char *_RPython_ThreadLocals_Build(void)
 {
-    _RPython_ThreadLocals_Init(&pypy_threadlocal);
+    _RPy_ThreadLocals_Init(&pypy_threadlocal);
+    return (char *)&pypy_threadlocal;
 }
 
 void RPython_ThreadLocals_ThreadDie(void)
 {
+    pypy_threadlocal.ready = 0;
 }
 
 
@@ -57,6 +62,16 @@
 /* ------------------------------------------------------------ */
 
 
+/* this is the case where the 'struct pypy_threadlocal_s' is allocated
+   explicitly, with malloc()/free(), and attached to (a single) thread-
+   local key using the API of Windows or pthread. */
+
+#ifdef _WIN32
+#  define _RPy_ThreadLocals_Set(p)  TlsSetValue(pypy_threadlocal_key, p)
+#else
+#  define _RPy_ThreadLocals_Set(p)  pthread_setspecific(pypy_threadlocal_key, p)
+#endif
+
 void RPython_ThreadLocals_ProgramInit(void)
 {
 #ifdef _WIN32
@@ -70,10 +85,10 @@
                         "out of thread-local storage indexes");
         abort();
     }
-    RPython_ThreadLocals_ThreadStart();
+    _RPython_ThreadLocals_Build();
 }
 
-void RPython_ThreadLocals_ThreadStart(void)
+char *_RPython_ThreadLocals_Build(void)
 {
     void *p = malloc(sizeof(struct pypy_threadlocal_s));
     if (!p) {
@@ -81,18 +96,16 @@
                         "out of memory for the thread-local storage");
         abort();
     }
-    _RPython_ThreadLocals_Init(p);
-#ifdef _WIN32
-    TlsSetValue(pypy_threadlocal_key, p);
-#else
-    pthread_setspecific(pypy_threadlocal_key, p);
-#endif
+    _RPy_ThreadLocals_Init(p);
+    _RPy_ThreadLocals_Set(p);
+    return (char *)p;
 }
 
 void RPython_ThreadLocals_ThreadDie(void)
 {
     void *p;
     OP_THREADLOCALREF_ADDR(p);
+    _RPy_ThreadLocals_Set(NULL);
     free(p);
 }
 
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
@@ -5,6 +5,22 @@
 #include <src/precommondefs.h>
 
 
+/* RPython_ThreadLocals_ProgramInit() is called once at program start-up. */
+RPY_EXTERN void RPython_ThreadLocals_ProgramInit(void);
+
+/* RPython_ThreadLocals_ThreadDie() is called in a thread that is about
+   to die. */
+RPY_EXTERN void RPython_ThreadLocals_ThreadDie(void);
+
+/* There are two llops: 'threadlocalref_addr' and 'threadlocalref_make'.
+   They both return the address of the thread-local structure (of the
+   C type 'struct pypy_threadlocal_s').  The difference is that
+   OP_THREADLOCALREF_MAKE() checks if we have initialized this thread-
+   local structure in the current thread, and if not, calls the following
+   helper. */
+RPY_EXTERN char *_RPython_ThreadLocals_Build(void);
+
+
 /* ------------------------------------------------------------ */
 #ifdef USE___THREAD
 /* ------------------------------------------------------------ */
@@ -14,6 +30,9 @@
 
 RPY_EXTERN __thread struct pypy_threadlocal_s pypy_threadlocal;
 #define OP_THREADLOCALREF_ADDR(r)    r = (char *)&pypy_threadlocal
+#define OP_THREADLOCALREF_MAKE(r)                               \
+    (OP_THREADLOCALREF_ADDR(r),                                 \
+     (pypy_threadlocal.ready || (r = _RPython_ThreadLocals_Build())))
 
 
 /* ------------------------------------------------------------ */
@@ -27,6 +46,9 @@
 RPY_EXTERN DWORD pypy_threadlocal_key;
 #define OP_THREADLOCALREF_ADDR(r)    r = (char *)TlsGetValue(  \
                                            pypy_threadlocal_key)
+#define OP_THREADLOCALREF_MAKE(r)                       \
+    (OP_THREADLOCALREF_ADDR(r),                         \
+     ((r) || (r = _RPython_ThreadLocals_Build())))
 
 
 /* ------------------------------------------------------------ */
@@ -41,6 +63,9 @@
 RPY_EXTERN pthread_key_t pypy_threadlocal_key;
 #define OP_THREADLOCALREF_ADDR(r)    r = (char *)pthread_getspecific(  \
                                            pypy_threadlocal_key)
+#define OP_THREADLOCALREF_MAKE(r)                       \
+    (OP_THREADLOCALREF_ADDR(r),                         \
+     ((r) || (r = _RPython_ThreadLocals_Build())))
 
 
 /* ------------------------------------------------------------ */
@@ -48,8 +73,4 @@
 /* ------------------------------------------------------------ */
 
 
-RPY_EXTERN void RPython_ThreadLocals_ProgramInit(void);
-RPY_EXTERN void RPython_ThreadLocals_ThreadStart(void);
-RPY_EXTERN void RPython_ThreadLocals_ThreadDie(void);
-
 #endif /* _SRC_THREADLOCAL_H */


More information about the pypy-commit mailing list