This commit is contained in:
Daniel D. Daugherty 2014-10-31 10:15:29 -07:00
commit 2730e1ad50
12 changed files with 372 additions and 140 deletions

@ -4118,7 +4118,18 @@ void os::pause() {
}
// Refer to the comments in os_solaris.cpp park-unpark.
// Refer to the comments in os_solaris.cpp park-unpark. The next two
// comment paragraphs are worth repeating here:
//
// Assumption:
// Only one parker can exist on an event, which is why we allocate
// them per-thread. Multiple unparkers can coexist.
//
// _Event serves as a restricted-range semaphore.
// -1 : thread is blocked, i.e. there is a waiter
// 0 : neutral: thread is running or ready,
// could have been signaled after a wait started
// 1 : signaled - thread is running or ready
//
// Beware -- Some versions of NPTL embody a flaw where pthread_cond_timedwait() can
// hang indefinitely. For instance NPTL 0.60 on 2.4.21-4ELsmp is vulnerable.
@ -4203,6 +4214,11 @@ static struct timespec* compute_abstime(struct timespec* abstime,
}
void os::PlatformEvent::park() { // AKA "down()"
// Transitions for _Event:
// -1 => -1 : illegal
// 1 => 0 : pass - return immediately
// 0 => -1 : block; then set _Event to 0 before returning
// Invariant: Only the thread associated with the Event/PlatformEvent
// may call park().
// TODO: assert that _Assoc != NULL or _Assoc == Self
@ -4240,6 +4256,11 @@ void os::PlatformEvent::park() { // AKA "down()"
}
int os::PlatformEvent::park(jlong millis) {
// Transitions for _Event:
// -1 => -1 : illegal
// 1 => 0 : pass - return immediately
// 0 => -1 : block; then set _Event to 0 before returning
guarantee(_nParked == 0, "invariant");
int v;
@ -4303,11 +4324,11 @@ int os::PlatformEvent::park(jlong millis) {
void os::PlatformEvent::unpark() {
// Transitions for _Event:
// 0 :=> 1
// 1 :=> 1
// -1 :=> either 0 or 1; must signal target thread
// That is, we can safely transition _Event from -1 to either
// 0 or 1.
// 0 => 1 : just return
// 1 => 1 : just return
// -1 => either 0 or 1; must signal target thread
// That is, we can safely transition _Event from -1 to either
// 0 or 1.
// See also: "Semaphores in Plan 9" by Mullender & Cox
//
// Note: Forcing a transition from "-1" to "1" on an unpark() means
@ -4330,15 +4351,16 @@ void os::PlatformEvent::unpark() {
status = pthread_mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
if (AnyWaiters != 0) {
// Note that we signal() *after* dropping the lock for "immortal" Events.
// This is safe and avoids a common class of futile wakeups. In rare
// circumstances this can cause a thread to return prematurely from
// cond_{timed}wait() but the spurious wakeup is benign and the victim
// will simply re-test the condition and re-park itself.
// This provides particular benefit if the underlying platform does not
// provide wait morphing.
status = pthread_cond_signal(_cond);
assert_status(status == 0, status, "cond_signal");
}
// Note that we signal() _after dropping the lock for "immortal" Events.
// This is safe and avoids a common class of futile wakeups. In rare
// circumstances this can cause a thread to return prematurely from
// cond_{timed}wait() but the spurious wakeup is benign and the victim will
// simply re-test the condition and re-park itself.
}

@ -5103,9 +5103,38 @@ int os::open(const char *path, int oflag, int mode) {
errno = ENAMETOOLONG;
return -1;
}
int fd;
fd = ::open64(path, oflag, mode);
// All file descriptors that are opened in the Java process and not
// specifically destined for a subprocess should have the close-on-exec
// flag set. If we don't set it, then careless 3rd party native code
// might fork and exec without closing all appropriate file descriptors
// (e.g. as we do in closeDescriptors in UNIXProcess.c), and this in
// turn might:
//
// - cause end-of-file to fail to be detected on some file
// descriptors, resulting in mysterious hangs, or
//
// - might cause an fopen in the subprocess to fail on a system
// suffering from bug 1085341.
//
// (Yes, the default setting of the close-on-exec flag is a Unix
// design flaw)
//
// See:
// 1085341: 32-bit stdio routines should support file descriptors >255
// 4843136: (process) pipe file descriptor from Runtime.exec not being closed
// 6339493: (process) Runtime.exec does not close all file descriptors on Solaris 9
//
// Modern Linux kernels (after 2.6.23 2007) support O_CLOEXEC with open().
// O_CLOEXEC is preferable to using FD_CLOEXEC on an open file descriptor
// because it saves a system call and removes a small window where the flag
// is unset. On ancient Linux kernels the O_CLOEXEC flag will be ignored
// and we fall back to using FD_CLOEXEC (see below).
#ifdef O_CLOEXEC
oflag |= O_CLOEXEC;
#endif
int fd = ::open64(path, oflag, mode);
if (fd == -1) return -1;
//If the open succeeded, the file might still be a directory
@ -5126,32 +5155,17 @@ int os::open(const char *path, int oflag, int mode) {
}
}
// All file descriptors that are opened in the JVM and not
// specifically destined for a subprocess should have the
// close-on-exec flag set. If we don't set it, then careless 3rd
// party native code might fork and exec without closing all
// appropriate file descriptors (e.g. as we do in closeDescriptors in
// UNIXProcess.c), and this in turn might:
//
// - cause end-of-file to fail to be detected on some file
// descriptors, resulting in mysterious hangs, or
//
// - might cause an fopen in the subprocess to fail on a system
// suffering from bug 1085341.
//
// (Yes, the default setting of the close-on-exec flag is a Unix
// design flaw)
//
// See:
// 1085341: 32-bit stdio routines should support file descriptors >255
// 4843136: (process) pipe file descriptor from Runtime.exec not being closed
// 6339493: (process) Runtime.exec does not close all file descriptors on Solaris 9
//
#ifdef FD_CLOEXEC
{
// Validate that the use of the O_CLOEXEC flag on open above worked.
// With recent kernels, we will perform this check exactly once.
static sig_atomic_t O_CLOEXEC_is_known_to_work = 0;
if (!O_CLOEXEC_is_known_to_work) {
int flags = ::fcntl(fd, F_GETFD);
if (flags != -1) {
::fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
if ((flags & FD_CLOEXEC) != 0)
O_CLOEXEC_is_known_to_work = 1;
else
::fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
}
}
#endif
@ -5401,7 +5415,18 @@ void os::pause() {
}
// Refer to the comments in os_solaris.cpp park-unpark.
// Refer to the comments in os_solaris.cpp park-unpark. The next two
// comment paragraphs are worth repeating here:
//
// Assumption:
// Only one parker can exist on an event, which is why we allocate
// them per-thread. Multiple unparkers can coexist.
//
// _Event serves as a restricted-range semaphore.
// -1 : thread is blocked, i.e. there is a waiter
// 0 : neutral: thread is running or ready,
// could have been signaled after a wait started
// 1 : signaled - thread is running or ready
//
// Beware -- Some versions of NPTL embody a flaw where pthread_cond_timedwait() can
// hang indefinitely. For instance NPTL 0.60 on 2.4.21-4ELsmp is vulnerable.
@ -5500,6 +5525,11 @@ static struct timespec* compute_abstime(timespec* abstime, jlong millis) {
}
void os::PlatformEvent::park() { // AKA "down()"
// Transitions for _Event:
// -1 => -1 : illegal
// 1 => 0 : pass - return immediately
// 0 => -1 : block; then set _Event to 0 before returning
// Invariant: Only the thread associated with the Event/PlatformEvent
// may call park().
// TODO: assert that _Assoc != NULL or _Assoc == Self
@ -5537,6 +5567,11 @@ void os::PlatformEvent::park() { // AKA "down()"
}
int os::PlatformEvent::park(jlong millis) {
// Transitions for _Event:
// -1 => -1 : illegal
// 1 => 0 : pass - return immediately
// 0 => -1 : block; then set _Event to 0 before returning
guarantee(_nParked == 0, "invariant");
int v;
@ -5600,11 +5635,11 @@ int os::PlatformEvent::park(jlong millis) {
void os::PlatformEvent::unpark() {
// Transitions for _Event:
// 0 :=> 1
// 1 :=> 1
// -1 :=> either 0 or 1; must signal target thread
// That is, we can safely transition _Event from -1 to either
// 0 or 1.
// 0 => 1 : just return
// 1 => 1 : just return
// -1 => either 0 or 1; must signal target thread
// That is, we can safely transition _Event from -1 to either
// 0 or 1.
// See also: "Semaphores in Plan 9" by Mullender & Cox
//
// Note: Forcing a transition from "-1" to "1" on an unpark() means
@ -5627,15 +5662,16 @@ void os::PlatformEvent::unpark() {
status = pthread_mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
if (AnyWaiters != 0) {
// Note that we signal() *after* dropping the lock for "immortal" Events.
// This is safe and avoids a common class of futile wakeups. In rare
// circumstances this can cause a thread to return prematurely from
// cond_{timed}wait() but the spurious wakeup is benign and the victim
// will simply re-test the condition and re-park itself.
// This provides particular benefit if the underlying platform does not
// provide wait morphing.
status = pthread_cond_signal(_cond);
assert_status(status == 0, status, "cond_signal");
}
// Note that we signal() _after dropping the lock for "immortal" Events.
// This is safe and avoids a common class of futile wakeups. In rare
// circumstances this can cause a thread to return prematurely from
// cond_{timed}wait() but the spurious wakeup is benign and the victim will
// simply re-test the condition and re-park itself.
}

@ -5372,31 +5372,32 @@ extern "C" {
// to immediately return 0 your code should still work,
// albeit degenerating to a spin loop.
//
// An interesting optimization for park() is to use a trylock()
// to attempt to acquire the mutex. If the trylock() fails
// then we know that a concurrent unpark() operation is in-progress.
// in that case the park() code could simply set _count to 0
// and return immediately. The subsequent park() operation *might*
// return immediately. That's harmless as the caller of park() is
// expected to loop. By using trylock() we will have avoided a
// avoided a context switch caused by contention on the per-thread mutex.
// In a sense, park()-unpark() just provides more polite spinning
// and polling with the key difference over naive spinning being
// that a parked thread needs to be explicitly unparked() in order
// to wake up and to poll the underlying condition.
//
// TODO-FIXME:
// 1. Reconcile Doug's JSR166 j.u.c park-unpark with the
// objectmonitor implementation.
// 2. Collapse the JSR166 parker event, and the
// objectmonitor ParkEvent into a single "Event" construct.
// 3. In park() and unpark() add:
// assert (Thread::current() == AssociatedWith).
// 4. add spurious wakeup injection on a -XX:EarlyParkReturn=N switch.
// 1-out-of-N park() operations will return immediately.
// Assumption:
// Only one parker can exist on an event, which is why we allocate
// them per-thread. Multiple unparkers can coexist.
//
// _Event transitions in park()
// -1 => -1 : illegal
// 1 => 0 : pass - return immediately
// 0 => -1 : block
// 0 => -1 : block; then set _Event to 0 before returning
//
// _Event transitions in unpark()
// 0 => 1 : just return
// 1 => 1 : just return
// -1 => either 0 or 1; must signal target thread
// That is, we can safely transition _Event from -1 to either
// 0 or 1.
//
// _Event serves as a restricted-range semaphore.
// -1 : thread is blocked, i.e. there is a waiter
// 0 : neutral: thread is running or ready,
// could have been signaled after a wait started
// 1 : signaled - thread is running or ready
//
// Another possible encoding of _Event would be with
// explicit "PARKED" == 01b and "SIGNALED" == 10b bits.
@ -5456,6 +5457,11 @@ static timestruc_t* compute_abstime(timestruc_t* abstime, jlong millis) {
}
void os::PlatformEvent::park() { // AKA: down()
// Transitions for _Event:
// -1 => -1 : illegal
// 1 => 0 : pass - return immediately
// 0 => -1 : block; then set _Event to 0 before returning
// Invariant: Only the thread associated with the Event/PlatformEvent
// may call park().
assert(_nParked == 0, "invariant");
@ -5497,6 +5503,11 @@ void os::PlatformEvent::park() { // AKA: down()
}
int os::PlatformEvent::park(jlong millis) {
// Transitions for _Event:
// -1 => -1 : illegal
// 1 => 0 : pass - return immediately
// 0 => -1 : block; then set _Event to 0 before returning
guarantee(_nParked == 0, "invariant");
int v;
for (;;) {
@ -5542,11 +5553,11 @@ int os::PlatformEvent::park(jlong millis) {
void os::PlatformEvent::unpark() {
// Transitions for _Event:
// 0 :=> 1
// 1 :=> 1
// -1 :=> either 0 or 1; must signal target thread
// That is, we can safely transition _Event from -1 to either
// 0 or 1.
// 0 => 1 : just return
// 1 => 1 : just return
// -1 => either 0 or 1; must signal target thread
// That is, we can safely transition _Event from -1 to either
// 0 or 1.
// See also: "Semaphores in Plan 9" by Mullender & Cox
//
// Note: Forcing a transition from "-1" to "1" on an unpark() means
@ -5566,8 +5577,13 @@ void os::PlatformEvent::unpark() {
assert_status(status == 0, status, "mutex_unlock");
guarantee(AnyWaiters == 0 || AnyWaiters == 1, "invariant");
if (AnyWaiters != 0) {
// We intentional signal *after* dropping the lock
// to avoid a common class of futile wakeups.
// Note that we signal() *after* dropping the lock for "immortal" Events.
// This is safe and avoids a common class of futile wakeups. In rare
// circumstances this can cause a thread to return prematurely from
// cond_{timed}wait() but the spurious wakeup is benign and the victim
// will simply re-test the condition and re-park itself.
// This provides particular benefit if the underlying platform does not
// provide wait morphing.
status = os::Solaris::cond_signal(_cond);
assert_status(status == 0, status, "cond_signal");
}

@ -436,9 +436,9 @@ static unsigned __stdcall java_start(Thread* thread) {
}
// Diagnostic code to investigate JDK-6573254
int res = 90115; // non-java thread
int res = 50115; // non-java thread
if (thread->is_Java_thread()) {
res = 60115; // java thread
res = 40115; // java thread
}
// Install a win32 structured exception handler around every thread created
@ -3740,68 +3740,134 @@ HINSTANCE os::win32::load_Windows_dll(const char* name, char *ebuf,
return NULL;
}
#define MIN_EXIT_MUTEXES 1
#define MAX_EXIT_MUTEXES 16
#define MAX_EXIT_HANDLES 16
#define EXIT_TIMEOUT 1000 /* 1 sec */
struct ExitMutexes {
DWORD count;
HANDLE handles[MAX_EXIT_MUTEXES];
};
static BOOL CALLBACK init_muts_call(PINIT_ONCE, PVOID ppmuts, PVOID*) {
static ExitMutexes muts;
muts.count = os::processor_count();
if (muts.count < MIN_EXIT_MUTEXES) {
muts.count = MIN_EXIT_MUTEXES;
} else if (muts.count > MAX_EXIT_MUTEXES) {
muts.count = MAX_EXIT_MUTEXES;
}
for (DWORD i = 0; i < muts.count; ++i) {
muts.handles[i] = CreateMutex(NULL, FALSE, NULL);
if (muts.handles[i] == NULL) {
return FALSE;
}
}
*((ExitMutexes**)ppmuts) = &muts;
static BOOL CALLBACK init_crit_sect_call(PINIT_ONCE, PVOID pcrit_sect, PVOID*) {
InitializeCriticalSection((CRITICAL_SECTION*)pcrit_sect);
return TRUE;
}
int os::win32::exit_process_or_thread(Ept what, int exit_code) {
if (os::win32::has_exit_bug()) {
static INIT_ONCE init_once_muts = INIT_ONCE_STATIC_INIT;
static ExitMutexes* pmuts;
// Basic approach:
// - Each exiting thread registers its intent to exit and then does so.
// - A thread trying to terminate the process must wait for all
// threads currently exiting to complete their exit.
if (!InitOnceExecuteOnce(&init_once_muts, init_muts_call, &pmuts, NULL)) {
warning("ExitMutex initialization failed in %s: %d\n", __FILE__, __LINE__);
} else if (WaitForMultipleObjects(pmuts->count, pmuts->handles,
(what != EPT_THREAD), // exiting process waits for all mutexes
INFINITE) == WAIT_FAILED) {
warning("ExitMutex acquisition failed in %s: %d\n", __FILE__, __LINE__);
if (os::win32::has_exit_bug()) {
// The array holds handles of the threads that have started exiting by calling
// _endthreadex().
// Should be large enough to avoid blocking the exiting thread due to lack of
// a free slot.
static HANDLE handles[MAX_EXIT_HANDLES];
static int handle_count = 0;
static INIT_ONCE init_once_crit_sect = INIT_ONCE_STATIC_INIT;
static CRITICAL_SECTION crit_sect;
int i, j;
DWORD res;
HANDLE hproc, hthr;
// The first thread that reached this point, initializes the critical section.
if (!InitOnceExecuteOnce(&init_once_crit_sect, init_crit_sect_call, &crit_sect, NULL)) {
warning("crit_sect initialization failed in %s: %d\n", __FILE__, __LINE__);
} else {
EnterCriticalSection(&crit_sect);
if (what == EPT_THREAD) {
// Remove from the array those handles of the threads that have completed exiting.
for (i = 0, j = 0; i < handle_count; ++i) {
res = WaitForSingleObject(handles[i], 0 /* don't wait */);
if (res == WAIT_TIMEOUT) {
handles[j++] = handles[i];
} else {
if (res != WAIT_OBJECT_0) {
warning("WaitForSingleObject failed in %s: %d\n", __FILE__, __LINE__);
// Don't keep the handle, if we failed waiting for it.
}
CloseHandle(handles[i]);
}
}
// If there's no free slot in the array of the kept handles, we'll have to
// wait until at least one thread completes exiting.
if ((handle_count = j) == MAX_EXIT_HANDLES) {
res = WaitForMultipleObjects(MAX_EXIT_HANDLES, handles, FALSE, EXIT_TIMEOUT);
if (res >= WAIT_OBJECT_0 && res < (WAIT_OBJECT_0 + MAX_EXIT_HANDLES)) {
i = (res - WAIT_OBJECT_0);
handle_count = MAX_EXIT_HANDLES - 1;
for (; i < handle_count; ++i) {
handles[i] = handles[i + 1];
}
} else {
warning("WaitForMultipleObjects failed in %s: %d\n", __FILE__, __LINE__);
// Don't keep handles, if we failed waiting for them.
for (i = 0; i < MAX_EXIT_HANDLES; ++i) {
CloseHandle(handles[i]);
}
handle_count = 0;
}
}
// Store a duplicate of the current thread handle in the array of handles.
hproc = GetCurrentProcess();
hthr = GetCurrentThread();
if (!DuplicateHandle(hproc, hthr, hproc, &handles[handle_count],
0, FALSE, DUPLICATE_SAME_ACCESS)) {
warning("DuplicateHandle failed in %s: %d\n", __FILE__, __LINE__);
} else {
++handle_count;
}
// The current exiting thread has stored its handle in the array, and now
// should leave the critical section before calling _endthreadex().
} else { // what != EPT_THREAD
if (handle_count > 0) {
// Before ending the process, make sure all the threads that had called
// _endthreadex() completed.
res = WaitForMultipleObjects(handle_count, handles, TRUE, EXIT_TIMEOUT);
if (res == WAIT_FAILED) {
warning("WaitForMultipleObjects failed in %s: %d\n", __FILE__, __LINE__);
}
for (i = 0; i < handle_count; ++i) {
CloseHandle(handles[i]);
}
handle_count = 0;
}
// End the process, not leaving critical section.
// This makes sure no other thread executes exit-related code at the same
// time, thus a race is avoided.
if (what == EPT_PROCESS) {
::exit(exit_code);
} else {
_exit(exit_code);
}
}
LeaveCriticalSection(&crit_sect);
}
}
switch (what) {
case EPT_THREAD:
// We are here if either
// - there's no 'race at exit' bug on this OS release;
// - initialization of the critical section failed (unlikely);
// - the current thread has stored its handle and left the critical section.
if (what == EPT_THREAD) {
_endthreadex((unsigned)exit_code);
break;
case EPT_PROCESS:
} else if (what == EPT_PROCESS) {
::exit(exit_code);
break;
case EPT_PROCESS_DIE:
} else {
_exit(exit_code);
break;
}
// should not reach here
// Should not reach here
return exit_code;
}
#undef MIN_EXIT_MUTEXES
#undef MAX_EXIT_MUTEXES
#undef MAX_EXIT_HANDLES
#undef EXIT_TIMEOUT
void os::win32::setmode_streams() {
_setmode(_fileno(stdin), _O_BINARY);
@ -4792,27 +4858,46 @@ bool os::WatcherThreadCrashProtection::call(os::CrashProtectionCallback& cb) {
// 3. Collapse the interrupt_event, the JSR166 parker event, and the objectmonitor ParkEvent
// into a single win32 CreateEvent() handle.
//
// Assumption:
// Only one parker can exist on an event, which is why we allocate
// them per-thread. Multiple unparkers can coexist.
//
// _Event transitions in park()
// -1 => -1 : illegal
// 1 => 0 : pass - return immediately
// 0 => -1 : block
// 0 => -1 : block; then set _Event to 0 before returning
//
// _Event serves as a restricted-range semaphore :
// -1 : thread is blocked
// 0 : neutral - thread is running or ready
// 1 : signaled - thread is running or ready
// _Event transitions in unpark()
// 0 => 1 : just return
// 1 => 1 : just return
// -1 => either 0 or 1; must signal target thread
// That is, we can safely transition _Event from -1 to either
// 0 or 1.
//
// _Event serves as a restricted-range semaphore.
// -1 : thread is blocked, i.e. there is a waiter
// 0 : neutral: thread is running or ready,
// could have been signaled after a wait started
// 1 : signaled - thread is running or ready
//
// Another possible encoding of _Event would be with
// explicit "PARKED" == 01b and "SIGNALED" == 10b bits.
//
// Another possible encoding of _Event would be
// with explicit "PARKED" and "SIGNALED" bits.
int os::PlatformEvent::park(jlong Millis) {
// Transitions for _Event:
// -1 => -1 : illegal
// 1 => 0 : pass - return immediately
// 0 => -1 : block; then set _Event to 0 before returning
guarantee(_ParkHandle != NULL , "Invariant");
guarantee(Millis > 0 , "Invariant");
int v;
// CONSIDER: defer assigning a CreateEvent() handle to the Event until
// the initial park() operation.
// Consider: use atomic decrement instead of CAS-loop
int v;
for (;;) {
v = _Event;
if (Atomic::cmpxchg(v-1, &_Event, v) == v) break;
@ -4860,9 +4945,15 @@ int os::PlatformEvent::park(jlong Millis) {
}
void os::PlatformEvent::park() {
// Transitions for _Event:
// -1 => -1 : illegal
// 1 => 0 : pass - return immediately
// 0 => -1 : block; then set _Event to 0 before returning
guarantee(_ParkHandle != NULL, "Invariant");
// Invariant: Only the thread associated with the Event/PlatformEvent
// may call park().
// Consider: use atomic decrement instead of CAS-loop
int v;
for (;;) {
v = _Event;
@ -4891,11 +4982,11 @@ void os::PlatformEvent::unpark() {
guarantee(_ParkHandle != NULL, "Invariant");
// Transitions for _Event:
// 0 :=> 1
// 1 :=> 1
// -1 :=> either 0 or 1; must signal target thread
// That is, we can safely transition _Event from -1 to either
// 0 or 1.
// 0 => 1 : just return
// 1 => 1 : just return
// -1 => either 0 or 1; must signal target thread
// That is, we can safely transition _Event from -1 to either
// 0 or 1.
// See also: "Semaphores in Plan 9" by Mullender & Cox
//
// Note: Forcing a transition from "-1" to "1" on an unpark() means

@ -553,6 +553,7 @@ ClassLoaderData* ClassLoaderDataGraph::_saved_unloading = NULL;
ClassLoaderData* ClassLoaderDataGraph::_saved_head = NULL;
bool ClassLoaderDataGraph::_should_purge = false;
bool ClassLoaderDataGraph::_metaspace_oom = false;
// Add a new class loader data node to the list. Assign the newly created
// ClassLoaderData into the java/lang/ClassLoader object as a hidden field
@ -804,12 +805,17 @@ void ClassLoaderDataGraph::purge() {
ClassLoaderData* list = _unloading;
_unloading = NULL;
ClassLoaderData* next = list;
bool classes_unloaded = false;
while (next != NULL) {
ClassLoaderData* purge_me = next;
next = purge_me->next();
delete purge_me;
classes_unloaded = true;
}
if (classes_unloaded) {
Metaspace::purge();
set_metaspace_oom(false);
}
Metaspace::purge();
}
void ClassLoaderDataGraph::post_class_unload_events(void) {

@ -68,6 +68,9 @@ class ClassLoaderDataGraph : public AllStatic {
static ClassLoaderData* _saved_head;
static ClassLoaderData* _saved_unloading;
static bool _should_purge;
// OOM has been seen in metaspace allocation. Used to prevent some
// allocations until class unloading
static bool _metaspace_oom;
static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS);
static void post_class_unload_events(void);
@ -107,6 +110,9 @@ class ClassLoaderDataGraph : public AllStatic {
}
}
static bool has_metaspace_oom() { return _metaspace_oom; }
static void set_metaspace_oom(bool value) { _metaspace_oom = value; }
static void free_deallocate_lists();
static void dump_on(outputStream * const out) PRODUCT_RETURN;

@ -185,6 +185,14 @@ class CompilationLog : public StringEventLog {
lm.print("\n");
log(thread, "%s", (const char*)lm);
}
void log_metaspace_failure(const char* reason) {
ResourceMark rm;
StringLogMessage lm;
lm.print("%4d COMPILE PROFILING SKIPPED: %s", -1, reason);
lm.print("\n");
log(JavaThread::current(), "%s", (const char*)lm);
}
};
static CompilationLog* _compilation_log = NULL;
@ -1817,6 +1825,18 @@ void CompileBroker::init_compiler_thread_log() {
warning("Cannot open log file: %s", file_name);
}
void CompileBroker::log_metaspace_failure() {
const char* message = "some methods may not be compiled because metaspace "
"is out of memory";
if (_compilation_log != NULL) {
_compilation_log->log_metaspace_failure(message);
}
if (PrintCompilation) {
tty->print_cr("COMPILE PROFILING SKIPPED: %s", message);
}
}
// ------------------------------------------------------------------
// CompileBroker::set_should_block
//

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2014, 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
@ -471,6 +471,9 @@ class CompileBroker: AllStatic {
static int get_sum_nmethod_code_size() { return _sum_nmethod_code_size; }
static long get_peak_compilation_time() { return _peak_compilation_time; }
static long get_total_compilation_time() { return _t_total_compilation.milliseconds(); }
// Log that compilation profiling is skipped because metaspace is full.
static void log_metaspace_failure();
};
#endif // SHARE_VM_COMPILER_COMPILEBROKER_HPP

@ -368,6 +368,13 @@ void Method::print_invocation_count() {
// Build a MethodData* object to hold information about this method
// collected in the interpreter.
void Method::build_interpreter_method_data(methodHandle method, TRAPS) {
// Do not profile the method if metaspace has hit an OOM previously
// allocating profiling data. Callers clear pending exception so don't
// add one here.
if (ClassLoaderDataGraph::has_metaspace_oom()) {
return;
}
// 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)) {
@ -379,7 +386,13 @@ void Method::build_interpreter_method_data(methodHandle method, TRAPS) {
MutexLocker ml(MethodData_lock, THREAD);
if (method->method_data() == NULL) {
ClassLoaderData* loader_data = method->method_holder()->class_loader_data();
MethodData* method_data = MethodData::allocate(loader_data, method, CHECK);
MethodData* method_data = MethodData::allocate(loader_data, method, THREAD);
if (HAS_PENDING_EXCEPTION) {
CompileBroker::log_metaspace_failure();
ClassLoaderDataGraph::set_metaspace_oom(true);
return; // return the exception (which is cleared)
}
method->set_method_data(method_data);
if (PrintMethodData && (Verbose || WizardMode)) {
ResourceMark rm(THREAD);
@ -392,9 +405,19 @@ void Method::build_interpreter_method_data(methodHandle method, TRAPS) {
}
MethodCounters* Method::build_method_counters(Method* m, TRAPS) {
// Do not profile the method if metaspace has hit an OOM previously
if (ClassLoaderDataGraph::has_metaspace_oom()) {
return NULL;
}
methodHandle mh(m);
ClassLoaderData* loader_data = mh->method_holder()->class_loader_data();
MethodCounters* counters = MethodCounters::allocate(loader_data, CHECK_NULL);
MethodCounters* counters = MethodCounters::allocate(loader_data, THREAD);
if (HAS_PENDING_EXCEPTION) {
CompileBroker::log_metaspace_failure();
ClassLoaderDataGraph::set_metaspace_oom(true);
return NULL; // return the exception (which is cleared)
}
if (!mh->init_method_counters(counters)) {
MetadataFactory::free_metadata(loader_data, counters);
}

@ -38,6 +38,7 @@ PerfCounter* RuntimeService::_sync_time_ticks = NULL;
PerfCounter* RuntimeService::_total_safepoints = NULL;
PerfCounter* RuntimeService::_safepoint_time_ticks = NULL;
PerfCounter* RuntimeService::_application_time_ticks = NULL;
double RuntimeService::_last_safepoint_sync_time_sec = 0.0;
void RuntimeService::init() {
// Make sure the VM version is initialized
@ -96,6 +97,7 @@ void RuntimeService::record_safepoint_begin() {
// update the time stamp to begin recording safepoint time
_safepoint_timer.update();
_last_safepoint_sync_time_sec = 0.0;
if (UsePerfData) {
_total_safepoints->inc();
if (_app_timer.is_updated()) {
@ -108,6 +110,9 @@ void RuntimeService::record_safepoint_synchronized() {
if (UsePerfData) {
_sync_time_ticks->inc(_safepoint_timer.ticks_since_update());
}
if (PrintGCApplicationStoppedTime) {
_last_safepoint_sync_time_sec = last_safepoint_time_sec();
}
}
void RuntimeService::record_safepoint_end() {
@ -119,8 +124,10 @@ void RuntimeService::record_safepoint_end() {
gclog_or_tty->date_stamp(PrintGCDateStamps);
gclog_or_tty->stamp(PrintGCTimeStamps);
gclog_or_tty->print_cr("Total time for which application threads "
"were stopped: %3.7f seconds",
last_safepoint_time_sec());
"were stopped: %3.7f seconds, "
"Stopping threads took: %3.7f seconds",
last_safepoint_time_sec(),
_last_safepoint_sync_time_sec);
}
// update the time stamp to begin recording app time

@ -37,6 +37,7 @@ private:
static TimeStamp _safepoint_timer;
static TimeStamp _app_timer;
static double _last_safepoint_sync_time_sec;
public:
static void init();

@ -27,6 +27,7 @@ import java.util.Random;
/*
* @test
* @ignore 8061157
* @bug 8016304
* @summary Make sure no deadlock is reported for this program which has no deadlocks.
* @run main/othervm TestFalseDeadLock