8151601: Cleanup locking of the Reference pending list
Reviewed-by: brutisso, stefank
This commit is contained in:
parent
9d3140761b
commit
da5ca5c5d5
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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) \
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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.");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
226
hotspot/src/share/vm/gc/shared/referencePendingListLocker.cpp
Normal file
226
hotspot/src/share/vm/gc/shared/referencePendingListLocker.cpp
Normal 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();
|
||||
}
|
||||
}
|
@ -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
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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) \
|
||||
|
Loading…
Reference in New Issue
Block a user