mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			170 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			170 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
| // 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
 |