aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/lang/natThreadLocal.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/java/lang/natThreadLocal.cc')
-rw-r--r--libjava/java/lang/natThreadLocal.cc148
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