< prev index next >

src/os/bsd/vm/os_bsd.cpp

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 1999, 2015, 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. --- 1,7 ---- /* ! * 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.
*** 4040,4104 **** // -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. - // For specifics regarding the bug see GLIBC BUGID 261237 : - // http://www.mail-archive.com/debian-glibc@lists.debian.org/msg10837.html. - // Briefly, pthread_cond_timedwait() calls with an expiry time that's not in the future - // will either hang or corrupt the condvar, resulting in subsequent hangs if the condvar - // is used. (The simple C test-case provided in the GLIBC bug report manifests the - // hang). The JVM is vulernable via sleep(), Object.wait(timo), LockSupport.parkNanos() - // and monitorenter when we're using 1-0 locking. All those operations may result in - // calls to pthread_cond_timedwait(). Using LD_ASSUME_KERNEL to use an older version - // of libpthread avoids the problem, but isn't practical. - // - // Possible remedies: - // - // 1. Establish a minimum relative wait time. 50 to 100 msecs seems to work. - // This is palliative and probabilistic, however. If the thread is preempted - // between the call to compute_abstime() and pthread_cond_timedwait(), more - // than the minimum period may have passed, and the abstime may be stale (in the - // past) resultin in a hang. Using this technique reduces the odds of a hang - // but the JVM is still vulnerable, particularly on heavily loaded systems. - // - // 2. Modify park-unpark to use per-thread (per ParkEvent) pipe-pairs instead - // of the usual flag-condvar-mutex idiom. The write side of the pipe is set - // NDELAY. unpark() reduces to write(), park() reduces to read() and park(timo) - // reduces to poll()+read(). This works well, but consumes 2 FDs per extant - // thread. - // - // 3. Embargo pthread_cond_timedwait() and implement a native "chron" thread - // that manages timeouts. We'd emulate pthread_cond_timedwait() by enqueuing - // a timeout request to the chron thread and then blocking via pthread_cond_wait(). - // This also works well. In fact it avoids kernel-level scalability impediments - // on certain platforms that don't handle lots of active pthread_cond_timedwait() - // timers in a graceful fashion. - // - // 4. When the abstime value is in the past it appears that control returns - // correctly from pthread_cond_timedwait(), but the condvar is left corrupt. - // Subsequent timedwait/wait calls may hang indefinitely. Given that, we - // can avoid the problem by reinitializing the condvar -- by cond_destroy() - // followed by cond_init() -- after all calls to pthread_cond_timedwait(). - // It may be possible to avoid reinitialization by checking the return - // value from pthread_cond_timedwait(). In addition to reinitializing the - // condvar we must establish the invariant that cond_signal() is only called - // within critical sections protected by the adjunct mutex. This prevents - // cond_signal() from "seeing" a condvar that's in the midst of being - // reinitialized or that is corrupt. Sadly, this invariant obviates the - // desirable signal-after-unlock optimization that avoids futile context switching. - // - // I'm also concerned that some versions of NTPL might allocate an auxilliary - // structure when a condvar is used or initialized. cond_destroy() would - // release the helper structure. Our reinitialize-after-timedwait fix - // put excessive stress on malloc/free and locks protecting the c-heap. - // - // We currently use (4). See the WorkAroundNTPLTimedWaitHang flag. - // It may be possible to refine (4) by checking the kernel and NTPL verisons - // and only enabling the work-around for vulnerable environments. // utility to compute the abstime argument to timedwait: // millis is the relative timeout time // abstime will be the absolute timeout time // TODO: replace compute_abstime() with unpackTime() --- 4040,4049 ----
*** 4106,4116 **** static struct timespec* compute_abstime(struct timespec* abstime, jlong millis) { if (millis < 0) millis = 0; struct timeval now; int status = gettimeofday(&now, NULL); ! assert(status == 0, "gettimeofday"); jlong seconds = millis / 1000; millis %= 1000; if (seconds > 50000000) { // see man cond_timedwait(3T) seconds = 50000000; } --- 4051,4061 ---- static struct timespec* compute_abstime(struct timespec* abstime, jlong millis) { if (millis < 0) millis = 0; struct timeval now; int status = gettimeofday(&now, NULL); ! assert_status(status == 0, status, "gettimeofday"); jlong seconds = millis / 1000; millis %= 1000; if (seconds > 50000000) { // see man cond_timedwait(3T) seconds = 50000000; }
*** 4206,4219 **** // TODO: properly differentiate simultaneous notify+interrupt. // In that case, we should propagate the notify to another waiter. while (_Event < 0) { status = pthread_cond_timedwait(_cond, _mutex, &abst); - if (status != 0 && WorkAroundNPTLTimedWaitHang) { - pthread_cond_destroy(_cond); - pthread_cond_init(_cond, NULL); - } assert_status(status == 0 || status == EINTR || status == ETIMEDOUT, status, "cond_timedwait"); if (!FilterSpuriousWakeups) break; // previous semantics if (status == ETIMEDOUT) break; --- 4151,4160 ----
*** 4253,4266 **** // Wait for the thread associated with the event to vacate int status = pthread_mutex_lock(_mutex); assert_status(status == 0, status, "mutex_lock"); int AnyWaiters = _nParked; assert(AnyWaiters == 0 || AnyWaiters == 1, "invariant"); - if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) { - AnyWaiters = 0; - pthread_cond_signal(_cond); - } 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 --- 4194,4203 ----
*** 4309,4319 **** static void unpackTime(struct timespec* absTime, bool isAbsolute, jlong time) { assert(time > 0, "convertTime"); struct timeval now; int status = gettimeofday(&now, NULL); ! assert(status == 0, "gettimeofday"); time_t max_secs = now.tv_sec + MAX_SECS; if (isAbsolute) { jlong secs = time / 1000; --- 4246,4256 ---- static void unpackTime(struct timespec* absTime, bool isAbsolute, jlong time) { assert(time > 0, "convertTime"); struct timeval now; int status = gettimeofday(&now, NULL); ! assert_status(status == 0, status, "gettimeofday"); time_t max_secs = now.tv_sec + MAX_SECS; if (isAbsolute) { jlong secs = time / 1000;
*** 4389,4399 **** int status; if (_counter > 0) { // no wait needed _counter = 0; status = pthread_mutex_unlock(_mutex); ! assert(status == 0, "invariant"); // Paranoia to ensure our locked and lock-free paths interact // correctly with each other and Java-level accesses. OrderAccess::fence(); return; } --- 4326,4336 ---- int status; if (_counter > 0) { // no wait needed _counter = 0; status = pthread_mutex_unlock(_mutex); ! assert_status(status == 0, status, "invariant"); // Paranoia to ensure our locked and lock-free paths interact // correctly with each other and Java-level accesses. OrderAccess::fence(); return; }
*** 4412,4425 **** if (time == 0) { status = pthread_cond_wait(_cond, _mutex); } else { status = pthread_cond_timedwait(_cond, _mutex, &absTime); - if (status != 0 && WorkAroundNPTLTimedWaitHang) { - pthread_cond_destroy(_cond); - pthread_cond_init(_cond, NULL); - } } assert_status(status == 0 || status == EINTR || status == ETIMEDOUT, status, "cond_timedwait"); --- 4349,4358 ----
*** 4440,4467 **** } } void Parker::unpark() { int status = pthread_mutex_lock(_mutex); ! assert(status == 0, "invariant"); const int s = _counter; _counter = 1; if (s < 1) { - if (WorkAroundNPTLTimedWaitHang) { - status = pthread_cond_signal(_cond); - assert(status == 0, "invariant"); - status = pthread_mutex_unlock(_mutex); - assert(status == 0, "invariant"); - } else { status = pthread_mutex_unlock(_mutex); ! assert(status == 0, "invariant"); status = pthread_cond_signal(_cond); ! assert(status == 0, "invariant"); ! } } else { pthread_mutex_unlock(_mutex); ! assert(status == 0, "invariant"); } } // Darwin has no "environ" in a dynamic library. --- 4373,4393 ---- } } void Parker::unpark() { int status = pthread_mutex_lock(_mutex); ! assert_status(status == 0, status, "invariant"); const int s = _counter; _counter = 1; if (s < 1) { status = pthread_mutex_unlock(_mutex); ! assert_status(status == 0, status, "invariant"); status = pthread_cond_signal(_cond); ! assert_status(status == 0, status, "invariant"); } else { pthread_mutex_unlock(_mutex); ! assert_status(status == 0, status, "invariant"); } } // Darwin has no "environ" in a dynamic library.
< prev index next >