diff options
Diffstat (limited to 'libjava')
-rw-r--r-- | libjava/ChangeLog | 8 | ||||
-rw-r--r-- | libjava/java/lang/ThreadLocal.java | 23 | ||||
-rw-r--r-- | libjava/java/lang/natThreadLocal.cc | 148 |
3 files changed, 87 insertions, 92 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 3b98a204d65..0dccbe7e806 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,11 @@ +2006-10-12 Andrew Haley <aph@redhat.com> + + * java/lang/natThreadLocal.cc: New file. + * java/lang/ThreadLocal.java: Rewrite to use native TLS. + * Makefile.am: Add java/lang/natThreadLocal.cc. + * sources.am: Move classpath/java/lang/ThreadLocal.java to + java/lang/ThreadLocal.java. + 2006-09-01 Andrew Haley <aph@redhat.com> * Makefile.in: Rebuild. diff --git a/libjava/java/lang/ThreadLocal.java b/libjava/java/lang/ThreadLocal.java index cd6276f5d7d..644c93b67e4 100644 --- a/libjava/java/lang/ThreadLocal.java +++ b/libjava/java/lang/ThreadLocal.java @@ -100,6 +100,7 @@ public class ThreadLocal */ public ThreadLocal() { + constructNative(); } /** @@ -125,7 +126,7 @@ public class ThreadLocal */ public native Object get(); - private final Object slowGet() + private final Object internalGet() { Map map = Thread.getThreadLocals(); // Note that we don't have to synchronize, as only this thread will @@ -149,7 +150,7 @@ public class ThreadLocal */ public native void set(Object value); - private final void slowSet(Object value) + private final void internalSet(Object value) { Map map = Thread.getThreadLocals(); // Note that we don't have to synchronize, as only this thread will @@ -164,27 +165,15 @@ public class ThreadLocal */ public native void remove(); - private final void slowRemove() + private final void internalRemove() { Map map = Thread.getThreadLocals(); map.remove(this); } - private final void setTLS(gnu.gcj.RawData p) - { - synchronized (sentinel) - { - if (counter == 0) - // We've run out of unique TLS IDs. Fall back to using slow - // TLS. - return; - id = counter++; - TLSPointer = p; - } - } + protected native void finalize () throws Throwable; - static private long counter = 1; + private native void constructNative(); private gnu.gcj.RawData TLSPointer; - private long id; } 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 |