diff options
Diffstat (limited to 'libjava/java/lang/natThreadLocal.cc')
-rw-r--r-- | libjava/java/lang/natThreadLocal.cc | 148 |
1 files changed, 73 insertions, 75 deletions
diff --git a/libjava/java/lang/natThreadLocal.cc b/libjava/java/lang/natThreadLocal.cc index 3bced24541a..1b81aab63f0 100644 --- a/libjava/java/lang/natThreadLocal.cc +++ b/libjava/java/lang/natThreadLocal.cc @@ -52,55 +52,10 @@ details. */ So, we can't simply replace get() and set() with accesses of a __thread variable. - This is how our soloution works: - - Whenever we create a static field of Class ThreadLocal, we also - create a variable with __thread attribute, but it is only used as a - cache of a ThreadLocal entry. Whenever we set() a static - ThreadLocal, we must update a map of ThreadLocals and the __thread - variable we're using to cache the entry. However, when we get() a - static ThreadLocal, we only need to read the cache. - - - In detail: - - When gcj allocates a static field that is an instance of - ThreadLocal, it also allocates a thread-local cache variable. This - is is a static structure of type tls_t: - - typedef struct - { - jlong id; - void *val; - } tls_t; - - When gcj generates a store that sets a ThreadLocal static field, it - also generates a call to setTLS(ptr). ptr is a pointer to a - function that returns the address of the cache variable in thread - local memory. ThreadLocal.setTLS(ptr) saves that function pointer - and also generates a unique ID that will be used to identify this - instance of ThreadLocal. So, the ThreadLocal instance is now - "tied" to that cache variable. - - The first time that ThreadLocal.set() is called in a particular - thread, we check the ID in the cache variable to see if it is the - same as the ID of this ThreadLocal instance. We see that it is - not, because all __thread variables are initialized to zero, so we - write the ID of this ThreadLocal and the value into the cache - variable. We also update the map of ThreadLocals on the heap; we - must do this for the benefit of the garbage collector. - - When get() is called, we look in the cache variable, check the ID, - see that it is the same as the ID of this ThreadLocal instance, and - return the value immediately. - - Whenever we need to invalidate the cache, we can do so by setting - ID to 0. - - This is safe even in degenerate cases such as assigning the same - ThreadLocal instance to multiple static fields or repeatedly - re-assigning a static field in multiple threads. If the cached - value doesn't belong to this ThreadLocal, we simply ignore it. + 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 slower than the @@ -110,19 +65,22 @@ details. */ */ -typedef struct -{ - jlong id; - void *val; -} tls_t; +#ifdef _POSIX_PTHREAD_SEMANTICS -static inline tls_t* -get_tls_addr (void *p) +class tls_t { - typedef tls_t* func (void); - func *fptr = (func*)p; +public: + pthread_key_t key; +}; - return fptr (); +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 @@ -130,28 +88,27 @@ java::lang::ThreadLocal::set (::java::lang::Object *value) { if (TLSPointer != NULL) { - tls_t* tls_var_p = get_tls_addr (TLSPointer); - tls_var_p->val = value; - tls_var_p->id = id; - } + tls_t* tls = (tls_t*)TLSPointer; + pthread_setspecific (tls->key, value); + } - slowSet (value); + internalSet (value); } ::java::lang::Object * java::lang::ThreadLocal::get (void) { if (TLSPointer == NULL) - return slowGet (); + return internalGet (); - tls_t* tls_var_p = get_tls_addr (TLSPointer); + tls_t* tls = (tls_t*)TLSPointer; + void *obj = pthread_getspecific(tls->key); - if (tls_var_p->id == this->id) - return (::java::lang::Object *)tls_var_p->val; + if (obj) + return (::java::lang::Object *)obj; - ::java::lang::Object *value = slowGet (); - tls_var_p->val = value; - tls_var_p->id = this->id; + ::java::lang::Object *value = internalGet (); + pthread_setspecific (tls->key, value); return value; } @@ -161,11 +118,52 @@ java::lang::ThreadLocal::remove (void) { if (TLSPointer != NULL) { - tls_t* tls_var_p = get_tls_addr (TLSPointer); - tls_var_p->val = NULL; - tls_var_p->id = 0; + 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) +{ +} - slowRemove (); +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 |