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

@ -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.
*
* This code is free software; you can redistribute it and/or modify it
@ -1533,15 +1533,22 @@ void os::PlatformEvent::unpark() {
// JSR166 support
os::PlatformParker::PlatformParker() {
int status;
status = pthread_cond_init(&_cond[REL_INDEX], _condAttr);
os::PlatformParker::PlatformParker() : _counter(0), _cur_index(-1) {
int status = pthread_cond_init(&_cond[REL_INDEX], _condAttr);
assert_status(status == 0, status, "cond_init rel");
status = pthread_cond_init(&_cond[ABS_INDEX], NULL);
assert_status(status == 0, status, "cond_init abs");
status = pthread_mutex_init(_mutex, _mutexAttr);
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

@ -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.
*
* 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
// level of encapsulation - so combining the two remains a future project.
class PlatformParker : public CHeapObj<mtSynchronizer> {
class PlatformParker {
NONCOPYABLE(PlatformParker);
protected:
enum {
REL_INDEX = 0,
ABS_INDEX = 1
};
volatile int _counter;
int _cur_index; // which cond is in use: -1, 0, 1
pthread_mutex_t _mutex[1];
pthread_cond_t _cond[2]; // one for relative times and one for absolute
public: // TODO-FIXME: make dtor private
~PlatformParker() { guarantee(false, "invariant"); }
public:
PlatformParker();
~PlatformParker();
};
// 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
// operations on Win32 Events turn out to have the right semantics to
// use them directly. We opportunistically resuse the event inherited
// from Monitor.
// use them directly.
void Parker::park(bool isAbsolute, jlong time) {
guarantee(_ParkEvent != NULL, "invariant");
guarantee(_ParkHandle != NULL, "invariant");
// First, demultiplex/decode time arguments
if (time < 0) { // don't wait
return;
@ -5457,16 +5456,16 @@ void Parker::park(bool isAbsolute, jlong time) {
// Don't wait if interrupted or already triggered
if (thread->is_interrupted(false) ||
WaitForSingleObject(_ParkEvent, 0) == WAIT_OBJECT_0) {
ResetEvent(_ParkEvent);
WaitForSingleObject(_ParkHandle, 0) == WAIT_OBJECT_0) {
ResetEvent(_ParkHandle);
return;
} else {
ThreadBlockInVM tbivm(thread);
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
thread->set_suspend_equivalent();
WaitForSingleObject(_ParkEvent, time);
ResetEvent(_ParkEvent);
WaitForSingleObject(_ParkHandle, time);
ResetEvent(_ParkHandle);
// If externally suspended while waiting, re-suspend
if (thread->handle_special_suspend_equivalent_condition()) {
@ -5476,8 +5475,8 @@ void Parker::park(bool isAbsolute, jlong time) {
}
void Parker::unpark() {
guarantee(_ParkEvent != NULL, "invariant");
SetEvent(_ParkEvent);
guarantee(_ParkHandle != NULL, "invariant");
SetEvent(_ParkHandle);
}
// 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.
*
* 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> {
protected:
HANDLE _ParkEvent ;
class PlatformParker {
NONCOPYABLE(PlatformParker);
public:
~PlatformParker () { guarantee (0, "invariant") ; }
PlatformParker () {
_ParkEvent = CreateEvent (NULL, true, false, NULL) ;
guarantee (_ParkEvent != NULL, "invariant") ;
}
protected:
HANDLE _ParkHandle;
} ;
public:
PlatformParker() {
_ParkHandle = CreateEvent (NULL, true, false, NULL) ;
guarantee(_ParkHandle != NULL, "invariant") ;
}
~PlatformParker() {
CloseHandle(_ParkHandle);
}
};
// Platform specific implementations that underpin VM Mutex/Monitor classes.
// 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_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread)) {
Parker* p = NULL;
if (jthread != NULL) {
ThreadsListHandle tlh;
JavaThread* thr = NULL;
@ -1012,18 +1010,13 @@ UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread))
// This is a valid oop.
if (thr != NULL) {
// The JavaThread is alive.
p = thr->parker();
Parker* p = thr->parker();
HOTSPOT_THREAD_UNPARK((uintptr_t) p);
p->unpark();
}
}
} // 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_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.
*
* 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 ...
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.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,17 +27,21 @@
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
/*
* 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.
*
* 6271289 --
* To avoid errors where an os thread expires but the JavaThread still
* exists, Parkers are immortal (type-stable) and are recycled across
* new threads. This parallels the ParkEvent implementation.
* Because park-unpark allow spurious wakeups it is harmless if an
* unpark call unparks a new thread using the old Parker reference.
* Parkers are inherently part of their associated JavaThread and are only
* accessed when the JavaThread is guaranteed to be alive (e.g. by operating
* on the current thread, or by having the thread protected by a
* ThreadsListHandle.
*
* 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
* ParkEvent instead. There's considerable duplication between the two
@ -46,32 +50,15 @@
*/
class Parker : public os::PlatformParker {
private:
volatile int _counter ;
Parker * FreeNext ;
JavaThread * AssociatedWith ; // Current association
private:
NONCOPYABLE(Parker);
public:
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,
// relative, and absolute) are multiplexed into one call.
void park(bool isAbsolute, jlong time);
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),
_thread_stat(new ThreadStatistics()),
_parker(Parker::Allocate(this)),
_parker(),
_cached_monitor_info(nullptr),
_class_to_be_initialized(nullptr),
@ -1603,6 +1603,9 @@ JavaThread::JavaThread(bool is_attaching_via_jni) : JavaThread() {
// interrupt support
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);)
// For Windows _interrupt_event
@ -1700,10 +1703,6 @@ JavaThread::~JavaThread() {
// Ask ServiceThread to release the threadObj OopHandle
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
ParkEvent::Release(_SleepEvent);
_SleepEvent = NULL;

@ -66,8 +66,6 @@ class JvmtiThreadState;
class JvmtiVMObjectAllocEventCollector;
class ThreadStatistics;
class ConcurrentLocksDump;
class ParkEvent;
class Parker;
class MonitorInfo;
class BufferBlob;
@ -1854,9 +1852,9 @@ class JavaThread: public Thread {
// JSR166 per-thread parker
private:
Parker* _parker;
Parker _parker;
public:
Parker* parker() { return _parker; }
Parker* parker() { return &_parker; }
// Biased locking support
private: