mirror of
https://github.com/corda/corda.git
synced 2025-01-19 11:16:54 +00:00
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:
parent
ff19ab6c13
commit
5d3dc707cb
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user