Author: Armin Rigo <ar...@tunes.org>
Branch: portable-threadlocal
Changeset: r74632:40454c851fe5
Date: 2014-11-22 18:31 +0100
http://bitbucket.org/pypy/pypy/changeset/40454c851fe5/

Log:    in-progress: refactor the threadlocal through the translation
        toolchain

diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py
--- a/rpython/annotator/bookkeeper.py
+++ b/rpython/annotator/bookkeeper.py
@@ -65,6 +65,7 @@
         self.external_class_cache = {}      # cache of ExternalType classes
 
         self.needs_generic_instantiate = {}
+        self.thread_local_fields = set()
 
         delayed_imports()
 
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -95,12 +95,19 @@
 # the default wrapper for set_errno is not suitable for use in critical places
 # like around GIL handling logic, so we provide our own wrappers.
 
-@jit.oopspec("rposix.get_errno()")
 def get_errno():
+    if jit.we_are_jitted():
+        from rpython.rlib import rthread
+        perrno = rthread.tlfield_p_errno.getraw()
+        return intmask(perrno[0])
     return intmask(_get_errno())
 
-@jit.oopspec("rposix.set_errno(errno)")
 def set_errno(errno):
+    if jit.we_are_jitted():
+        from rpython.rlib import rthread
+        perrno = rthread.tlfield_p_errno.getraw()
+        perrno[0] = rffi.cast(INT, errno)
+        return
     _set_errno(rffi.cast(INT, errno))
 
 if os.name == 'nt':
diff --git a/rpython/rlib/rthread.py b/rpython/rlib/rthread.py
--- a/rpython/rlib/rthread.py
+++ b/rpython/rlib/rthread.py
@@ -5,8 +5,10 @@
 from rpython.rlib import jit, rgc
 from rpython.rlib.debug import ll_assert
 from rpython.rlib.objectmodel import we_are_translated, specialize
+from rpython.rlib.objectmodel import CDefinedIntSymbolic
 from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.rtyper.tool import rffi_platform
+from rpython.rtyper.extregistry import ExtRegistryEntry
 
 class RThreadError(Exception):
     pass
@@ -40,8 +42,6 @@
                             releasegil=True)  # release the GIL, but most
                                               # importantly, reacquire it
                                               # around the callback
-c_thread_get_ident = llexternal('RPyThreadGetIdent', [], rffi.LONG,
-                                _nowrapper=True)    # always call directly
 
 TLOCKP = rffi.COpaquePtr('struct RPyOpaque_ThreadLock',
                           compilation_info=eci)
@@ -83,9 +83,8 @@
 
 # wrappers...
 
-@jit.loop_invariant
 def get_ident():
-    return rffi.cast(lltype.Signed, c_thread_get_ident())
+    return tlfield_thread_ident.getraw()
 
 @specialize.arg(0)
 def start_new_thread(x, y):
@@ -265,17 +264,35 @@
 # KEEP THE REFERENCE ALIVE, THE GC DOES NOT FOLLOW THEM SO FAR!
 # We use _make_sure_does_not_move() to make sure the pointer will not move.
 
-ecitl = ExternalCompilationInfo(
-    includes = ['src/threadlocal.h'],
-    separate_module_files = [translator_c_dir / 'src' / 'threadlocal.c'])
-ensure_threadlocal = rffi.llexternal_use_eci(ecitl)
 
-class ThreadLocalReference(object):
+class ThreadLocalField(object):
+    def __init__(self, FIELDTYPE, fieldname):
+        "NOT_RPYTHON: must be prebuilt"
+        self.FIELDTYPE = FIELDTYPE
+        self.fieldname = fieldname
+        offset = CDefinedIntSymbolic('RPY_TLOFS_%s' % self.fieldname,
+                                     default='?')
+        self.offset = offset
+
+        def getraw():
+            _threadlocalref_seeme(self)
+            addr = llop.threadlocalref_addr(llmemory.Address)
+            return llop.raw_load(FIELDTYPE, addr, offset)
+
+        def setraw(value):
+            _threadlocalref_seeme(self)
+            addr = llop.threadlocalref_addr(llmemory.Address)
+            llop.raw_store(lltype.Void, addr, offset, value)
+
+        self.getraw = getraw
+        self.setraw = setraw
+
+    def _freeze_(self):
+        return True
+
+
+class ThreadLocalReference(ThreadLocalField):
     _COUNT = 1
-    OPAQUEID = lltype.OpaqueType("ThreadLocalRef",
-                                 hints={"threadlocalref": True,
-                                        "external": "C",
-                                        "c_name": "RPyThreadStaticTLS"})
 
     def __init__(self, Cls):
         "NOT_RPYTHON: must be prebuilt"
@@ -284,16 +301,14 @@
         self.local = thread._local()      # <- NOT_RPYTHON
         unique_id = ThreadLocalReference._COUNT
         ThreadLocalReference._COUNT += 1
-        opaque_id = lltype.opaqueptr(ThreadLocalReference.OPAQUEID,
-                                     'tlref%d' % unique_id)
-        self.opaque_id = opaque_id
+        ThreadLocalField.__init__(self, llmemory.GCREF, 'tlref%d' % unique_id)
+        getraw = self.getraw
+        setraw = self.setraw
 
         def get():
             if we_are_translated():
-                from rpython.rtyper import rclass
-                from rpython.rtyper.annlowlevel import 
cast_base_ptr_to_instance
-                ptr = llop.threadlocalref_get(rclass.OBJECTPTR, opaque_id)
-                return cast_base_ptr_to_instance(Cls, ptr)
+                from rpython.rtyper.annlowlevel import cast_gcref_to_instance
+                return cast_gcref_to_instance(Cls, getraw())
             else:
                 return getattr(self.local, 'value', None)
 
@@ -304,18 +319,30 @@
                 from rpython.rtyper.annlowlevel import 
cast_instance_to_base_ptr
                 from rpython.rlib.rgc import _make_sure_does_not_move
                 from rpython.rlib.objectmodel import running_on_llinterp
-                ptr = cast_instance_to_base_ptr(value)
+                gcref = cast_instance_to_gcref(value)
                 if not running_on_llinterp:
-                    gcref = lltype.cast_opaque_ptr(llmemory.GCREF, ptr)
                     if gcref:
                         _make_sure_does_not_move(gcref)
-                llop.threadlocalref_set(lltype.Void, opaque_id, ptr)
-                ensure_threadlocal()
+                setraw(gcref)
             else:
                 self.local.value = value
 
         self.get = get
         self.set = set
 
-    def _freeze_(self):
-        return True
+
+tlfield_thread_ident = ThreadLocalField(lltype.Signed, "thread_ident")
+tlfield_p_errno = ThreadLocalField(rffi.CArrayPtr(rffi.INT), "p_errno")
+
+def _threadlocalref_seeme(field):
+    "NOT_RPYTHON"
+
+class _Entry(ExtRegistryEntry):
+    _about_ = _threadlocalref_seeme
+
+    def compute_result_annotation(self, s_field):
+        field = s_field.const
+        self.bookkeeper.thread_local_fields.add(field)
+
+    def specialize_call(self, hop):
+        hop.exception_cannot_occur()
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
@@ -546,9 +546,7 @@
     'getslice':             LLOp(canraise=(Exception,)),
     'check_and_clear_exc':  LLOp(),
 
-    'threadlocalref_get':   LLOp(sideeffects=False),
-    'threadlocalref_getaddr': LLOp(sideeffects=False),
-    'threadlocalref_set':   LLOp(),
+    'threadlocalref_addr':  LLOp(sideeffects=False),
 
     # __________ debugging __________
     'debug_view':           LLOp(),
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
@@ -703,8 +703,27 @@
     for node in structdeflist:
         for line in node.definition():
             print >> f, line
+    gen_threadlocal_structdef(f, database)
     print >> f, "#endif"
 
+def gen_threadlocal_structdef(f, database):
+    bk = database.translator.annotator.bookkeeper
+    if bk.thread_local_fields:
+        from rpython.translator.c.support import cdecl
+        print >> f
+        fields = list(bk.thread_local_fields)
+        fields.sort(key=lambda field: field.fieldname)
+        print >> f, '#define RPY_HAS_THREADLOCAL_S'
+        for field in fields:
+            print >> f, ('#define RPY_TLOFS_%s  offsetof(' % field.fieldname +
+                         'struct pypy_threadlocal_s, %s)' % field.fieldname)
+        print >> f, 'struct pypy_threadlocal_s {'
+        for field in fields:
+            typename = database.gettype(field.FIELDTYPE)
+            print >> f, '\t%s;' % cdecl(typename, field.fieldname)
+        print >> f, '};'
+        print >> f
+
 def gen_forwarddecl(f, database):
     print >> f, '/***********************************************************/'
     print >> f, '/***  Forward declarations                               ***/'
@@ -748,6 +767,11 @@
                 print >> f, '\tif (error) return error;'
             for line in lines:
                 print >> f, '\t'+line
+
+    bk = database.translator.annotator.bookkeeper
+    if bk.thread_local_fields:
+        print >> f, '\tRPython_ThreadLocals_ProgramInit();'
+
     print >> f, '\treturn error;'
     print >> f, '}'
 
@@ -770,6 +794,7 @@
         srcdir / 'asm.c',
         srcdir / 'instrument.c',
         srcdir / 'int.c',
+        srcdir / 'threadlocal.c',
     ]
     if _CYGWIN:
         files.append(srcdir / 'cygwin_wait.c')
diff --git a/rpython/translator/c/node.py b/rpython/translator/c/node.py
--- a/rpython/translator/c/node.py
+++ b/rpython/translator/c/node.py
@@ -966,30 +966,12 @@
                 args.append('0')
         yield 'RPyOpaque_SETUP_%s(%s);' % (T.tag, ', '.join(args))
 
-class ThreadLocalRefOpaqueNode(ContainerNode):
-    nodekind = 'tlrefopaque'
-
-    def basename(self):
-        return self.obj._name
-
-    def enum_dependencies(self):
-        return []
-
-    def initializationexpr(self, decoration=''):
-        return ['0']
-
-    def startupcode(self):
-        p = self.getptrname()
-        yield 'RPyThreadStaticTLS_Create(%s);' % (p,)
-
 
 def opaquenode_factory(db, T, obj):
     if T == RuntimeTypeInfo:
         return db.gcpolicy.rtti_node_factory()(db, T, obj)
     if T.hints.get("render_structure", False):
         return ExtType_OpaqueNode(db, T, obj)
-    if T.hints.get("threadlocalref", False):
-        return ThreadLocalRefOpaqueNode(db, T, obj)
     raise Exception("don't know about %r" % (T,))
 
 
diff --git a/rpython/translator/c/src/g_include.h 
b/rpython/translator/c/src/g_include.h
--- a/rpython/translator/c/src/g_include.h
+++ b/rpython/translator/c/src/g_include.h
@@ -48,3 +48,7 @@
 #ifdef __CYGWIN__
 #include "src/cygwin_wait.h"
 #endif
+
+#ifdef RPY_HAS_THREADLOCAL_S
+#include "src/threadlocal.h"
+#endif
diff --git a/rpython/translator/c/src/g_prerequisite.h 
b/rpython/translator/c/src/g_prerequisite.h
--- a/rpython/translator/c/src/g_prerequisite.h
+++ b/rpython/translator/c/src/g_prerequisite.h
@@ -23,6 +23,3 @@
 # define RPY_LENGTH0     1       /* array decl [0] are bad */
 # define RPY_DUMMY_VARLENGTH     /* nothing */
 #endif
-
-
-#include "src/threadlocal.h"
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
@@ -1,28 +1,97 @@
+#include "common_header.h"
+#include "structdef.h"
+
+#ifdef RPY_HAS_THREADLOCAL_S     /* otherwise, this file is not needed */
+
 #include <stdio.h>
 #include <stdlib.h>
+#include <errno.h>
 #include "src/threadlocal.h"
+#include "src/thread.h"
 
+
+static void _RPython_ThreadLocals_Init(char *p)
+{
+    struct pypy_threadlocal_s *tl = (struct pypy_threadlocal_s *)p;
+#ifdef RPY_TLOFS_p_errno
+    tl->p_errno = &errno;
+#endif
+#ifdef RPY_TLOFS_thread_ident
+    tl->thread_ident = RPyThreadGetIdent();
+#endif
+}
+
+
+/* ------------------------------------------------------------ */
+#ifdef USE___THREAD
+/* ------------------------------------------------------------ */
+
+
+__thread struct pypy_threadlocal_s pypy_threadlocal;
+
+void RPython_ThreadLocals_ProgramInit(void)
+{
+    RPython_ThreadLocals_ThreadStart();
+}
+
+void RPython_ThreadLocals_ThreadStart(void)
+{
+    _RPython_ThreadLocals_Init(&pypy_threadlocal);
+}
+
+void RPython_ThreadLocals_ThreadDie(void)
+{
+}
+
+
+/* ------------------------------------------------------------ */
+#else
+/* ------------------------------------------------------------ */
+
+
+void RPython_ThreadLocals_ProgramInit(void)
+{
 #ifdef _WIN32
-
-void RPyThreadTLS_Create(RPyThreadTLS *result)
-{
-    *result = TlsAlloc();
-    if (*result == TLS_OUT_OF_INDEXES) {
+    pypy_threadlocal_key = TlsAlloc();
+    if (pypy_threadlocal_key == TLS_OUT_OF_INDEXES)
+#else
+    if (pthread_key_create(&pypy_threadlocal_key, NULL) != 0)
+#endif
+    {
         fprintf(stderr, "Internal RPython error: "
                         "out of thread-local storage indexes");
         abort();
     }
+    RPython_ThreadLocals_ThreadStart();
 }
 
-#else
-
-void RPyThreadTLS_Create(RPyThreadTLS *result)
+void RPython_ThreadLocals_ThreadStart(void)
 {
-    if (pthread_key_create(result, NULL) != 0) {
+    char *p = malloc(sizeof(struct pypy_threadlocal_s));
+    if (!p) {
         fprintf(stderr, "Internal RPython error: "
-                        "out of thread-local storage keys");
+                        "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
 }
 
+void RPython_ThreadLocals_ThreadDie(void)
+{
+    char *p;
+    OP_THREADLOCALREF_ADDR(p);
+    free(p);
+}
+
+
+/* ------------------------------------------------------------ */
 #endif
+/* ------------------------------------------------------------ */
+
+
+#endif  /* RPY_HAS_THREADLOCAL_S */
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,48 +5,54 @@
 #include <src/precommondefs.h>
 
 
-#ifdef _WIN32
+#ifndef RPY_HAS_THREADLOCAL_S
+#  error "src/threadlocal.h should only be included if RPY_HAS_THREADLOCAL_S"
+#endif
+
+
+/* ------------------------------------------------------------ */
+#ifdef USE___THREAD
+/* ------------------------------------------------------------ */
+
+
+/* Use the '__thread' specifier, so far only on Linux */
+
+RPY_EXTERN __thread struct pypy_threadlocal_s pypy_threadlocal;
+#define OP_THREADLOCALREF_ADDR(r)    r = &pypy_threadlocal
+
+
+/* ------------------------------------------------------------ */
+#elif _WIN32
+/* ------------------------------------------------------------ */
+
 
 #include <WinSock2.h>
 #include <windows.h>
-#define __thread __declspec(thread)
-typedef DWORD RPyThreadTLS;
-#define RPyThreadTLS_Get(key)          TlsGetValue(key)
-#define RPyThreadTLS_Set(key, value)   TlsSetValue(key, value)
 
+RPY_EXTERN DWORD pypy_threadlocal_key;
+#define OP_THREADLOCALREF_ADDR(r)    r = TlsGetValue(pypy_threadlocal_key)
+
+
+/* ------------------------------------------------------------ */
 #else
+/* ------------------------------------------------------------ */
+
+
+/* Other POSIX systems: use the pthread API */
 
 #include <pthread.h>
-typedef pthread_key_t RPyThreadTLS;
-#define RPyThreadTLS_Get(key)          pthread_getspecific(key)
-#define RPyThreadTLS_Set(key, value)   pthread_setspecific(key, value)
 
+RPY_EXTERN pthread_key_t pypy_threadlocal_key;
+#define OP_THREADLOCALREF_ADDR(r)  r = 
pthread_getspecific(pypy_threadlocal_key)
+
+
+/* ------------------------------------------------------------ */
 #endif
+/* ------------------------------------------------------------ */
 
 
-#ifdef USE___THREAD
-
-#define RPyThreadStaticTLS                  __thread void *
-#define RPyThreadStaticTLS_Create(tls)      (void)0
-#define RPyThreadStaticTLS_Get(tls)         tls
-#define RPyThreadStaticTLS_Set(tls, value)  tls = value
-#define OP_THREADLOCALREF_GETADDR(tlref, ptr)  ptr = tlref
-
-#endif
-
-#ifndef RPyThreadStaticTLS
-
-#define RPyThreadStaticTLS             RPyThreadTLS
-#define RPyThreadStaticTLS_Create(key) RPyThreadTLS_Create(key)
-#define RPyThreadStaticTLS_Get(key)    RPyThreadTLS_Get(key)
-#define RPyThreadStaticTLS_Set(key, value) RPyThreadTLS_Set(key, value)
-RPY_EXTERN void RPyThreadTLS_Create(RPyThreadTLS *result);
-
-#endif
-
-
-#define OP_THREADLOCALREF_SET(tlref, ptr, _) RPyThreadStaticTLS_Set(*tlref, 
ptr)
-#define OP_THREADLOCALREF_GET(tlref, ptr)   ptr = 
RPyThreadStaticTLS_Get(*tlref)
-
+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 */
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to