8223056: Remove Type-Stable-Memory support for Parkers

Reviewed-by: coleenp, rehn
This commit is contained in:
David Holmes 2021-01-21 02:41:52 +00:00
parent 35c9da7031
commit 77a4302309
9 changed files with 65 additions and 131 deletions

View file

@ -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

View file

@ -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?).

View file

@ -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

View file

@ -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 {
NONCOPYABLE(PlatformParker);
protected: protected:
HANDLE _ParkEvent ; HANDLE _ParkHandle;
public: public:
~PlatformParker () { guarantee (0, "invariant") ; } PlatformParker() {
PlatformParker () { _ParkHandle = CreateEvent (NULL, true, false, NULL) ;
_ParkEvent = CreateEvent (NULL, true, false, NULL) ; guarantee(_ParkHandle != NULL, "invariant") ;
guarantee (_ParkEvent != 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

View file

@ -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)) {

View file

@ -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);
}

View file

@ -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 ;
}; };
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////

View file

@ -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;

View file

@ -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: