Merge
This commit is contained in:
commit
2730e1ad50
hotspot
src
os
share/vm
test/serviceability/threads
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user