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