Merged gcj-eclipse branch to trunk.
From-SVN: r120621
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user