diff options
Diffstat (limited to 'libjava/java/lang/natThreadLocal.cc')
-rw-r--r-- | libjava/java/lang/natThreadLocal.cc | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/libjava/java/lang/natThreadLocal.cc b/libjava/java/lang/natThreadLocal.cc new file mode 100644 index 00000000000..cd61f4a623f --- /dev/null +++ b/libjava/java/lang/natThreadLocal.cc @@ -0,0 +1,169 @@ +// 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 <config.h> + +#include <stdlib.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-threads.h> + +#include <gnu/gcj/RawDataManaged.h> +#include <java/lang/ThreadLocal.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/IllegalThreadStateException.h> +#include <java/lang/InterruptedException.h> +#include <java/util/Map.h> + +#include <jni.h> + +/* 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 |