briefly enter idle state in get*Volatile

In order for a thread to enter the "exclusive" state such that no
other threads are active in the VM, it must wait for all active
threads to enter the "idle" state.  In order for this to happen in a
timely manner, threads must check frequently to see if a thread is
waiting to enter the exclusive state.  These checks happen at every
memory allocation, wait, sleep, native call, etc.  However, if a
thread is in a busy loop that does none of those things, it will block
any other thread from entering that state.

The proper way to address this is to detect such loops (or tail
recursion in tail-call-optimized builds) at compile or interpret time
and insert explicit checks.  This hasn't been a high priority thus
far, though, since we had yet to encounter such code in the wild.

Now, however, we find that scala.concurrent.forkjoin.ForkJoinPool.scan
(and possibly some versions of java.util.concurrent.ForkJoinPool.scan,
on which we assume the former is based) has just such a loop.
Fortunately, that loop calls Unsafe.getObjectVolatile, which the VM
implements and thus can treat as a checkpoint.  That's the workaround
we use in this patch.
This commit is contained in:
Joel Dice 2013-03-08 18:21:12 -07:00
parent ff19ab6c13
commit 5d3dc707cb

View File

@ -2729,11 +2729,15 @@ Avian_sun_misc_Unsafe_getFloat__Ljava_lang_Object_2J
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getIntVolatile
(Thread*, object, uintptr_t* arguments)
(Thread* t, object, uintptr_t* arguments)
{
object o = reinterpret_cast<object>(arguments[1]);
int64_t offset; memcpy(&offset, arguments + 2, 8);
// avoid blocking the VM if this is being called in a busy loop
PROTECT(t, o);
{ ENTER(t, Thread::IdleState); }
int32_t result = fieldAtOffset<int32_t>(o, offset);
loadMemoryBarrier();
return result;
@ -2764,6 +2768,10 @@ Avian_sun_misc_Unsafe_getLongVolatile
object o = reinterpret_cast<object>(arguments[1]);
int64_t offset; memcpy(&offset, arguments + 2, 8);
// avoid blocking the VM if this is being called in a busy loop
PROTECT(t, o);
{ ENTER(t, Thread::IdleState); }
object field;
if (BytesPerWord < 8) {
field = local::fieldForOffset(t, o, offset);
@ -2869,10 +2877,14 @@ Avian_sun_misc_Unsafe_putLong__Ljava_lang_Object_2JJ
extern "C" JNIEXPORT int64_t JNICALL
Avian_sun_misc_Unsafe_getObjectVolatile
(Thread*, object, uintptr_t* arguments)
(Thread* t, object, uintptr_t* arguments)
{
object o = reinterpret_cast<object>(arguments[1]);
int64_t offset; memcpy(&offset, arguments + 2, 8);
// avoid blocking the VM if this is being called in a busy loop
PROTECT(t, o);
{ ENTER(t, Thread::IdleState); }
uintptr_t value = fieldAtOffset<uintptr_t>(o, offset);
loadMemoryBarrier();