aboutsummaryrefslogtreecommitdiff
path: root/libjava/java/lang/natThreadLocal.cc
diff options
context:
space:
mode:
authoraph <aph@138bc75d-0d04-0410-961f-82ee72b054a4>2006-09-01 16:50:49 +0000
committeraph <aph@138bc75d-0d04-0410-961f-82ee72b054a4>2006-09-01 16:50:49 +0000
commit6315672d0b699d57d74e0fffe8c8e068a691ed28 (patch)
treee491de0830a3e60ad749329b448695d646eb4fe4 /libjava/java/lang/natThreadLocal.cc
parent97d8b636c83861f1da127fa8107e62a8649be5b9 (diff)
2006-09-01 Andrew Haley <aph@redhat.com>
* class.c (find_tls_thunk): New function. (build_tls_thunks): New function. (build_tls_thunk): New function. (make_class_data): Spurious hacks. * parse.y (java_expand_method_bodies): Call build_tls_thunks(). * jcf-parse.c (parse_class_file): Likewise. * java-gimplify.c (java_maybe_replace_init_expr): New function. (java_gimplify_modify_expr): Call java_maybe_replace_init_expr. 2006-09-01 Andrew Haley <aph@redhat.com> * Makefile.in: Rebuild. * sources.am: Rebuild. * java/lang/natThreadLocal.cc: New file. * java/lang/ThreadLocal.java: Lotsa hacks. * Makefile.am: Add java/lang/natThreadLocal.cc. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcj/gcj-tls-experimental-branch@116632 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/java/lang/natThreadLocal.cc')
-rw-r--r--libjava/java/lang/natThreadLocal.cc171
1 files changed, 171 insertions, 0 deletions
diff --git a/libjava/java/lang/natThreadLocal.cc b/libjava/java/lang/natThreadLocal.cc
new file mode 100644
index 00000000000..3bced24541a
--- /dev/null
+++ b/libjava/java/lang/natThreadLocal.cc
@@ -0,0 +1,171 @@
+// 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.
+
+ 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.
+
+ This scheme is biased towards efficiency when get() is called much
+ more frequently than set(). It is slightly slower than the
+ all-Java solution using the underlying map in the set() case.
+ However, get() is very much more frequently invoked than set().
+
+*/
+
+
+typedef struct
+{
+ jlong id;
+ void *val;
+} tls_t;
+
+static inline tls_t*
+get_tls_addr (void *p)
+{
+ typedef tls_t* func (void);
+ func *fptr = (func*)p;
+
+ return fptr ();
+}
+
+void
+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;
+ }
+
+ slowSet (value);
+}
+
+::java::lang::Object *
+java::lang::ThreadLocal::get (void)
+{
+ if (TLSPointer == NULL)
+ return slowGet ();
+
+ tls_t* tls_var_p = get_tls_addr (TLSPointer);
+
+ if (tls_var_p->id == this->id)
+ return (::java::lang::Object *)tls_var_p->val;
+
+ ::java::lang::Object *value = slowGet ();
+ tls_var_p->val = value;
+ tls_var_p->id = this->id;
+
+ return value;
+}
+
+void
+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;
+ }
+
+ slowRemove ();
+}
+