mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-17 17:44:40 +02:00
8223056: Remove Type-Stable-Memory support for Parkers
Reviewed-by: coleenp, rehn
This commit is contained in:
parent
35c9da7031
commit
77a4302309
9 changed files with 65 additions and 131 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -1533,15 +1533,22 @@ void os::PlatformEvent::unpark() {
|
||||||
|
|
||||||
// JSR166 support
|
// JSR166 support
|
||||||
|
|
||||||
os::PlatformParker::PlatformParker() {
|
os::PlatformParker::PlatformParker() : _counter(0), _cur_index(-1) {
|
||||||
int status;
|
int status = pthread_cond_init(&_cond[REL_INDEX], _condAttr);
|
||||||
status = pthread_cond_init(&_cond[REL_INDEX], _condAttr);
|
|
||||||
assert_status(status == 0, status, "cond_init rel");
|
assert_status(status == 0, status, "cond_init rel");
|
||||||
status = pthread_cond_init(&_cond[ABS_INDEX], NULL);
|
status = pthread_cond_init(&_cond[ABS_INDEX], NULL);
|
||||||
assert_status(status == 0, status, "cond_init abs");
|
assert_status(status == 0, status, "cond_init abs");
|
||||||
status = pthread_mutex_init(_mutex, _mutexAttr);
|
status = pthread_mutex_init(_mutex, _mutexAttr);
|
||||||
assert_status(status == 0, status, "mutex_init");
|
assert_status(status == 0, status, "mutex_init");
|
||||||
_cur_index = -1; // mark as unused
|
}
|
||||||
|
|
||||||
|
os::PlatformParker::~PlatformParker() {
|
||||||
|
int status = pthread_cond_destroy(&_cond[REL_INDEX]);
|
||||||
|
assert_status(status == 0, status, "cond_destroy rel");
|
||||||
|
status = pthread_cond_destroy(&_cond[ABS_INDEX]);
|
||||||
|
assert_status(status == 0, status, "cond_destroy abs");
|
||||||
|
status = pthread_mutex_destroy(_mutex);
|
||||||
|
assert_status(status == 0, status, "mutex_destroy");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parker::park decrements count if > 0, else does a condvar wait. Unpark
|
// Parker::park decrements count if > 0, else does a condvar wait. Unpark
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -184,21 +184,21 @@ class PlatformEvent : public CHeapObj<mtSynchronizer> {
|
||||||
// API updates of course). But Parker methods use fastpaths that break that
|
// API updates of course). But Parker methods use fastpaths that break that
|
||||||
// level of encapsulation - so combining the two remains a future project.
|
// level of encapsulation - so combining the two remains a future project.
|
||||||
|
|
||||||
class PlatformParker : public CHeapObj<mtSynchronizer> {
|
class PlatformParker {
|
||||||
|
NONCOPYABLE(PlatformParker);
|
||||||
protected:
|
protected:
|
||||||
enum {
|
enum {
|
||||||
REL_INDEX = 0,
|
REL_INDEX = 0,
|
||||||
ABS_INDEX = 1
|
ABS_INDEX = 1
|
||||||
};
|
};
|
||||||
|
volatile int _counter;
|
||||||
int _cur_index; // which cond is in use: -1, 0, 1
|
int _cur_index; // which cond is in use: -1, 0, 1
|
||||||
pthread_mutex_t _mutex[1];
|
pthread_mutex_t _mutex[1];
|
||||||
pthread_cond_t _cond[2]; // one for relative times and one for absolute
|
pthread_cond_t _cond[2]; // one for relative times and one for absolute
|
||||||
|
|
||||||
public: // TODO-FIXME: make dtor private
|
|
||||||
~PlatformParker() { guarantee(false, "invariant"); }
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PlatformParker();
|
PlatformParker();
|
||||||
|
~PlatformParker();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Workaround for a bug in macOSX kernel's pthread support (fixed in Mojave?).
|
// Workaround for a bug in macOSX kernel's pthread support (fixed in Mojave?).
|
||||||
|
|
|
@ -5431,11 +5431,10 @@ void os::PlatformEvent::unpark() {
|
||||||
|
|
||||||
// The Windows implementation of Park is very straightforward: Basic
|
// The Windows implementation of Park is very straightforward: Basic
|
||||||
// operations on Win32 Events turn out to have the right semantics to
|
// operations on Win32 Events turn out to have the right semantics to
|
||||||
// use them directly. We opportunistically resuse the event inherited
|
// use them directly.
|
||||||
// from Monitor.
|
|
||||||
|
|
||||||
void Parker::park(bool isAbsolute, jlong time) {
|
void Parker::park(bool isAbsolute, jlong time) {
|
||||||
guarantee(_ParkEvent != NULL, "invariant");
|
guarantee(_ParkHandle != NULL, "invariant");
|
||||||
// First, demultiplex/decode time arguments
|
// First, demultiplex/decode time arguments
|
||||||
if (time < 0) { // don't wait
|
if (time < 0) { // don't wait
|
||||||
return;
|
return;
|
||||||
|
@ -5457,16 +5456,16 @@ void Parker::park(bool isAbsolute, jlong time) {
|
||||||
|
|
||||||
// Don't wait if interrupted or already triggered
|
// Don't wait if interrupted or already triggered
|
||||||
if (thread->is_interrupted(false) ||
|
if (thread->is_interrupted(false) ||
|
||||||
WaitForSingleObject(_ParkEvent, 0) == WAIT_OBJECT_0) {
|
WaitForSingleObject(_ParkHandle, 0) == WAIT_OBJECT_0) {
|
||||||
ResetEvent(_ParkEvent);
|
ResetEvent(_ParkHandle);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
ThreadBlockInVM tbivm(thread);
|
ThreadBlockInVM tbivm(thread);
|
||||||
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
|
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
|
||||||
thread->set_suspend_equivalent();
|
thread->set_suspend_equivalent();
|
||||||
|
|
||||||
WaitForSingleObject(_ParkEvent, time);
|
WaitForSingleObject(_ParkHandle, time);
|
||||||
ResetEvent(_ParkEvent);
|
ResetEvent(_ParkHandle);
|
||||||
|
|
||||||
// If externally suspended while waiting, re-suspend
|
// If externally suspended while waiting, re-suspend
|
||||||
if (thread->handle_special_suspend_equivalent_condition()) {
|
if (thread->handle_special_suspend_equivalent_condition()) {
|
||||||
|
@ -5476,8 +5475,8 @@ void Parker::park(bool isAbsolute, jlong time) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Parker::unpark() {
|
void Parker::unpark() {
|
||||||
guarantee(_ParkEvent != NULL, "invariant");
|
guarantee(_ParkHandle != NULL, "invariant");
|
||||||
SetEvent(_ParkEvent);
|
SetEvent(_ParkHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Platform Monitor implementation
|
// Platform Monitor implementation
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -188,18 +188,21 @@ class PlatformEvent : public CHeapObj<mtSynchronizer> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PlatformParker : public CHeapObj<mtSynchronizer> {
|
class PlatformParker {
|
||||||
protected:
|
NONCOPYABLE(PlatformParker);
|
||||||
HANDLE _ParkEvent ;
|
|
||||||
|
|
||||||
public:
|
protected:
|
||||||
~PlatformParker () { guarantee (0, "invariant") ; }
|
HANDLE _ParkHandle;
|
||||||
PlatformParker () {
|
|
||||||
_ParkEvent = CreateEvent (NULL, true, false, NULL) ;
|
|
||||||
guarantee (_ParkEvent != NULL, "invariant") ;
|
|
||||||
}
|
|
||||||
|
|
||||||
} ;
|
public:
|
||||||
|
PlatformParker() {
|
||||||
|
_ParkHandle = CreateEvent (NULL, true, false, NULL) ;
|
||||||
|
guarantee(_ParkHandle != NULL, "invariant") ;
|
||||||
|
}
|
||||||
|
~PlatformParker() {
|
||||||
|
CloseHandle(_ParkHandle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Platform specific implementations that underpin VM Mutex/Monitor classes.
|
// Platform specific implementations that underpin VM Mutex/Monitor classes.
|
||||||
// Note that CRITICAL_SECTION supports recursive locking, while the semantics
|
// Note that CRITICAL_SECTION supports recursive locking, while the semantics
|
||||||
|
|
|
@ -1001,8 +1001,6 @@ UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute,
|
||||||
} UNSAFE_END
|
} UNSAFE_END
|
||||||
|
|
||||||
UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread)) {
|
UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread)) {
|
||||||
Parker* p = NULL;
|
|
||||||
|
|
||||||
if (jthread != NULL) {
|
if (jthread != NULL) {
|
||||||
ThreadsListHandle tlh;
|
ThreadsListHandle tlh;
|
||||||
JavaThread* thr = NULL;
|
JavaThread* thr = NULL;
|
||||||
|
@ -1012,18 +1010,13 @@ UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread))
|
||||||
// This is a valid oop.
|
// This is a valid oop.
|
||||||
if (thr != NULL) {
|
if (thr != NULL) {
|
||||||
// The JavaThread is alive.
|
// The JavaThread is alive.
|
||||||
p = thr->parker();
|
Parker* p = thr->parker();
|
||||||
|
HOTSPOT_THREAD_UNPARK((uintptr_t) p);
|
||||||
|
p->unpark();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // ThreadsListHandle is destroyed here.
|
} // ThreadsListHandle is destroyed here.
|
||||||
|
|
||||||
// 'p' points to type-stable-memory if non-NULL. If the target
|
|
||||||
// thread terminates before we get here the new user of this
|
|
||||||
// Parker will get a 'spurious' unpark - which is perfectly valid.
|
|
||||||
if (p != NULL) {
|
|
||||||
HOTSPOT_THREAD_UNPARK((uintptr_t) p);
|
|
||||||
p->unpark();
|
|
||||||
}
|
|
||||||
} UNSAFE_END
|
} UNSAFE_END
|
||||||
|
|
||||||
UNSAFE_ENTRY(jint, Unsafe_GetLoadAverage0(JNIEnv *env, jobject unsafe, jdoubleArray loadavg, jint nelem)) {
|
UNSAFE_ENTRY(jint, Unsafe_GetLoadAverage0(JNIEnv *env, jobject unsafe, jdoubleArray loadavg, jint nelem)) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -112,55 +112,3 @@ void ParkEvent::operator delete (void * a) {
|
||||||
// ParkEvents are type-stable and immortal ...
|
// ParkEvents are type-stable and immortal ...
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 6399321 As a temporary measure we copied & modified the ParkEvent::
|
|
||||||
// allocate() and release() code for use by Parkers. The Parker:: forms
|
|
||||||
// will eventually be removed as we consolidate and shift over to ParkEvents
|
|
||||||
// for both builtin synchronization and JSR166 operations.
|
|
||||||
|
|
||||||
volatile int Parker::ListLock = 0 ;
|
|
||||||
Parker * volatile Parker::FreeList = NULL ;
|
|
||||||
|
|
||||||
Parker * Parker::Allocate (JavaThread * t) {
|
|
||||||
guarantee (t != NULL, "invariant") ;
|
|
||||||
Parker * p ;
|
|
||||||
|
|
||||||
// Start by trying to recycle an existing but unassociated
|
|
||||||
// Parker from the global free list.
|
|
||||||
// 8028280: using concurrent free list without memory management can leak
|
|
||||||
// pretty badly it turns out.
|
|
||||||
Thread::SpinAcquire(&ListLock, "ParkerFreeListAllocate");
|
|
||||||
{
|
|
||||||
p = FreeList;
|
|
||||||
if (p != NULL) {
|
|
||||||
FreeList = p->FreeNext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Thread::SpinRelease(&ListLock);
|
|
||||||
|
|
||||||
if (p != NULL) {
|
|
||||||
guarantee (p->AssociatedWith == NULL, "invariant") ;
|
|
||||||
} else {
|
|
||||||
// Do this the hard way -- materialize a new Parker..
|
|
||||||
p = new Parker() ;
|
|
||||||
}
|
|
||||||
p->AssociatedWith = t ; // Associate p with t
|
|
||||||
p->FreeNext = NULL ;
|
|
||||||
return p ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Parker::Release (Parker * p) {
|
|
||||||
if (p == NULL) return ;
|
|
||||||
guarantee (p->AssociatedWith != NULL, "invariant") ;
|
|
||||||
guarantee (p->FreeNext == NULL , "invariant") ;
|
|
||||||
p->AssociatedWith = NULL ;
|
|
||||||
|
|
||||||
Thread::SpinAcquire(&ListLock, "ParkerFreeListRelease");
|
|
||||||
{
|
|
||||||
p->FreeNext = FreeList;
|
|
||||||
FreeList = p;
|
|
||||||
}
|
|
||||||
Thread::SpinRelease(&ListLock);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -27,17 +27,21 @@
|
||||||
|
|
||||||
#include "utilities/debug.hpp"
|
#include "utilities/debug.hpp"
|
||||||
#include "utilities/globalDefinitions.hpp"
|
#include "utilities/globalDefinitions.hpp"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Per-thread blocking support for JSR166. See the Java-level
|
* Per-thread blocking support for JSR166. See the Java-level
|
||||||
* Documentation for rationale. Basically, park acts like wait, unpark
|
* documentation for rationale. Basically, park acts like wait, unpark
|
||||||
* like notify.
|
* like notify.
|
||||||
*
|
*
|
||||||
* 6271289 --
|
* Parkers are inherently part of their associated JavaThread and are only
|
||||||
* To avoid errors where an os thread expires but the JavaThread still
|
* accessed when the JavaThread is guaranteed to be alive (e.g. by operating
|
||||||
* exists, Parkers are immortal (type-stable) and are recycled across
|
* on the current thread, or by having the thread protected by a
|
||||||
* new threads. This parallels the ParkEvent implementation.
|
* ThreadsListHandle.
|
||||||
* Because park-unpark allow spurious wakeups it is harmless if an
|
*
|
||||||
* unpark call unparks a new thread using the old Parker reference.
|
* Class Parker is declared in shared code and extends the platform-specific
|
||||||
|
* os::PlatformParker class, which contains the actual implementation
|
||||||
|
* mechanics (condvars/events etc). The implementation for park() and unpark()
|
||||||
|
* are also in the platform-specific os_<os>.cpp files.
|
||||||
*
|
*
|
||||||
* In the future we'll want to think about eliminating Parker and using
|
* In the future we'll want to think about eliminating Parker and using
|
||||||
* ParkEvent instead. There's considerable duplication between the two
|
* ParkEvent instead. There's considerable duplication between the two
|
||||||
|
@ -46,32 +50,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Parker : public os::PlatformParker {
|
class Parker : public os::PlatformParker {
|
||||||
private:
|
private:
|
||||||
volatile int _counter ;
|
NONCOPYABLE(Parker);
|
||||||
Parker * FreeNext ;
|
public:
|
||||||
JavaThread * AssociatedWith ; // Current association
|
Parker() : PlatformParker() {}
|
||||||
|
|
||||||
public:
|
|
||||||
Parker() : PlatformParker() {
|
|
||||||
_counter = 0 ;
|
|
||||||
FreeNext = NULL ;
|
|
||||||
AssociatedWith = NULL ;
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
~Parker() { ShouldNotReachHere(); }
|
|
||||||
public:
|
|
||||||
// For simplicity of interface with Java, all forms of park (indefinite,
|
// For simplicity of interface with Java, all forms of park (indefinite,
|
||||||
// relative, and absolute) are multiplexed into one call.
|
// relative, and absolute) are multiplexed into one call.
|
||||||
void park(bool isAbsolute, jlong time);
|
void park(bool isAbsolute, jlong time);
|
||||||
void unpark();
|
void unpark();
|
||||||
|
|
||||||
// Lifecycle operators
|
|
||||||
static Parker * Allocate (JavaThread * t) ;
|
|
||||||
static void Release (Parker * e) ;
|
|
||||||
private:
|
|
||||||
static Parker * volatile FreeList ;
|
|
||||||
static volatile int ListLock ;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -1565,7 +1565,7 @@ JavaThread::JavaThread() :
|
||||||
_should_post_on_exceptions_flag(JNI_FALSE),
|
_should_post_on_exceptions_flag(JNI_FALSE),
|
||||||
_thread_stat(new ThreadStatistics()),
|
_thread_stat(new ThreadStatistics()),
|
||||||
|
|
||||||
_parker(Parker::Allocate(this)),
|
_parker(),
|
||||||
_cached_monitor_info(nullptr),
|
_cached_monitor_info(nullptr),
|
||||||
|
|
||||||
_class_to_be_initialized(nullptr),
|
_class_to_be_initialized(nullptr),
|
||||||
|
@ -1603,6 +1603,9 @@ JavaThread::JavaThread(bool is_attaching_via_jni) : JavaThread() {
|
||||||
// interrupt support
|
// interrupt support
|
||||||
|
|
||||||
void JavaThread::interrupt() {
|
void JavaThread::interrupt() {
|
||||||
|
// All callers should have 'this' thread protected by a
|
||||||
|
// ThreadsListHandle so that it cannot terminate and deallocate
|
||||||
|
// itself.
|
||||||
debug_only(check_for_dangling_thread_pointer(this);)
|
debug_only(check_for_dangling_thread_pointer(this);)
|
||||||
|
|
||||||
// For Windows _interrupt_event
|
// For Windows _interrupt_event
|
||||||
|
@ -1700,10 +1703,6 @@ JavaThread::~JavaThread() {
|
||||||
// Ask ServiceThread to release the threadObj OopHandle
|
// Ask ServiceThread to release the threadObj OopHandle
|
||||||
ServiceThread::add_oop_handle_release(_threadObj);
|
ServiceThread::add_oop_handle_release(_threadObj);
|
||||||
|
|
||||||
// JSR166 -- return the parker to the free list
|
|
||||||
Parker::Release(_parker);
|
|
||||||
_parker = NULL;
|
|
||||||
|
|
||||||
// Return the sleep event to the free list
|
// Return the sleep event to the free list
|
||||||
ParkEvent::Release(_SleepEvent);
|
ParkEvent::Release(_SleepEvent);
|
||||||
_SleepEvent = NULL;
|
_SleepEvent = NULL;
|
||||||
|
|
|
@ -66,8 +66,6 @@ class JvmtiThreadState;
|
||||||
class JvmtiVMObjectAllocEventCollector;
|
class JvmtiVMObjectAllocEventCollector;
|
||||||
class ThreadStatistics;
|
class ThreadStatistics;
|
||||||
class ConcurrentLocksDump;
|
class ConcurrentLocksDump;
|
||||||
class ParkEvent;
|
|
||||||
class Parker;
|
|
||||||
class MonitorInfo;
|
class MonitorInfo;
|
||||||
|
|
||||||
class BufferBlob;
|
class BufferBlob;
|
||||||
|
@ -1854,9 +1852,9 @@ class JavaThread: public Thread {
|
||||||
|
|
||||||
// JSR166 per-thread parker
|
// JSR166 per-thread parker
|
||||||
private:
|
private:
|
||||||
Parker* _parker;
|
Parker _parker;
|
||||||
public:
|
public:
|
||||||
Parker* parker() { return _parker; }
|
Parker* parker() { return &_parker; }
|
||||||
|
|
||||||
// Biased locking support
|
// Biased locking support
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue