Author: Armin Rigo <[email protected]>
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.
[email protected]("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())
[email protected]("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...
[email protected]_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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit