8297168: Provide a bulk OopHandle release mechanism with the ServiceThread
Reviewed-by: rehn, coleenp
This commit is contained in:
parent
4a544bb0fc
commit
a6c418eaf8
@ -599,11 +599,8 @@ JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) : JavaThread
|
|||||||
|
|
||||||
JavaThread::~JavaThread() {
|
JavaThread::~JavaThread() {
|
||||||
|
|
||||||
// Ask ServiceThread to release the OopHandles
|
// Enqueue OopHandles for release by the service thread.
|
||||||
ServiceThread::add_oop_handle_release(_threadObj);
|
add_oop_handles_for_release();
|
||||||
ServiceThread::add_oop_handle_release(_vthread);
|
|
||||||
ServiceThread::add_oop_handle_release(_jvmti_vthread);
|
|
||||||
ServiceThread::add_oop_handle_release(_extentLocalCache);
|
|
||||||
|
|
||||||
// Return the sleep event to the free list
|
// Return the sleep event to the free list
|
||||||
ParkEvent::Release(_SleepEvent);
|
ParkEvent::Release(_SleepEvent);
|
||||||
@ -2073,3 +2070,57 @@ void JavaThread::vm_exit_on_osthread_failure(JavaThread* thread) {
|
|||||||
os::native_thread_creation_failed_msg());
|
os::native_thread_creation_failed_msg());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deferred OopHandle release support.
|
||||||
|
|
||||||
|
class OopHandleList : public CHeapObj<mtInternal> {
|
||||||
|
static const int _count = 4;
|
||||||
|
OopHandle _handles[_count];
|
||||||
|
OopHandleList* _next;
|
||||||
|
int _index;
|
||||||
|
public:
|
||||||
|
OopHandleList(OopHandleList* next) : _next(next), _index(0) {}
|
||||||
|
void add(OopHandle h) {
|
||||||
|
assert(_index < _count, "too many additions");
|
||||||
|
_handles[_index++] = h;
|
||||||
|
}
|
||||||
|
~OopHandleList() {
|
||||||
|
assert(_index == _count, "usage error");
|
||||||
|
for (int i = 0; i < _index; i++) {
|
||||||
|
_handles[i].release(JavaThread::thread_oop_storage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OopHandleList* next() const { return _next; }
|
||||||
|
};
|
||||||
|
|
||||||
|
OopHandleList* JavaThread::_oop_handle_list = nullptr;
|
||||||
|
|
||||||
|
// Called by the ServiceThread to do the work of releasing
|
||||||
|
// the OopHandles.
|
||||||
|
void JavaThread::release_oop_handles() {
|
||||||
|
OopHandleList* list;
|
||||||
|
{
|
||||||
|
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||||||
|
list = _oop_handle_list;
|
||||||
|
_oop_handle_list = nullptr;
|
||||||
|
}
|
||||||
|
assert(!SafepointSynchronize::is_at_safepoint(), "cannot be called at a safepoint");
|
||||||
|
|
||||||
|
while (list != nullptr) {
|
||||||
|
OopHandleList* l = list;
|
||||||
|
list = l->next();
|
||||||
|
delete l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add our OopHandles for later release.
|
||||||
|
void JavaThread::add_oop_handles_for_release() {
|
||||||
|
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||||||
|
OopHandleList* new_head = new OopHandleList(_oop_handle_list);
|
||||||
|
new_head->add(_threadObj);
|
||||||
|
new_head->add(_vthread);
|
||||||
|
new_head->add(_jvmti_vthread);
|
||||||
|
new_head->add(_extentLocalCache);
|
||||||
|
_oop_handle_list = new_head;
|
||||||
|
Service_lock->notify_all();
|
||||||
|
}
|
||||||
|
@ -59,6 +59,7 @@ class JvmtiSampledObjectAllocEventCollector;
|
|||||||
class JvmtiThreadState;
|
class JvmtiThreadState;
|
||||||
|
|
||||||
class Metadata;
|
class Metadata;
|
||||||
|
class OopHandleList;
|
||||||
class OopStorage;
|
class OopStorage;
|
||||||
class OSThread;
|
class OSThread;
|
||||||
|
|
||||||
@ -81,9 +82,14 @@ class JavaThread: public Thread {
|
|||||||
friend class HandshakeState;
|
friend class HandshakeState;
|
||||||
friend class Continuation;
|
friend class Continuation;
|
||||||
friend class Threads;
|
friend class Threads;
|
||||||
|
friend class ServiceThread; // for deferred OopHandle release access
|
||||||
private:
|
private:
|
||||||
bool _in_asgct; // Is set when this JavaThread is handling ASGCT call
|
bool _in_asgct; // Is set when this JavaThread is handling ASGCT call
|
||||||
bool _on_thread_list; // Is set when this JavaThread is added to the Threads list
|
bool _on_thread_list; // Is set when this JavaThread is added to the Threads list
|
||||||
|
|
||||||
|
// All references to Java objects managed via OopHandles. These
|
||||||
|
// have to be released by the ServiceThread after the JavaThread has
|
||||||
|
// terminated - see add_oop_handles_for_release().
|
||||||
OopHandle _threadObj; // The Java level thread object
|
OopHandle _threadObj; // The Java level thread object
|
||||||
OopHandle _vthread; // the value returned by Thread.currentThread(): the virtual thread, if mounted, otherwise _threadObj
|
OopHandle _vthread; // the value returned by Thread.currentThread(): the virtual thread, if mounted, otherwise _threadObj
|
||||||
OopHandle _jvmti_vthread;
|
OopHandle _jvmti_vthread;
|
||||||
@ -1168,6 +1174,20 @@ public:
|
|||||||
// AsyncGetCallTrace support
|
// AsyncGetCallTrace support
|
||||||
inline bool in_asgct(void) {return _in_asgct;}
|
inline bool in_asgct(void) {return _in_asgct;}
|
||||||
inline void set_in_asgct(bool value) {_in_asgct = value;}
|
inline void set_in_asgct(bool value) {_in_asgct = value;}
|
||||||
|
|
||||||
|
// Deferred OopHandle release support
|
||||||
|
private:
|
||||||
|
// List of OopHandles to be released - guarded by the Service_lock.
|
||||||
|
static OopHandleList* _oop_handle_list;
|
||||||
|
// Add our OopHandles to the list for the service thread to release.
|
||||||
|
void add_oop_handles_for_release();
|
||||||
|
// Called by the ServiceThread to release the OopHandles.
|
||||||
|
static void release_oop_handles();
|
||||||
|
// Called by the ServiceThread to poll if there are any OopHandles to release.
|
||||||
|
// Called when holding the Service_lock.
|
||||||
|
static bool has_oop_handles_to_release() {
|
||||||
|
return _oop_handle_list != nullptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline JavaThread* JavaThread::current_or_null() {
|
inline JavaThread* JavaThread::current_or_null() {
|
||||||
|
@ -59,36 +59,6 @@ JvmtiDeferredEvent* ServiceThread::_jvmti_event = NULL;
|
|||||||
// to add this field to the per-JavaThread event queue. TODO: fix this sometime later
|
// to add this field to the per-JavaThread event queue. TODO: fix this sometime later
|
||||||
JvmtiDeferredEventQueue ServiceThread::_jvmti_service_queue;
|
JvmtiDeferredEventQueue ServiceThread::_jvmti_service_queue;
|
||||||
|
|
||||||
// Defer releasing JavaThread OopHandle to the ServiceThread
|
|
||||||
class OopHandleList : public CHeapObj<mtInternal> {
|
|
||||||
OopHandle _handle;
|
|
||||||
OopHandleList* _next;
|
|
||||||
public:
|
|
||||||
OopHandleList(OopHandle h, OopHandleList* next) : _handle(h), _next(next) {}
|
|
||||||
~OopHandleList() {
|
|
||||||
_handle.release(JavaThread::thread_oop_storage());
|
|
||||||
}
|
|
||||||
OopHandleList* next() const { return _next; }
|
|
||||||
};
|
|
||||||
|
|
||||||
static OopHandleList* _oop_handle_list = NULL;
|
|
||||||
|
|
||||||
static void release_oop_handles() {
|
|
||||||
OopHandleList* list;
|
|
||||||
{
|
|
||||||
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
|
||||||
list = _oop_handle_list;
|
|
||||||
_oop_handle_list = NULL;
|
|
||||||
}
|
|
||||||
assert(!SafepointSynchronize::is_at_safepoint(), "cannot be called at a safepoint");
|
|
||||||
|
|
||||||
while (list != NULL) {
|
|
||||||
OopHandleList* l = list;
|
|
||||||
list = l->next();
|
|
||||||
delete l;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceThread::initialize() {
|
void ServiceThread::initialize() {
|
||||||
EXCEPTION_MARK;
|
EXCEPTION_MARK;
|
||||||
|
|
||||||
@ -152,7 +122,7 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
|
|||||||
(thread_id_table_work = ThreadIdTable::has_work()) |
|
(thread_id_table_work = ThreadIdTable::has_work()) |
|
||||||
(protection_domain_table_work = ProtectionDomainCacheTable::has_work()) |
|
(protection_domain_table_work = ProtectionDomainCacheTable::has_work()) |
|
||||||
(oopstorage_work = OopStorage::has_cleanup_work_and_reset()) |
|
(oopstorage_work = OopStorage::has_cleanup_work_and_reset()) |
|
||||||
(oop_handles_to_release = (_oop_handle_list != NULL)) |
|
(oop_handles_to_release = JavaThread::has_oop_handles_to_release()) |
|
||||||
(cldg_cleanup_work = ClassLoaderDataGraph::should_clean_metaspaces_and_reset()) |
|
(cldg_cleanup_work = ClassLoaderDataGraph::should_clean_metaspaces_and_reset()) |
|
||||||
(jvmti_tagmap_work = JvmtiTagMap::has_object_free_events_and_reset())
|
(jvmti_tagmap_work = JvmtiTagMap::has_object_free_events_and_reset())
|
||||||
) == 0) {
|
) == 0) {
|
||||||
@ -215,7 +185,7 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (oop_handles_to_release) {
|
if (oop_handles_to_release) {
|
||||||
release_oop_handles();
|
JavaThread::release_oop_handles();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cldg_cleanup_work) {
|
if (cldg_cleanup_work) {
|
||||||
@ -261,10 +231,3 @@ void ServiceThread::nmethods_do(CodeBlobClosure* cf) {
|
|||||||
_jvmti_service_queue.nmethods_do(cf);
|
_jvmti_service_queue.nmethods_do(cf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceThread::add_oop_handle_release(OopHandle handle) {
|
|
||||||
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
|
||||||
OopHandleList* new_head = new OopHandleList(handle, _oop_handle_list);
|
|
||||||
_oop_handle_list = new_head;
|
|
||||||
Service_lock->notify_all();
|
|
||||||
}
|
|
||||||
|
@ -52,7 +52,6 @@ class ServiceThread : public JavaThread {
|
|||||||
|
|
||||||
// Add event to the service thread event queue.
|
// Add event to the service thread event queue.
|
||||||
static void enqueue_deferred_event(JvmtiDeferredEvent* event);
|
static void enqueue_deferred_event(JvmtiDeferredEvent* event);
|
||||||
static void add_oop_handle_release(OopHandle handle);
|
|
||||||
|
|
||||||
// GC support
|
// GC support
|
||||||
void oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf);
|
void oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf);
|
||||||
|
Loading…
Reference in New Issue
Block a user