From 59e1980bc05264cbe73d28338c0073b46a2480bd Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Fri, 6 Oct 2006 17:00:37 +0000 Subject: 2006-10-06 Andrew Haley * builtins.c (compareAndSwapInt_builtin): Check that we really do have a compare_and_swap builtin. (compareAndSwapLong_builtin): Likewise. (compareAndSwapObject_builtin): Likewise. 2006-10-06 Andrew Haley * posix-threads.cc (_Jv_ThreadUnpark, _Jv_ThreadPark): Moved here from sun/misc/natUnsafe.cc. * sun/misc/natUnsafe.cc (class spinlock): New class. (compareAndSwap): New methods. (compareAndSwapInt, compareAndSwapLong, compareAndSwapObject) (putOrderedLong, putLongVolatile, putObjectVolatile, putLong) (getIntVolatile, getObjectVolatile, getLong, getLongVolatile): Rewrite to use gcj's own atomic functions rather than gcc builtins. (unpark): Moved to posix-threads.cc (park): Likewise. * include/jvm.h (struct natThread::alive_flag): Moved here from Thread.java. (struct natThread): Likewise. * include/posix-threads.h: (_Jv_ThreadUnpark, _Jv_ThreadPark): moved here from sun/misc/natUnsafe.cc. * java/lang/natThread.cc (initialize_native): Set alive_flag here. (isAlive): Moved here from Thread.java. (interrupt): alive_flag is now in the natThread structure. (interrupt): Call _Jv_ThreadUnpark(). (finish_): parkPermit and alive_flag are now in the natThread structure. (start): LIkewise. (_Jv_AttachCurrentThread): Likewise. * java/lang/Thread.java (alive_flag): Remove. (parkPermit): Likewise. (Thread): Don't set alive_flag. (isAlive): Make native. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/gcj-eclipse@117510 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/java/ChangeLog | 7 ++ gcc/java/builtins.c | 99 ++++++++++-------- libjava/ChangeLog | 31 ++++++ libjava/include/jvm.h | 11 +- libjava/include/posix-threads.h | 3 + libjava/java/lang/Thread.java | 8 +- libjava/java/lang/natThread.cc | 40 ++++---- libjava/posix-threads.cc | 123 +++++++++++++++++++++++ libjava/sun/misc/natUnsafe.cc | 217 ++++++++++++++++++++-------------------- 9 files changed, 362 insertions(+), 177 deletions(-) diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 14b0cbfc3d5..c063ab5e79e 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,10 @@ +2006-10-06 Andrew Haley + + * builtins.c (compareAndSwapInt_builtin): Check that we really do + have a compare_and_swap builtin. + (compareAndSwapLong_builtin): Likewise. + (compareAndSwapObject_builtin): Likewise. + 2006-10-04 Andrew Haley * builtins.c (java_builtins): Add compareAndSwapInt, diff --git a/gcc/java/builtins.c b/gcc/java/builtins.c index fe27f04c9da..d8238415d42 100644 --- a/gcc/java/builtins.c +++ b/gcc/java/builtins.c @@ -36,7 +36,10 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "java-tree.h" #include #include "convert.h" - +#include "rtl.h" +#include "insn-codes.h" +#include "expr.h" +#include "optabs.h" static tree max_builtin (tree, tree); static tree min_builtin (tree, tree); @@ -299,56 +302,75 @@ static tree compareAndSwapInt_builtin (tree method_return_type ATTRIBUTE_UNUSED, tree method_arguments) { - tree newarglist, addr, stmt; - UNMARSHAL5 (method_arguments); + enum machine_mode mode = TYPE_MODE (int_type_node); + if (sync_compare_and_swap_cc[mode] != CODE_FOR_nothing + || sync_compare_and_swap[mode] != CODE_FOR_nothing) + { + tree newarglist, addr, stmt; + UNMARSHAL5 (method_arguments); - addr = build_addr_sum (int_type_node, obj_arg, offset_arg); + addr = build_addr_sum (int_type_node, obj_arg, offset_arg); - newarglist - = build_arglist_for_builtin (addr, expected_arg, value_arg, NULL_TREE); - stmt = (build_function_call_expr - (built_in_decls[BUILT_IN_BOOL_COMPARE_AND_SWAP_4], - newarglist)); + newarglist + = build_arglist_for_builtin (addr, expected_arg, value_arg, NULL_TREE); + stmt = (build_function_call_expr + (built_in_decls[BUILT_IN_BOOL_COMPARE_AND_SWAP_4], + newarglist)); - return build_check_this (stmt, this_arg); + return build_check_this (stmt, this_arg); + } + return NULL_TREE; } static tree compareAndSwapLong_builtin (tree method_return_type ATTRIBUTE_UNUSED, tree method_arguments) { - tree newarglist, addr, stmt; - UNMARSHAL5 (method_arguments); + enum machine_mode mode = TYPE_MODE (long_type_node); + if (sync_compare_and_swap_cc[mode] != CODE_FOR_nothing + || sync_compare_and_swap[mode] != CODE_FOR_nothing) + { + tree newarglist, addr, stmt; + UNMARSHAL5 (method_arguments); - addr = build_addr_sum (long_type_node, obj_arg, offset_arg); + addr = build_addr_sum (long_type_node, obj_arg, offset_arg); - newarglist - = build_arglist_for_builtin (addr, expected_arg, value_arg, NULL_TREE); - stmt = (build_function_call_expr - (built_in_decls[BUILT_IN_BOOL_COMPARE_AND_SWAP_8], - newarglist)); + newarglist + = build_arglist_for_builtin (addr, expected_arg, value_arg, NULL_TREE); + stmt = (build_function_call_expr + (built_in_decls[BUILT_IN_BOOL_COMPARE_AND_SWAP_8], + newarglist)); - return build_check_this (stmt, this_arg); + return build_check_this (stmt, this_arg); + } + return NULL_TREE; } - static tree compareAndSwapObject_builtin (tree method_return_type ATTRIBUTE_UNUSED, tree method_arguments) { - tree newarglist, addr, stmt; - UNMARSHAL5 (method_arguments); - - addr = build_addr_sum (value_type, obj_arg, offset_arg); - - newarglist - = build_arglist_for_builtin (addr, expected_arg, value_arg, NULL_TREE); - stmt = (build_function_call_expr - (built_in_decls[POINTER_SIZE == 32 - ? BUILT_IN_BOOL_COMPARE_AND_SWAP_4 - : BUILT_IN_BOOL_COMPARE_AND_SWAP_8], - newarglist)); - - return build_check_this (stmt, this_arg); + enum machine_mode mode = TYPE_MODE (ptr_type_node); + if (sync_compare_and_swap_cc[mode] != CODE_FOR_nothing + || sync_compare_and_swap[mode] != CODE_FOR_nothing) + { + tree newarglist, addr, stmt; + UNMARSHAL5 (method_arguments); + + int builtin = (POINTER_SIZE == 32 + ? BUILT_IN_BOOL_COMPARE_AND_SWAP_4 + : BUILT_IN_BOOL_COMPARE_AND_SWAP_8); + + addr = build_addr_sum (value_type, obj_arg, offset_arg); + + newarglist + = build_arglist_for_builtin (addr, expected_arg, value_arg, NULL_TREE); + stmt = (build_function_call_expr + (built_in_decls[builtin], + newarglist)); + + return build_check_this (stmt, this_arg); + } + return NULL_TREE; } static tree @@ -366,7 +388,7 @@ putVolatile_builtin (tree method_return_type ATTRIBUTE_UNUSED, newarglist = NULL_TREE; stmt = (build_function_call_expr (built_in_decls[BUILT_IN_SYNCHRONIZE], - newarglist)); + newarglist)); modify_stmt = fold_build2 (MODIFY_EXPR, value_type, build_java_indirect_ref (value_type, addr, flag_check_references), @@ -392,7 +414,7 @@ getVolatile_builtin (tree method_return_type ATTRIBUTE_UNUSED, newarglist = NULL_TREE; stmt = (build_function_call_expr (built_in_decls[BUILT_IN_SYNCHRONIZE], - newarglist)); + newarglist)); tmp = build_decl (VAR_DECL, NULL, method_return_type); DECL_IGNORED_P (tmp) = 1; @@ -525,7 +547,6 @@ initialize_builtins (void) boolean_ftype_boolean_boolean, "__builtin_expect", BUILTIN_CONST | BUILTIN_NOTHROW); - define_builtin (BUILT_IN_BOOL_COMPARE_AND_SWAP_4, "__sync_bool_compare_and_swap_4", build_function_type_list (boolean_type_node, @@ -533,7 +554,6 @@ initialize_builtins (void) build_pointer_type (int_type_node), int_type_node, NULL_TREE), "__sync_bool_compare_and_swap_4", 0); - define_builtin (BUILT_IN_BOOL_COMPARE_AND_SWAP_8, "__sync_bool_compare_and_swap_8", build_function_type_list (boolean_type_node, @@ -541,11 +561,10 @@ initialize_builtins (void) build_pointer_type (long_type_node), int_type_node, NULL_TREE), "__sync_bool_compare_and_swap_8", 0); - define_builtin (BUILT_IN_SYNCHRONIZE, "__sync_synchronize", build_function_type (void_type_node, void_list_node), "__sync_synchronize", BUILTIN_NOTHROW); - + build_common_builtin_nodes (); } diff --git a/libjava/ChangeLog b/libjava/ChangeLog index fe33b0a4bde..dc223a938e4 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,34 @@ +2006-10-06 Andrew Haley + + * posix-threads.cc (_Jv_ThreadUnpark, _Jv_ThreadPark): Moved here + from sun/misc/natUnsafe.cc. + * sun/misc/natUnsafe.cc (class spinlock): New class. + (compareAndSwap): New methods. + (compareAndSwapInt, compareAndSwapLong, compareAndSwapObject) + (putOrderedLong, putLongVolatile, putObjectVolatile, putLong) + (getIntVolatile, getObjectVolatile, getLong, getLongVolatile): + Rewrite to use gcj's own atomic functions rather than gcc + builtins. + (unpark): Moved to posix-threads.cc + (park): Likewise. + * include/jvm.h (struct natThread::alive_flag): Moved here from + Thread.java. + (struct natThread): Likewise. + * include/posix-threads.h: (_Jv_ThreadUnpark, _Jv_ThreadPark): + moved here from sun/misc/natUnsafe.cc. + * java/lang/natThread.cc (initialize_native): Set alive_flag here. + (isAlive): Moved here from Thread.java. + (interrupt): alive_flag is now in the natThread structure. + (interrupt): Call _Jv_ThreadUnpark(). + (finish_): parkPermit and alive_flag are now in the natThread + structure. + (start): LIkewise. + (_Jv_AttachCurrentThread): Likewise. + * java/lang/Thread.java (alive_flag): Remove. + (parkPermit): Likewise. + (Thread): Don't set alive_flag. + (isAlive): Make native. + 2006-09-13 Andrew Haley * Makefile.am: Add sun/reflect/natReflection.cc. diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h index 74407bd7401..4f860133d5c 100644 --- a/libjava/include/jvm.h +++ b/libjava/include/jvm.h @@ -32,6 +32,8 @@ details. */ #include +#include + /* Macro for possible unused arguments. */ #define MAYBE_UNUSED __attribute__((__unused__)) @@ -750,13 +752,20 @@ public: // the Thread class. struct natThread { + // A thread is either alive, dead, or being sent a signal; if it is + // being sent a signal, it is also alive. Thus, if you want to know + // if a thread is alive, it is sufficient to test alive_status != + // THREAD_DEAD. + volatile obj_addr_t alive_flag; + // These are used to interrupt sleep and join calls. We can share a // condition variable here since it only ever gets notified when the thread // exits. _Jv_Mutex_t join_mutex; _Jv_ConditionVariable_t join_cond; - // These are used by Unsafe.park() and Unsafe.unpark(). + // These are used by Unsafe.park() and Unsafe.unpark(). + volatile obj_addr_t park_permit; pthread_mutex_t park_mutex; pthread_cond_t park_cond; diff --git a/libjava/include/posix-threads.h b/libjava/include/posix-threads.h index 86a021e4553..2cc30160c12 100644 --- a/libjava/include/posix-threads.h +++ b/libjava/include/posix-threads.h @@ -342,4 +342,7 @@ void _Jv_ThreadWait (void); void _Jv_ThreadInterrupt (_Jv_Thread_t *data); +void _Jv_ThreadUnpark (::java::lang::Thread *thread); +void _Jv_ThreadPark (jboolean isAbsolute, jlong time); + #endif /* __JV_POSIX_THREADS__ */ diff --git a/libjava/java/lang/Thread.java b/libjava/java/lang/Thread.java index e7865caac26..e030aeaec27 100644 --- a/libjava/java/lang/Thread.java +++ b/libjava/java/lang/Thread.java @@ -135,7 +135,6 @@ public class Thread implements Runnable private static final byte THREAD_DEAD = 0; private static final byte THREAD_ALIVE = 1; private static final byte THREAD_SIGNALED = 2; - private volatile byte alive_flag; private boolean startable_flag; @@ -171,7 +170,6 @@ public class Thread implements Runnable static final byte THREAD_PARK_PERMIT = 1; static final byte THREAD_PARK_PARKED = 2; static final byte THREAD_PARK_DEAD = 3; - byte parkPermit; // This describes the top-most interpreter frame for this thread. RawData interp_frame; @@ -395,7 +393,6 @@ public class Thread implements Runnable data = null; interrupt_flag = false; - alive_flag = THREAD_DEAD; startable_flag = true; if (current != null) @@ -606,10 +603,7 @@ public class Thread implements Runnable * * @return whether this Thread is alive */ - public final synchronized boolean isAlive() - { - return alive_flag != THREAD_DEAD; - } + public final native boolean isAlive(); /** * Tell whether this is a daemon Thread or not. diff --git a/libjava/java/lang/natThread.cc b/libjava/java/lang/natThread.cc index 8ea31ef9421..637f8a2884e 100644 --- a/libjava/java/lang/natThread.cc +++ b/libjava/java/lang/natThread.cc @@ -44,6 +44,7 @@ java::lang::Thread::initialize_native (void) natThread *nt = (natThread *) _Jv_AllocBytes (sizeof (natThread)); state = JV_NEW; + nt->alive_flag = THREAD_DEAD; data = (gnu::gcj::RawDataManaged *) nt; @@ -104,32 +105,33 @@ java::lang::Thread::holdsLock (jobject obj) return !_Jv_ObjectCheckMonitor (obj); } +jboolean +java::lang::Thread::isAlive (void) +{ + natThread *nt = (natThread *) data; + return nt->alive_flag != (obj_addr_t)THREAD_DEAD; +} + void java::lang::Thread::interrupt (void) { checkAccess (); + natThread *nt = (natThread *) data; + // If a thread is in state ALIVE, we atomically set it to state // SIGNALED and send it a signal. Once we've sent it the signal, we // set its state back to ALIVE. - if (__sync_bool_compare_and_swap - (&alive_flag, Thread::THREAD_ALIVE, Thread::THREAD_SIGNALED)) + if (compare_and_swap + (&nt->alive_flag, Thread::THREAD_ALIVE, Thread::THREAD_SIGNALED)) { - natThread *nt = (natThread *) data; - _Jv_ThreadInterrupt (nt->thread); - __sync_bool_compare_and_swap - (&alive_flag, THREAD_SIGNALED, Thread::THREAD_ALIVE); + compare_and_swap + (&nt->alive_flag, THREAD_SIGNALED, Thread::THREAD_ALIVE); // Even though we've interrupted this thread, it might still be // parked. - if (__sync_bool_compare_and_swap - (&parkPermit, Thread::THREAD_PARK_PARKED, Thread::THREAD_PARK_RUNNING)) - { - pthread_mutex_lock (&nt->park_mutex); - pthread_cond_signal (&nt->park_cond); - pthread_mutex_unlock (&nt->park_mutex); - } + _Jv_ThreadUnpark (this); } } @@ -209,10 +211,10 @@ java::lang::Thread::sleep (jlong millis, jint nanos) void java::lang::Thread::finish_ () { - parkPermit = THREAD_PARK_DEAD; __sync_synchronize(); natThread *nt = (natThread *) data; + nt->park_permit = THREAD_PARK_DEAD; group->removeThread (this); #ifdef ENABLE_JVMPI @@ -240,7 +242,7 @@ java::lang::Thread::finish_ () { JvSynchronize sync (this); - alive_flag = THREAD_DEAD; + nt->alive_flag = THREAD_DEAD; state = JV_TERMINATED; } @@ -342,10 +344,10 @@ java::lang::Thread::start (void) if (!startable_flag) throw new IllegalThreadStateException; - alive_flag = THREAD_ALIVE; + natThread *nt = (natThread *) data; + nt->alive_flag = THREAD_ALIVE; startable_flag = false; state = JV_RUNNABLE; - natThread *nt = (natThread *) data; _Jv_ThreadStart (this, nt->thread, (_Jv_ThreadStartFunc *) &_Jv_ThreadRun); } @@ -455,9 +457,9 @@ _Jv_AttachCurrentThread(java::lang::Thread* thread) if (thread == NULL || thread->startable_flag == false) return -1; thread->startable_flag = false; - thread->alive_flag = ::java::lang::Thread::THREAD_ALIVE; - thread->state = JV_RUNNABLE; natThread *nt = (natThread *) thread->data; + nt->alive_flag = ::java::lang::Thread::THREAD_ALIVE; + thread->state = JV_RUNNABLE; _Jv_ThreadRegister (nt->thread); return 0; } diff --git a/libjava/posix-threads.cc b/libjava/posix-threads.cc index db21c93a823..19a7631d64a 100644 --- a/libjava/posix-threads.cc +++ b/libjava/posix-threads.cc @@ -327,6 +327,129 @@ _Jv_ThreadInterrupt (_Jv_Thread_t *data) pthread_mutex_unlock (&data->wait_mutex); } +/** + * Releases the block on a thread created by _Jv_ThreadPark(). This + * method can also be used to terminate a blockage caused by a prior + * call to park. This operation is unsafe, as the thread must be + * guaranteed to be live. + * + * @param thread the thread to unblock. + */ + +void +_Jv_ThreadUnpark (::java::lang::Thread *thread) +{ + using namespace ::java::lang; + natThread *nt = (natThread *) thread->data; + volatile obj_addr_t *ptr = &nt->park_permit; + + /* If this thread is in state RUNNING, give it a permit and return + immediately. */ + if (compare_and_swap + (ptr, Thread::THREAD_PARK_RUNNING, Thread::THREAD_PARK_PERMIT)) + return; + + /* If this thread is parked, put it into state RUNNING and send it a + signal. */ + if (compare_and_swap + (ptr, Thread::THREAD_PARK_PARKED, Thread::THREAD_PARK_RUNNING)) + { + pthread_mutex_lock (&nt->park_mutex); + pthread_cond_signal (&nt->park_cond); + pthread_mutex_unlock (&nt->park_mutex); + } +} + +/** + * Blocks the thread until a matching _Jv_ThreadUnpark() occurs, the + * thread is interrupted or the optional timeout expires. If an + * unpark call has already occurred, this also counts. A timeout + * value of zero is defined as no timeout. When isAbsolute is true, + * the timeout is in milliseconds relative to the epoch. Otherwise, + * the value is the number of nanoseconds which must occur before + * timeout. This call may also return spuriously (i.e. for no + * apparent reason). + * + * @param isAbsolute true if the timeout is specified in milliseconds from + * the epoch. + * @param time either the number of nanoseconds to wait, or a time in + * milliseconds from the epoch to wait for. + */ + +void +_Jv_ThreadPark (jboolean isAbsolute, jlong time) +{ + using namespace ::java::lang; + Thread *thread = Thread::currentThread(); + natThread *nt = (natThread *) thread->data; + volatile obj_addr_t *ptr = &nt->park_permit; + + /* If we have a permit, return immediately. */ + if (compare_and_swap + (ptr, Thread::THREAD_PARK_PERMIT, Thread::THREAD_PARK_RUNNING)) + return; + + struct timespec ts; + jlong millis = 0, nanos = 0; + + if (time) + { + if (isAbsolute) + { + millis = time; + nanos = 0; + } + else + { + millis = java::lang::System::currentTimeMillis(); + nanos = time; + } + + if (millis > 0 || nanos > 0) + { + // Calculate the abstime corresponding to the timeout. + // Everything is in milliseconds. + // + // We use `unsigned long long' rather than jlong because our + // caller may pass up to Long.MAX_VALUE millis. This would + // overflow the range of a timespec. + + unsigned long long m = (unsigned long long)millis; + unsigned long long seconds = m / 1000; + + ts.tv_sec = seconds; + if (ts.tv_sec < 0 || (unsigned long long)ts.tv_sec != seconds) + { + // We treat a timeout that won't fit into a struct timespec + // as a wait forever. + millis = nanos = 0; + } + else + { + m %= 1000; + ts.tv_nsec = m * 1000000 + (unsigned long long)nanos; + } + } + } + + pthread_mutex_lock (&nt->park_mutex); + if (compare_and_swap + (ptr, Thread::THREAD_PARK_RUNNING, Thread::THREAD_PARK_PARKED)) + { + if (millis == 0 && nanos == 0) + pthread_cond_wait (&nt->park_cond, &nt->park_mutex); + else + pthread_cond_timedwait (&nt->park_cond, &nt->park_mutex, + &ts); + /* If we were unparked by some other thread, this will already + be in state THREAD_PARK_RUNNING. If we timed out, we have to + do it ourself. */ + compare_and_swap + (ptr, Thread::THREAD_PARK_PARKED, Thread::THREAD_PARK_RUNNING); + } + pthread_mutex_unlock (&nt->park_mutex); +} + static void handle_intr (int) { diff --git a/libjava/sun/misc/natUnsafe.cc b/libjava/sun/misc/natUnsafe.cc index 6f88226ad98..b30f275ad9b 100644 --- a/libjava/sun/misc/natUnsafe.cc +++ b/libjava/sun/misc/natUnsafe.cc @@ -1,3 +1,14 @@ +// natUnsafe.cc - Implementation of sun.misc.Unsafe native methods. + +/* 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 #include #include @@ -9,6 +20,64 @@ #include #include +#include "sysdep/locks.h" + +// Use a spinlock for multi-word accesses +class spinlock +{ + static volatile obj_addr_t lock; + +public: + +spinlock () + { + while (! compare_and_swap (&lock, 0, 1)); + } + ~spinlock () + { + release_set (&lock, 0); + } +}; + +// This is a single lock that is used for all synchronized accesses if +// the compiler can't generate inline compare-and-swap operations. In +// most cases it'll never be used, but the i386 needs it for 64-bit +// locked accesses and so does PPC32. It's worth building libgcj with +// target=i486 (or above) to get the inlines. +volatile obj_addr_t spinlock::lock; + + +static inline bool +compareAndSwap (volatile jint *addr, jint old, jint new_val) +{ + jboolean result = false; + spinlock lock; + if ((result = (*addr == old))) + *addr = new_val; + return result; +} + +static inline bool +compareAndSwap (volatile jlong *addr, jlong old, jlong new_val) +{ + jboolean result = false; + spinlock lock; + if ((result = (*addr == old))) + *addr = new_val; + return result; +} + +static inline bool +compareAndSwap (volatile jobject *addr, jobject old, jobject new_val) +{ + jboolean result = false; + spinlock lock; + if ((result = (*addr == old))) + *addr = new_val; + return result; +} + + jlong sun::misc::Unsafe::objectFieldOffset (::java::lang::reflect::Field *field) { @@ -17,14 +86,6 @@ sun::misc::Unsafe::objectFieldOffset (::java::lang::reflect::Field *field) return fld->getOffset(); } -jboolean -sun::misc::Unsafe::compareAndSwapInt (jobject obj, jlong offset, - jint expect, jint update) -{ - jint *addr = (jint *)((char *)obj + offset); - return __sync_bool_compare_and_swap (addr, expect, update); -} - jint sun::misc::Unsafe::arrayBaseOffset (jclass arrayClass) { @@ -43,12 +104,23 @@ sun::misc::Unsafe::arrayIndexScale (jclass arrayClass) return sizeof (void *); } +// These methods are used when the compiler fails to generate inline +// versions of the compare-and-swap primitives. + +jboolean +sun::misc::Unsafe::compareAndSwapInt (jobject obj, jlong offset, + jint expect, jint update) +{ + jint *addr = (jint *)((char *)obj + offset); + return compareAndSwap (addr, expect, update); +} + jboolean sun::misc::Unsafe::compareAndSwapLong (jobject obj, jlong offset, jlong expect, jlong update) { - jlong *addr = (jlong*)((char *) obj + offset); - return __sync_bool_compare_and_swap (addr, expect, update); + volatile jlong *addr = (jlong*)((char *) obj + offset); + return compareAndSwap (addr, expect, update); } jboolean @@ -56,48 +128,52 @@ sun::misc::Unsafe::compareAndSwapObject (jobject obj, jlong offset, jobject expect, jobject update) { jobject *addr = (jobject*)((char *) obj + offset); - return __sync_bool_compare_and_swap (addr, expect, update); + return compareAndSwap (addr, expect, update); } void sun::misc::Unsafe::putOrderedInt (jobject obj, jlong offset, jint value) { - jint *addr = (jint *) ((char *) obj + offset); + volatile jint *addr = (jint *) ((char *) obj + offset); *addr = value; } void sun::misc::Unsafe::putOrderedLong (jobject obj, jlong offset, jlong value) { - jlong *addr = (jlong *) ((char *) obj + offset); + volatile jlong *addr = (jlong *) ((char *) obj + offset); + spinlock lock; *addr = value; } void sun::misc::Unsafe::putOrderedObject (jobject obj, jlong offset, jobject value) { - jobject *addr = (jobject *) ((char *) obj + offset); + volatile jobject *addr = (jobject *) ((char *) obj + offset); *addr = value; } void sun::misc::Unsafe::putIntVolatile (jobject obj, jlong offset, jint value) { - jint *addr = (jint *) ((char *) obj + offset); + write_barrier (); + volatile jint *addr = (jint *) ((char *) obj + offset); *addr = value; } void sun::misc::Unsafe::putLongVolatile (jobject obj, jlong offset, jlong value) { - jlong *addr = (jlong *) ((char *) obj + offset); + volatile jlong *addr = (jlong *) ((char *) obj + offset); + spinlock lock; *addr = value; } void sun::misc::Unsafe::putObjectVolatile (jobject obj, jlong offset, jobject value) { - jobject *addr = (jobject *) ((char *) obj + offset); + write_barrier (); + volatile jobject *addr = (jobject *) ((char *) obj + offset); *addr = value; } @@ -114,6 +190,7 @@ void sun::misc::Unsafe::putLong (jobject obj, jlong offset, jlong value) { jlong *addr = (jlong *) ((char *) obj + offset); + spinlock lock; *addr = value; } @@ -127,125 +204,45 @@ sun::misc::Unsafe::putObject (jobject obj, jlong offset, jobject value) jint sun::misc::Unsafe::getIntVolatile (jobject obj, jlong offset) { - jint *addr = (jint *) ((char *) obj + offset); - return *addr; + volatile jint *addr = (jint *) ((char *) obj + offset); + jint result = *addr; + read_barrier (); + return result; } jobject sun::misc::Unsafe::getObjectVolatile (jobject obj, jlong offset) { - jobject *addr = (jobject *) ((char *) obj + offset); - return *addr; + volatile jobject *addr = (jobject *) ((char *) obj + offset); + jobject result = *addr; + read_barrier (); + return result; } jlong sun::misc::Unsafe::getLong (jobject obj, jlong offset) { jlong *addr = (jlong *) ((char *) obj + offset); + spinlock lock; return *addr; } jlong sun::misc::Unsafe::getLongVolatile (jobject obj, jlong offset) { - jlong *addr = (jlong *) ((char *) obj + offset); + volatile jlong *addr = (jlong *) ((char *) obj + offset); + spinlock lock; return *addr; } void sun::misc::Unsafe::unpark (::java::lang::Thread *thread) { - using namespace ::java::lang; - volatile jbyte *ptr = &thread->parkPermit; - - /* If this thread is in state RUNNING, give it a permit and return - immediately. */ - if (__sync_bool_compare_and_swap - (ptr, Thread::THREAD_PARK_RUNNING, Thread::THREAD_PARK_PERMIT)) - return; - - /* If this thread is parked, put it into state RUNNING and send it a - signal. */ - if (__sync_bool_compare_and_swap - (ptr, Thread::THREAD_PARK_PARKED, Thread::THREAD_PARK_RUNNING)) - { - natThread *nt = (natThread *) thread->data; - pthread_mutex_lock (&nt->park_mutex); - pthread_cond_signal (&nt->park_cond); - pthread_mutex_unlock (&nt->park_mutex); - } + _Jv_ThreadUnpark (thread); } void sun::misc::Unsafe::park (jboolean isAbsolute, jlong time) { - using namespace ::java::lang; - Thread *thread = Thread::currentThread(); - volatile jbyte *ptr = &thread->parkPermit; - - /* If we have a permit, return immediately. */ - if (__sync_bool_compare_and_swap - (ptr, Thread::THREAD_PARK_PERMIT, Thread::THREAD_PARK_RUNNING)) - return; - - struct timespec ts; - jlong millis = 0, nanos = 0; - - if (time) - { - if (isAbsolute) - { - millis = time; - nanos = 0; - } - else - { - millis = java::lang::System::currentTimeMillis(); - nanos = time; - } - - if (millis > 0 || nanos > 0) - { - // Calculate the abstime corresponding to the timeout. - // Everything is in milliseconds. - // - // We use `unsigned long long' rather than jlong because our - // caller may pass up to Long.MAX_VALUE millis. This would - // overflow the range of a timespec. - - unsigned long long m = (unsigned long long)millis; - unsigned long long seconds = m / 1000; - - ts.tv_sec = seconds; - if (ts.tv_sec < 0 || (unsigned long long)ts.tv_sec != seconds) - { - // We treat a timeout that won't fit into a struct timespec - // as a wait forever. - millis = nanos = 0; - } - else - { - m %= 1000; - ts.tv_nsec = m * 1000000 + (unsigned long long)nanos; - } - } - } - - natThread *nt = (natThread *) thread->data; - pthread_mutex_lock (&nt->park_mutex); - if (__sync_bool_compare_and_swap - (ptr, Thread::THREAD_PARK_RUNNING, Thread::THREAD_PARK_PARKED)) - { - if (millis == 0 && nanos == 0) - pthread_cond_wait (&nt->park_cond, &nt->park_mutex); - else - pthread_cond_timedwait (&nt->park_cond, &nt->park_mutex, - &ts); - /* If we were unparked by some other thread, this will already - be in state THREAD_PARK_RUNNING. If we timed out, we have to - do it ourself. */ - __sync_bool_compare_and_swap - (ptr, Thread::THREAD_PARK_PARKED, Thread::THREAD_PARK_RUNNING); - } - pthread_mutex_unlock (&nt->park_mutex); + _Jv_ThreadPark (isAbsolute, time); } -- cgit v1.2.3