8151601: Cleanup locking of the Reference pending list

Reviewed-by: brutisso, stefank
This commit is contained in:
Per Lidén 2016-03-17 08:07:53 +01:00
parent 9d3140761b
commit da5ca5c5d5
29 changed files with 401 additions and 353 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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
@ -130,7 +130,7 @@ public class Threads {
virtualConstructor.addMapping("CodeCacheSweeperThread", CodeCacheSweeperThread.class);
}
// for now, use JavaThread itself. fix it later with appropriate class if needed
virtualConstructor.addMapping("SurrogateLockerThread", JavaThread.class);
virtualConstructor.addMapping("ReferencePendingListLockerThread", JavaThread.class);
virtualConstructor.addMapping("JvmtiAgentThread", JvmtiAgentThread.class);
virtualConstructor.addMapping("ServiceThread", ServiceThread.class);
}
@ -172,7 +172,7 @@ public class Threads {
return thread;
} catch (Exception e) {
throw new RuntimeException("Unable to deduce type of thread from address " + threadAddr +
" (expected type JavaThread, CompilerThread, ServiceThread, JvmtiAgentThread, SurrogateLockerThread, or CodeCacheSweeperThread)", e);
" (expected type JavaThread, CompilerThread, ServiceThread, JvmtiAgentThread, ReferencePendingListLockerThread, or CodeCacheSweeperThread)", e);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2016, 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
@ -837,7 +837,7 @@ vmType2Class["InterpreterCodelet"] = sapkg.interpreter.InterpreterCodelet;
vmType2Class["JavaThread"] = sapkg.runtime.JavaThread;
vmType2Class["CompilerThread"] = sapkg.runtime.CompilerThread;
vmType2Class["CodeCacheSweeperThread"] = sapkg.runtime.CodeCacheSweeperThread;
vmType2Class["SurrogateLockerThread"] = sapkg.runtime.JavaThread;
vmType2Class["ReferencePendingListLockerThread"] = sapkg.runtime.JavaThread;
vmType2Class["DebuggerThread"] = sapkg.runtime.DebuggerThread;
// gc

View File

@ -1,4 +1,5 @@
/* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
/*
* Copyright (c) 2013, 2016, 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
@ -28,6 +29,7 @@
#include "ci/ciKlass.hpp"
#include "ci/ciUtilities.hpp"
#include "compiler/compileBroker.hpp"
#include "gc/shared/referencePendingListLocker.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
@ -574,7 +576,7 @@ class CompileReplay : public StackObj {
Method* method = parse_method(CHECK);
if (had_error()) return;
/* just copied from Method, to build interpret data*/
if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) {
if (ReferencePendingListLocker::is_locked_by_self()) {
return;
}
// To be properly initialized, some profiling in the MDO needs the

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2016, 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
@ -32,6 +32,7 @@
#include "compiler/compileLog.hpp"
#include "compiler/compilerOracle.hpp"
#include "compiler/directivesParser.hpp"
#include "gc/shared/referencePendingListLocker.hpp"
#include "interpreter/linkResolver.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/methodData.hpp"
@ -904,7 +905,7 @@ void CompileBroker::compile_method_base(const methodHandle& method,
// the pending list lock or a 3-way deadlock may occur
// between the reference handler thread, a GC (instigated
// by a compiler thread), and compiled method registration.
if (InstanceRefKlass::owns_pending_list_lock(JavaThread::current())) {
if (ReferencePendingListLocker::is_locked_by_self()) {
return;
}
@ -1309,7 +1310,7 @@ uint CompileBroker::assign_compile_id_unlocked(Thread* thread, const methodHandl
* has been fulfilled?
*/
bool CompileBroker::is_compile_blocking() {
assert(!InstanceRefKlass::owns_pending_list_lock(JavaThread::current()), "possible deadlock");
assert(!ReferencePendingListLocker::is_locked_by_self(), "possible deadlock");
return !BackgroundCompilation;
}

View File

@ -28,7 +28,7 @@
#include "gc/cms/concurrentMarkSweepThread.hpp"
#include "gc/shared/gcId.hpp"
#include "gc/shared/genCollectedHeap.hpp"
#include "oops/instanceRefKlass.hpp"
#include "gc/shared/referencePendingListLocker.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/interfaceSupport.hpp"
@ -46,11 +46,6 @@ int ConcurrentMarkSweepThread::_CMS_flag = CMS_nil;
volatile jint ConcurrentMarkSweepThread::_pending_yields = 0;
SurrogateLockerThread* ConcurrentMarkSweepThread::_slt = NULL;
SurrogateLockerThread::SLT_msg_type
ConcurrentMarkSweepThread::_sltBuffer = SurrogateLockerThread::empty;
Monitor* ConcurrentMarkSweepThread::_sltMonitor = NULL;
ConcurrentMarkSweepThread::ConcurrentMarkSweepThread(CMSCollector* collector)
: ConcurrentGCThread() {
assert(UseConcMarkSweepGC, "UseConcMarkSweepGC should be set");
@ -73,8 +68,6 @@ ConcurrentMarkSweepThread::ConcurrentMarkSweepThread(CMSCollector* collector)
// That won't happen on Solaris for various reasons,
// but may well happen on non-Solaris platforms.
create_and_start(UseCriticalCMSThreadPriority ? CriticalPriority : NearMaxPriority);
_sltMonitor = SLT_lock;
}
void ConcurrentMarkSweepThread::run_service() {
@ -94,7 +87,7 @@ void ConcurrentMarkSweepThread::run_service() {
// We cannot start the SLT thread ourselves since we need
// to be a JavaThread to do so.
CMSLoopCountWarn loopY("CMS::run", "waiting for SLT installation", 2);
while (_slt == NULL && !should_terminate()) {
while (!ReferencePendingListLocker::is_initialized() && !should_terminate()) {
CGC_lock->wait(true, 200);
loopY.tick();
}
@ -337,15 +330,3 @@ void ConcurrentMarkSweepThread::sleepBeforeNextCycle() {
// and wait some more
}
}
// Note: this method, although exported by the ConcurrentMarkSweepThread,
// which is a non-JavaThread, can only be called by a JavaThread.
// Currently this is done at vm creation time (post-vm-init) by the
// main/Primordial (Java)Thread.
// XXX Consider changing this in the future to allow the CMS thread
// itself to create this thread?
void ConcurrentMarkSweepThread::makeSurrogateLockerThread(TRAPS) {
assert(UseConcMarkSweepGC, "SLT thread needed only for CMS GC");
assert(_slt == NULL, "SLT already created");
_slt = SurrogateLockerThread::make(THREAD);
}

View File

@ -39,11 +39,8 @@ class ConcurrentMarkSweepThread: public ConcurrentGCThread {
friend class CMSCollector;
private:
static ConcurrentMarkSweepThread* _cmst;
static CMSCollector* _collector;
static SurrogateLockerThread* _slt;
static SurrogateLockerThread::SLT_msg_type _sltBuffer;
static Monitor* _sltMonitor;
static ConcurrentMarkSweepThread* _cmst;
static CMSCollector* _collector;
enum CMS_flag_type {
CMS_nil = NoBits,
@ -75,9 +72,6 @@ class ConcurrentMarkSweepThread: public ConcurrentGCThread {
// Constructor
ConcurrentMarkSweepThread(CMSCollector* collector);
static void makeSurrogateLockerThread(TRAPS);
static SurrogateLockerThread* slt() { return _slt; }
static void threads_do(ThreadClosure* tc);
// Printing

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2016, 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
@ -38,21 +38,11 @@
// Methods in abstract class VM_CMS_Operation
//////////////////////////////////////////////////////////
void VM_CMS_Operation::acquire_pending_list_lock() {
// The caller may block while communicating
// with the SLT thread in order to acquire/release the PLL.
SurrogateLockerThread* slt = ConcurrentMarkSweepThread::slt();
if (slt != NULL) {
slt->manipulatePLL(SurrogateLockerThread::acquirePLL);
} else {
SurrogateLockerThread::report_missing_slt();
}
_pending_list_locker.lock();
}
void VM_CMS_Operation::release_and_notify_pending_list_lock() {
// The caller may block while communicating
// with the SLT thread in order to acquire/release the PLL.
ConcurrentMarkSweepThread::slt()->
manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL);
_pending_list_locker.unlock();
}
void VM_CMS_Operation::verify_before_gc() {
@ -95,7 +85,7 @@ bool VM_CMS_Operation::doit_prologue() {
assert(!ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
"Possible deadlock");
if (needs_pll()) {
if (needs_pending_list_lock()) {
acquire_pending_list_lock();
}
// Get the Heap_lock after the pending_list_lock.
@ -103,7 +93,7 @@ bool VM_CMS_Operation::doit_prologue() {
if (lost_race()) {
assert(_prologue_succeeded == false, "Initialized in c'tor");
Heap_lock->unlock();
if (needs_pll()) {
if (needs_pending_list_lock()) {
release_and_notify_pending_list_lock();
}
} else {
@ -120,7 +110,7 @@ void VM_CMS_Operation::doit_epilogue() {
// Release the Heap_lock first.
Heap_lock->unlock();
if (needs_pll()) {
if (needs_pending_list_lock()) {
release_and_notify_pending_list_lock();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2016, 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
@ -28,6 +28,7 @@
#include "gc/cms/concurrentMarkSweepGeneration.hpp"
#include "gc/shared/gcCause.hpp"
#include "gc/shared/gcId.hpp"
#include "gc/shared/referencePendingListLocker.hpp"
#include "gc/shared/vmGCOperations.hpp"
#include "runtime/vm_operations.hpp"
@ -51,6 +52,9 @@
class CMSCollector;
class VM_CMS_Operation: public VM_Operation {
private:
ReferencePendingListLocker _pending_list_locker;
protected:
CMSCollector* _collector; // associated collector
bool _prologue_succeeded; // whether doit_prologue succeeded
@ -73,7 +77,7 @@ class VM_CMS_Operation: public VM_Operation {
virtual const CMSCollector::CollectorState legal_state() const = 0;
// Whether the pending list lock needs to be held
virtual const bool needs_pll() const = 0;
virtual const bool needs_pending_list_lock() const = 0;
// Execute operations in the context of the caller,
// prior to execution of the vm operation itself.
@ -105,7 +109,7 @@ class VM_CMS_Initial_Mark: public VM_CMS_Operation {
return CMSCollector::InitialMarking;
}
virtual const bool needs_pll() const {
virtual const bool needs_pending_list_lock() const {
return false;
}
};
@ -122,7 +126,7 @@ class VM_CMS_Final_Remark: public VM_CMS_Operation {
return CMSCollector::FinalMarking;
}
virtual const bool needs_pll() const {
virtual const bool needs_pending_list_lock() const {
return true;
}
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2016, 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
@ -51,14 +51,12 @@
declare_type(ConcurrentMarkSweepGeneration,CardGeneration) \
declare_type(CompactibleFreeListSpace, CompactibleSpace) \
declare_type(ConcurrentMarkSweepThread, NamedThread) \
declare_type(SurrogateLockerThread, JavaThread) \
declare_toplevel_type(CMSCollector) \
declare_toplevel_type(CMSBitMap) \
declare_toplevel_type(FreeChunk) \
declare_toplevel_type(Metablock) \
declare_toplevel_type(ConcurrentMarkSweepThread*) \
declare_toplevel_type(ConcurrentMarkSweepGeneration*) \
declare_toplevel_type(SurrogateLockerThread*) \
declare_toplevel_type(CompactibleFreeListSpace*) \
declare_toplevel_type(CMSCollector*) \
declare_toplevel_type(AFLBinaryTreeDictionary) \

View File

@ -41,9 +41,6 @@
// The CM thread is created when the G1 garbage collector is used
SurrogateLockerThread*
ConcurrentMarkThread::_slt = NULL;
ConcurrentMarkThread::ConcurrentMarkThread(G1ConcurrentMark* cm) :
ConcurrentGCThread(),
_cm(cm),
@ -305,16 +302,3 @@ void ConcurrentMarkThread::sleepBeforeNextCycle() {
set_in_progress();
}
}
// Note: As is the case with CMS - this method, although exported
// by the ConcurrentMarkThread, which is a non-JavaThread, can only
// be called by a JavaThread. Currently this is done at vm creation
// time (post-vm-init) by the main/Primordial (Java)Thread.
// XXX Consider changing this in the future to allow the CM thread
// itself to create this thread?
void ConcurrentMarkThread::makeSurrogateLockerThread(TRAPS) {
assert(UseG1GC, "SLT thread needed only for concurrent GC");
assert(THREAD->is_Java_thread(), "must be a Java thread");
assert(_slt == NULL, "SLT already created");
_slt = SurrogateLockerThread::make(THREAD);
}

View File

@ -56,15 +56,10 @@ class ConcurrentMarkThread: public ConcurrentGCThread {
void run_service();
void stop_service();
static SurrogateLockerThread* _slt;
public:
// Constructor
ConcurrentMarkThread(G1ConcurrentMark* cm);
static void makeSurrogateLockerThread(TRAPS);
static SurrogateLockerThread* slt() { return _slt; }
// Total virtual time so far for this thread and concurrent marking tasks.
double vtime_accum();
// Marking virtual time so far this thread and concurrent marking tasks.

View File

@ -1292,6 +1292,12 @@ public:
return true;
}
// The reference pending list lock is acquired from from the
// ConcurrentMarkThread.
virtual bool needs_reference_pending_list_locker_thread() const {
return true;
}
inline bool is_in_young(const oop obj);
virtual bool is_scavengable(const void* addr);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2016, 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
@ -205,23 +205,11 @@ void VM_G1IncCollectionPause::doit_epilogue() {
}
void VM_CGC_Operation::acquire_pending_list_lock() {
assert(_needs_pll, "don't call this otherwise");
// The caller may block while communicating
// with the SLT thread in order to acquire/release the PLL.
SurrogateLockerThread* slt = ConcurrentMarkThread::slt();
if (slt != NULL) {
slt->manipulatePLL(SurrogateLockerThread::acquirePLL);
} else {
SurrogateLockerThread::report_missing_slt();
}
_pending_list_locker.lock();
}
void VM_CGC_Operation::release_and_notify_pending_list_lock() {
assert(_needs_pll, "don't call this otherwise");
// The caller may block while communicating
// with the SLT thread in order to acquire/release the PLL.
ConcurrentMarkThread::slt()->
manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL);
_pending_list_locker.unlock();
}
void VM_CGC_Operation::doit() {
@ -236,10 +224,9 @@ void VM_CGC_Operation::doit() {
bool VM_CGC_Operation::doit_prologue() {
// Note the relative order of the locks must match that in
// VM_GC_Operation::doit_prologue() or deadlocks can occur
if (_needs_pll) {
if (_needs_pending_list_lock) {
acquire_pending_list_lock();
}
Heap_lock->lock();
return true;
}
@ -248,7 +235,7 @@ void VM_CGC_Operation::doit_epilogue() {
// Note the relative order of the unlocks must match that in
// VM_GC_Operation::doit_epilogue()
Heap_lock->unlock();
if (_needs_pll) {
if (_needs_pending_list_lock) {
release_and_notify_pending_list_lock();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2016, 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,6 +27,7 @@
#include "gc/g1/g1AllocationContext.hpp"
#include "gc/shared/gcId.hpp"
#include "gc/shared/referencePendingListLocker.hpp"
#include "gc/shared/vmGCOperations.hpp"
// VM_operations for the G1 collector.
@ -102,10 +103,11 @@ public:
// Concurrent GC stop-the-world operations such as remark and cleanup;
// consider sharing these with CMS's counterparts.
class VM_CGC_Operation: public VM_Operation {
VoidClosure* _cl;
const char* _printGCMessage;
bool _needs_pll;
uint _gc_id;
VoidClosure* _cl;
const char* _printGCMessage;
bool _needs_pending_list_lock;
ReferencePendingListLocker _pending_list_locker;
uint _gc_id;
protected:
// java.lang.ref.Reference support
@ -113,8 +115,8 @@ protected:
void release_and_notify_pending_list_lock();
public:
VM_CGC_Operation(VoidClosure* cl, const char *printGCMsg, bool needs_pll)
: _cl(cl), _printGCMessage(printGCMsg), _needs_pll(needs_pll), _gc_id(GCId::current()) { }
VM_CGC_Operation(VoidClosure* cl, const char *printGCMsg, bool needs_pending_list_lock)
: _cl(cl), _printGCMessage(printGCMsg), _needs_pending_list_lock(needs_pending_list_lock), _gc_id(GCId::current()) {}
virtual VMOp_Type type() const { return VMOp_CGC_Operation; }
virtual void doit();
virtual bool doit_prologue();

View File

@ -438,6 +438,12 @@ class CollectedHeap : public CHeapObj<mtInternal> {
// remembered set.
virtual void flush_deferred_store_barrier(JavaThread* thread);
// Should return true if the reference pending list lock is
// acquired from non-Java threads, such as a concurrent GC thread.
virtual bool needs_reference_pending_list_locker_thread() const {
return false;
}
// Perform a collection of the heap; intended for use in implementing
// "System.gc". This probably implies as full a collection as the
// "CollectedHeap" supports.

View File

@ -102,131 +102,3 @@ void ConcurrentGCThread::stop() {
}
}
}
static void _sltLoop(JavaThread* thread, TRAPS) {
SurrogateLockerThread* slt = (SurrogateLockerThread*)thread;
slt->loop();
}
SurrogateLockerThread::SurrogateLockerThread() :
JavaThread(&_sltLoop),
_monitor(Mutex::nonleaf, "SLTMonitor", false,
Monitor::_safepoint_check_sometimes),
_buffer(empty)
{}
SurrogateLockerThread* SurrogateLockerThread::make(TRAPS) {
Klass* k =
SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(),
true, CHECK_NULL);
instanceKlassHandle klass (THREAD, k);
instanceHandle thread_oop = klass->allocate_instance_handle(CHECK_NULL);
const char thread_name[] = "Surrogate Locker Thread (Concurrent GC)";
Handle string = java_lang_String::create_from_str(thread_name, CHECK_NULL);
// Initialize thread_oop to put it into the system threadGroup
Handle thread_group (THREAD, Universe::system_thread_group());
JavaValue result(T_VOID);
JavaCalls::call_special(&result, thread_oop,
klass,
vmSymbols::object_initializer_name(),
vmSymbols::threadgroup_string_void_signature(),
thread_group,
string,
CHECK_NULL);
SurrogateLockerThread* res;
{
MutexLocker mu(Threads_lock);
res = new SurrogateLockerThread();
// At this point it may be possible that no osthread was created for the
// JavaThread due to lack of memory. We would have to throw an exception
// in that case. However, since this must work and we do not allow
// exceptions anyway, check and abort if this fails.
if (res == NULL || res->osthread() == NULL) {
vm_exit_during_initialization("java.lang.OutOfMemoryError",
os::native_thread_creation_failed_msg());
}
java_lang_Thread::set_thread(thread_oop(), res);
java_lang_Thread::set_priority(thread_oop(), NearMaxPriority);
java_lang_Thread::set_daemon(thread_oop());
res->set_threadObj(thread_oop());
Threads::add(res);
Thread::start(res);
}
os::naked_yield(); // This seems to help with initial start-up of SLT
return res;
}
void SurrogateLockerThread::report_missing_slt() {
vm_exit_during_initialization(
"GC before GC support fully initialized: "
"SLT is needed but has not yet been created.");
ShouldNotReachHere();
}
void SurrogateLockerThread::manipulatePLL(SLT_msg_type msg) {
MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag);
assert(_buffer == empty, "Should be empty");
assert(msg != empty, "empty message");
assert(!Heap_lock->owned_by_self(), "Heap_lock owned by requesting thread");
_buffer = msg;
while (_buffer != empty) {
_monitor.notify();
_monitor.wait(Mutex::_no_safepoint_check_flag);
}
}
// ======= Surrogate Locker Thread =============
void SurrogateLockerThread::loop() {
BasicLock pll_basic_lock;
SLT_msg_type msg;
debug_only(unsigned int owned = 0;)
while (/* !isTerminated() */ 1) {
{
MutexLocker x(&_monitor);
// Since we are a JavaThread, we can't be here at a safepoint.
assert(!SafepointSynchronize::is_at_safepoint(),
"SLT is a JavaThread");
// wait for msg buffer to become non-empty
while (_buffer == empty) {
_monitor.notify();
_monitor.wait();
}
msg = _buffer;
}
switch(msg) {
case acquirePLL: {
InstanceRefKlass::acquire_pending_list_lock(&pll_basic_lock);
debug_only(owned++;)
break;
}
case releaseAndNotifyPLL: {
assert(owned > 0, "Don't have PLL");
InstanceRefKlass::release_and_notify_pending_list_lock(&pll_basic_lock);
debug_only(owned--;)
break;
}
case empty:
default: {
guarantee(false,"Unexpected message in _buffer");
break;
}
}
{
MutexLocker x(&_monitor);
// Since we are a JavaThread, we can't be here at a safepoint.
assert(!SafepointSynchronize::is_at_safepoint(),
"SLT is a JavaThread");
_buffer = empty;
_monitor.notify();
}
}
assert(!_monitor.owned_by_self(), "Should unlock before exit.");
}

View File

@ -70,37 +70,4 @@ public:
bool has_terminated() { return _has_terminated; }
};
// The SurrogateLockerThread is used by concurrent GC threads for
// manipulating Java monitors, in particular, currently for
// manipulating the pending_list_lock. XXX
class SurrogateLockerThread: public JavaThread {
friend class VMStructs;
public:
enum SLT_msg_type {
empty = 0, // no message
acquirePLL, // acquire pending list lock
releaseAndNotifyPLL // notify and release pending list lock
};
private:
// the following are shared with the CMSThread
SLT_msg_type _buffer; // communication buffer
Monitor _monitor; // monitor controlling buffer
BasicLock _basicLock; // used for PLL locking
public:
static SurrogateLockerThread* make(TRAPS);
// Terminate VM with error message that SLT needed but not yet created.
static void report_missing_slt();
SurrogateLockerThread();
bool is_hidden_from_external_view() const { return true; }
void loop(); // main method
void manipulatePLL(SLT_msg_type msg);
};
#endif // SHARE_VM_GC_SHARED_CONCURRENTGCTHREAD_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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
@ -281,6 +281,10 @@ public:
return UseConcMarkSweepGC;
}
virtual bool needs_reference_pending_list_locker_thread() const {
return UseConcMarkSweepGC;
}
// We don't need barriers for stores to objects in the
// young gen and, a fortiori, for initializing stores to
// objects therein. This applies to DefNew+Tenured and ParNew+CMS

View File

@ -0,0 +1,226 @@
/*
* Copyright (c) 2016, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/referencePendingListLocker.hpp"
#include "memory/universe.hpp"
#include "runtime/javaCalls.hpp"
#include "utilities/preserveException.hpp"
ReferencePendingListLockerThread::ReferencePendingListLockerThread() :
JavaThread(&start),
_monitor(Monitor::nonleaf, "ReferencePendingListLocker", false, Monitor::_safepoint_check_sometimes),
_message(NONE) {}
ReferencePendingListLockerThread* ReferencePendingListLockerThread::create(TRAPS) {
// Create Java thread objects
instanceKlassHandle thread_klass = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK_NULL);
instanceHandle thread_object = thread_klass->allocate_instance_handle(CHECK_NULL);
Handle thread_name = java_lang_String::create_from_str("Reference Pending List Locker", CHECK_NULL);
Handle thread_group = Universe::system_thread_group();
JavaValue result(T_VOID);
JavaCalls::call_special(&result,
thread_object,
thread_klass,
vmSymbols::object_initializer_name(),
vmSymbols::threadgroup_string_void_signature(),
thread_group,
thread_name,
CHECK_NULL);
{
MutexLocker ml(Threads_lock);
// Allocate thread
ReferencePendingListLockerThread* thread = new ReferencePendingListLockerThread();
if (thread == NULL || thread->osthread() == NULL) {
vm_exit_during_initialization("java.lang.OutOfMemoryError",
os::native_thread_creation_failed_msg());
}
// Initialize thread
java_lang_Thread::set_thread(thread_object(), thread);
java_lang_Thread::set_priority(thread_object(), NearMaxPriority);
java_lang_Thread::set_daemon(thread_object());
thread->set_threadObj(thread_object());
// Start thread
Threads::add(thread);
Thread::start(thread);
return thread;
}
}
void ReferencePendingListLockerThread::start(JavaThread* thread, TRAPS) {
ReferencePendingListLockerThread* locker_thread = static_cast<ReferencePendingListLockerThread*>(thread);
locker_thread->receive_and_handle_messages();
}
bool ReferencePendingListLockerThread::is_hidden_from_external_view() const {
return true;
}
void ReferencePendingListLockerThread::send_message(Message message) {
assert(message != NONE, "Should not be none");
MonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag);
// Wait for completion of current message
while (_message != NONE) {
ml.wait(Monitor::_no_safepoint_check_flag);
}
// Send new message
_message = message;
ml.notify_all();
// Wait for completion of new message
while (_message != NONE) {
ml.wait(Monitor::_no_safepoint_check_flag);
}
}
void ReferencePendingListLockerThread::receive_and_handle_messages() {
ReferencePendingListLocker pending_list_locker;
MonitorLockerEx ml(&_monitor);
// Main loop, never terminates
for (;;) {
// Wait for message
while (_message == NONE) {
ml.wait();
}
// Handle message
if (_message == LOCK) {
pending_list_locker.lock();
} else if (_message == UNLOCK) {
pending_list_locker.unlock();
} else {
ShouldNotReachHere();
}
// Clear message
_message = NONE;
ml.notify_all();
}
}
void ReferencePendingListLockerThread::lock() {
send_message(LOCK);
}
void ReferencePendingListLockerThread::unlock() {
send_message(UNLOCK);
}
bool ReferencePendingListLocker::_is_initialized = false;
ReferencePendingListLockerThread* ReferencePendingListLocker::_locker_thread = NULL;
void ReferencePendingListLocker::initialize(bool needs_locker_thread, TRAPS) {
if (needs_locker_thread) {
_locker_thread = ReferencePendingListLockerThread::create(CHECK);
}
_is_initialized = true;
}
bool ReferencePendingListLocker::is_initialized() {
return _is_initialized;
}
bool ReferencePendingListLocker::is_locked_by_self() {
oop pending_list_lock = java_lang_ref_Reference::pending_list_lock();
if (pending_list_lock == NULL) {
return false;
}
JavaThread* thread = JavaThread::current();
Handle handle(thread, pending_list_lock);
return ObjectSynchronizer::current_thread_holds_lock(thread, handle);
}
void ReferencePendingListLocker::lock() {
assert(!Heap_lock->owned_by_self(), "Heap_lock must not be owned by requesting thread");
if (Thread::current()->is_Java_thread()) {
assert(java_lang_ref_Reference::pending_list_lock() != NULL, "Not initialized");
// We may enter this with a pending exception
PRESERVE_EXCEPTION_MARK;
HandleMark hm;
Handle handle(THREAD, java_lang_ref_Reference::pending_list_lock());
assert(!is_locked_by_self(), "Should not be locked by self");
// Lock
ObjectSynchronizer::fast_enter(handle, &_basic_lock, false, THREAD);
assert(is_locked_by_self(), "Locking failed");
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
}
} else {
// Delegate operation to locker thread
assert(_locker_thread != NULL, "Locker thread not created");
_locker_thread->lock();
}
}
void ReferencePendingListLocker::unlock() {
if (Thread::current()->is_Java_thread()) {
assert(java_lang_ref_Reference::pending_list_lock() != NULL, "Not initialized");
// We may enter this with a pending exception
PRESERVE_EXCEPTION_MARK;
HandleMark hm;
Handle handle(THREAD, java_lang_ref_Reference::pending_list_lock());
assert(is_locked_by_self(), "Should be locked by self");
// Notify waiters if the pending list is non-empty
if (java_lang_ref_Reference::pending_list() != NULL) {
ObjectSynchronizer::notifyall(handle, THREAD);
}
// Unlock
ObjectSynchronizer::fast_exit(handle(), &_basic_lock, THREAD);
assert(!is_locked_by_self(), "Unlocking failed");
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
}
} else {
// Delegate operation to locker thread
assert(_locker_thread != NULL, "Locker thread not created");
_locker_thread->unlock();
}
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (c) 2016, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_GC_SHARED_REFERENCEPENDINGLISTLOCKER_HPP
#define SHARE_VM_GC_SHARED_REFERENCEPENDINGLISTLOCKER_HPP
#include "memory/allocation.hpp"
#include "runtime/basicLock.hpp"
#include "runtime/mutex.hpp"
#include "runtime/thread.hpp"
#include "utilities/exceptions.hpp"
//
// The ReferencePendingListLockerThread locks and unlocks the reference
// pending list lock on behalf a non-Java thread, typically a concurrent
// GC thread. This interface should not be directly accessed. All uses
// should instead go through the ReferencePendingListLocker, which calls
// this thread if needed.
//
class ReferencePendingListLockerThread : public JavaThread {
private:
enum Message {
NONE,
LOCK,
UNLOCK
};
Monitor _monitor;
Message _message;
ReferencePendingListLockerThread();
static void start(JavaThread* thread, TRAPS);
void send_message(Message message);
void receive_and_handle_messages();
public:
static ReferencePendingListLockerThread* create(TRAPS);
virtual bool is_hidden_from_external_view() const;
void lock();
void unlock();
};
//
// The ReferencePendingListLocker is the main interface for locking and
// unlocking the reference pending list lock, which needs to be held by
// the GC when adding references to the pending list. Since this is a
// Java-level monitor it can only be locked/unlocked by a Java thread.
// For this reason there is an option to spawn a helper thread, the
// ReferencePendingListLockerThread, during initialization. If a helper
// thread is spawned all lock operations from non-Java threads will be
// delegated to the helper thread. The helper thread is typically needed
// by concurrent GCs.
//
class ReferencePendingListLocker VALUE_OBJ_CLASS_SPEC {
private:
static bool _is_initialized;
static ReferencePendingListLockerThread* _locker_thread;
BasicLock _basic_lock;
public:
static void initialize(bool needs_locker_thread, TRAPS);
static bool is_initialized();
static bool is_locked_by_self();
void lock();
void unlock();
};
#endif // SHARE_VM_GC_SHARED_REFERENCEPENDINGLISTLOCKER_HPP

View File

@ -30,10 +30,8 @@
#include "gc/shared/gcLocker.inline.hpp"
#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/vmGCOperations.hpp"
#include "memory/oopFactory.hpp"
#include "logging/log.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/instanceRefKlass.hpp"
#include "memory/oopFactory.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/interfaceSupport.hpp"
@ -64,14 +62,11 @@ void VM_GC_Operation::notify_gc_end() {
}
void VM_GC_Operation::acquire_pending_list_lock() {
// we may enter this with pending exception set
InstanceRefKlass::acquire_pending_list_lock(&_pending_list_basic_lock);
_pending_list_locker.lock();
}
void VM_GC_Operation::release_and_notify_pending_list_lock() {
InstanceRefKlass::release_and_notify_pending_list_lock(&_pending_list_basic_lock);
_pending_list_locker.unlock();
}
// Allocations may fail in several threads at about the same time,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2016, 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,6 +27,7 @@
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/referencePendingListLocker.hpp"
#include "memory/heapInspection.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/handles.hpp"
@ -69,8 +70,10 @@
//
class VM_GC_Operation: public VM_Operation {
private:
ReferencePendingListLocker _pending_list_locker;
protected:
BasicLock _pending_list_basic_lock; // for refs pending list notification (PLL)
uint _gc_count_before; // gc count before acquiring PLL
uint _full_gc_count_before; // full gc count before acquiring PLL
bool _full; // whether a "full" collection

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2016, 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
@ -25,13 +25,8 @@
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/specialized_oop_closures.hpp"
#include "oops/instanceRefKlass.inline.hpp"
#include "oops/oop.inline.hpp"
#include "utilities/macros.hpp"
#include "utilities/preserveException.hpp"
void InstanceRefKlass::update_nonstatic_oop_maps(Klass* k) {
// Clear the nonstatic oop-map entries corresponding to referent
@ -87,48 +82,3 @@ void InstanceRefKlass::oop_verify_on(oop obj, outputStream* st) {
guarantee(InstanceKlass::cast(next->klass())->is_reference_instance_klass(), "next field verify failed");
}
}
bool InstanceRefKlass::owns_pending_list_lock(JavaThread* thread) {
if (java_lang_ref_Reference::pending_list_lock() == NULL) return false;
Handle h_lock(thread, java_lang_ref_Reference::pending_list_lock());
return ObjectSynchronizer::current_thread_holds_lock(thread, h_lock);
}
void InstanceRefKlass::acquire_pending_list_lock(BasicLock *pending_list_basic_lock) {
// we may enter this with pending exception set
PRESERVE_EXCEPTION_MARK; // exceptions are never thrown, needed for TRAPS argument
// Create a HandleMark in case we retry a GC multiple times.
// Each time we attempt the GC, we allocate the handle below
// to hold the pending list lock. We want to free this handle.
HandleMark hm;
Handle h_lock(THREAD, java_lang_ref_Reference::pending_list_lock());
ObjectSynchronizer::fast_enter(h_lock, pending_list_basic_lock, false, THREAD);
assert(ObjectSynchronizer::current_thread_holds_lock(
JavaThread::current(), h_lock),
"Locking should have succeeded");
if (HAS_PENDING_EXCEPTION) CLEAR_PENDING_EXCEPTION;
}
void InstanceRefKlass::release_and_notify_pending_list_lock(
BasicLock *pending_list_basic_lock) {
// we may enter this with pending exception set
PRESERVE_EXCEPTION_MARK; // exceptions are never thrown, needed for TRAPS argument
// Create a HandleMark in case we retry a GC multiple times.
// Each time we attempt the GC, we allocate the handle below
// to hold the pending list lock. We want to free this handle.
HandleMark hm;
Handle h_lock(THREAD, java_lang_ref_Reference::pending_list_lock());
assert(ObjectSynchronizer::current_thread_holds_lock(
JavaThread::current(), h_lock),
"Lock should be held");
// Notify waiters on pending lists lock if there is any reference.
if (java_lang_ref_Reference::pending_list() != NULL) {
ObjectSynchronizer::notifyall(h_lock, THREAD);
}
ObjectSynchronizer::fast_exit(h_lock(), pending_list_basic_lock, THREAD);
if (HAS_PENDING_EXCEPTION) CLEAR_PENDING_EXCEPTION;
}

View File

@ -118,10 +118,6 @@ private:
ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL_BACKWARDS)
#endif // INCLUDE_ALL_GCS
static void release_and_notify_pending_list_lock(BasicLock *pending_list_basic_lock);
static void acquire_pending_list_lock(BasicLock *pending_list_basic_lock);
static bool owns_pending_list_lock(JavaThread* thread);
// Update non-static oop maps so 'referent', 'nextPending' and
// 'discovered' will look like non-oops
static void update_nonstatic_oop_maps(Klass* k);

View File

@ -30,6 +30,7 @@
#include "gc/shared/collectedHeap.inline.hpp"
#include "gc/shared/gcLocker.hpp"
#include "gc/shared/generation.hpp"
#include "gc/shared/referencePendingListLocker.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "interpreter/bytecodeTracer.hpp"
#include "interpreter/bytecodes.hpp"
@ -374,7 +375,7 @@ void Method::build_interpreter_method_data(const methodHandle& method, TRAPS) {
// Do not profile method if current thread holds the pending list lock,
// which avoids deadlock for acquiring the MethodData_lock.
if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) {
if (ReferencePendingListLocker::is_locked_by_self()) {
return;
}

View File

@ -70,7 +70,6 @@ Monitor* SerializePage_lock = NULL;
Monitor* Threads_lock = NULL;
Monitor* CGC_lock = NULL;
Monitor* STS_lock = NULL;
Monitor* SLT_lock = NULL;
Monitor* FullGCCount_lock = NULL;
Mutex* SATB_Q_FL_lock = NULL;
Monitor* SATB_Q_CBL_mon = NULL;
@ -242,9 +241,6 @@ void mutex_init() {
def(JNIGlobalHandle_lock , Mutex , nonleaf, true, Monitor::_safepoint_check_always); // locks JNIHandleBlockFreeList_lock
def(JNICritical_lock , Monitor, nonleaf, true, Monitor::_safepoint_check_always); // used for JNI critical regions
def(AdapterHandlerLibrary_lock , Mutex , nonleaf, true, Monitor::_safepoint_check_always);
if (UseConcMarkSweepGC) {
def(SLT_lock , Monitor, nonleaf, false, Monitor::_safepoint_check_never); // used in CMS GC for locking PLL lock
}
def(Heap_lock , Monitor, nonleaf+1, false, Monitor::_safepoint_check_sometimes);
def(JfieldIdCreation_lock , Mutex , nonleaf+1, true, Monitor::_safepoint_check_always); // jfieldID, Used in VM_Operation

View File

@ -65,7 +65,6 @@ extern Monitor* Threads_lock; // a lock on the Threads table
extern Monitor* CGC_lock; // used for coordination between
// fore- & background GC threads.
extern Monitor* STS_lock; // used for joining/leaving SuspendibleThreadSet.
extern Monitor* SLT_lock; // used in CMS GC for acquiring PLL
extern Monitor* FullGCCount_lock; // in support of "concurrent" full gc
extern Mutex* SATB_Q_FL_lock; // Protects SATB Q
// buffer free list.

View File

@ -34,6 +34,7 @@
#include "compiler/compileTask.hpp"
#include "gc/shared/gcId.hpp"
#include "gc/shared/gcLocker.inline.hpp"
#include "gc/shared/referencePendingListLocker.hpp"
#include "gc/shared/workgroup.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/linkResolver.hpp"
@ -3650,18 +3651,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
// anymore. We call vm_exit_during_initialization directly instead.
SystemDictionary::compute_java_system_loader(CHECK_(JNI_ERR));
#if INCLUDE_ALL_GCS
// Support for ConcurrentMarkSweep. This should be cleaned up
// and better encapsulated. The ugly nested if test would go away
// once things are properly refactored. XXX YSR
if (UseConcMarkSweepGC || UseG1GC) {
if (UseConcMarkSweepGC) {
ConcurrentMarkSweepThread::makeSurrogateLockerThread(CHECK_JNI_ERR);
} else {
ConcurrentMarkThread::makeSurrogateLockerThread(CHECK_JNI_ERR);
}
}
#endif // INCLUDE_ALL_GCS
// Initialize reference pending list locker
bool needs_locker_thread = Universe::heap()->needs_reference_pending_list_locker_thread();
ReferencePendingListLocker::initialize(needs_locker_thread, CHECK_JNI_ERR);
// Always call even when there are not JVMTI environments yet, since environments
// may be attached late and JVMTI must track phases of VM execution

View File

@ -54,6 +54,7 @@
#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/generation.hpp"
#include "gc/shared/generationSpec.hpp"
#include "gc/shared/referencePendingListLocker.hpp"
#include "gc/shared/space.hpp"
#include "interpreter/bytecodeInterpreter.hpp"
#include "interpreter/bytecodes.hpp"
@ -1692,6 +1693,7 @@ typedef CompactHashtable<Symbol*, char> SymbolCompactHashTable;
declare_type(JavaThread, Thread) \
declare_type(JvmtiAgentThread, JavaThread) \
declare_type(ServiceThread, JavaThread) \
declare_type(ReferencePendingListLockerThread, JavaThread) \
declare_type(CompilerThread, JavaThread) \
declare_type(CodeCacheSweeperThread, JavaThread) \
declare_toplevel_type(OSThread) \