// natThreadLocal.cc - Native part of ThreadLocal class. // Fast thread local storage for systems that support the __thread // variable attribute. /* Copyright (C) 2006 Free Software Foundation This file is part of libgcj. This software is copyrighted work licensed under the terms of the Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ #include #include #include #include #include #include #include #include #include #include #include #include /* We would like to have fast thread local variables that behave in the same way as C and C++ thread local variables. This would mean having an field attribute "thread" (like static, final, etc.). However, this is not compatible with java semantics, which we wish to support transparently. The problems we must overcome are: * In Java, ThreadLocal variables are not statically allocated: they are objects, created at runtime. * Class ThreadLocal is not final and neither are its methods, so it is possible to create a subclass of ThreadLocal that overrides any method. * __thread variables in DSOs are not visible to the garbage collector, so we must ensure that we keep a copy of every thread local variable somewhere on the heap. * Once a ThreadLocal instance has been created and assigned to a static field, that field may be reassigned to a different ThreadLocal instance or null. So, we can't simply replace get() and set() with accesses of a __thread variable. So, we create a pthread_key in each ThreadLocal object and use that as a kind of "look-aside cache". When a ThreadLocal is set, we also set the corresponding thread-specific value. When the ThreadLocal is collected, we delete the key. This scheme is biased towards efficiency when get() is called much more frequently than set(). It is slightly internaler than the all-Java solution using the underlying map in the set() case. However, get() is very much more frequently invoked than set(). */ #ifdef _POSIX_PTHREAD_SEMANTICS class tls_t { public: pthread_key_t key; }; void java::lang::ThreadLocal::constructNative (void) { tls_t *tls = (tls_t *)_Jv_Malloc (sizeof (tls_t)); if (pthread_key_create (&tls->key, NULL) == 0) TLSPointer = (::gnu::gcj::RawData *)tls; else _Jv_Free (tls); } void java::lang::ThreadLocal::set (::java::lang::Object *value) { if (TLSPointer != NULL) { tls_t* tls = (tls_t*)TLSPointer; pthread_setspecific (tls->key, value); } internalSet (value); } ::java::lang::Object * java::lang::ThreadLocal::get (void) { if (TLSPointer == NULL) return internalGet (); tls_t* tls = (tls_t*)TLSPointer; void *obj = pthread_getspecific(tls->key); if (obj) return (::java::lang::Object *)obj; ::java::lang::Object *value = internalGet (); pthread_setspecific (tls->key, value); return value; } void java::lang::ThreadLocal::remove (void) { if (TLSPointer != NULL) { tls_t* tls = (tls_t*)TLSPointer; pthread_setspecific (tls->key, NULL); } internalRemove (); } void java::lang::ThreadLocal::finalize (void) { if (TLSPointer != NULL) { tls_t* tls = (tls_t*)TLSPointer; pthread_key_delete (tls->key); _Jv_Free (tls); } } #else void java::lang::ThreadLocal::constructNative (void) { } void java::lang::ThreadLocal::set (::java::lang::Object *value) { internalSet (value); } ::java::lang::Object * java::lang::ThreadLocal::get (void) { return internalGet (); } void java::lang::ThreadLocal::remove (void) { internalRemove (); } void java::lang::ThreadLocal::finalize (void) { } #endif