5347 // -1 : thread is blocked, i.e. there is a waiter |
5347 // -1 : thread is blocked, i.e. there is a waiter |
5348 // 0 : neutral: thread is running or ready, |
5348 // 0 : neutral: thread is running or ready, |
5349 // could have been signaled after a wait started |
5349 // could have been signaled after a wait started |
5350 // 1 : signaled - thread is running or ready |
5350 // 1 : signaled - thread is running or ready |
5351 // |
5351 // |
5352 // Beware -- Some versions of NPTL embody a flaw where pthread_cond_timedwait() can |
|
5353 // hang indefinitely. For instance NPTL 0.60 on 2.4.21-4ELsmp is vulnerable. |
|
5354 // For specifics regarding the bug see GLIBC BUGID 261237 : |
|
5355 // http://www.mail-archive.com/debian-glibc@lists.debian.org/msg10837.html. |
|
5356 // Briefly, pthread_cond_timedwait() calls with an expiry time that's not in the future |
|
5357 // will either hang or corrupt the condvar, resulting in subsequent hangs if the condvar |
|
5358 // is used. (The simple C test-case provided in the GLIBC bug report manifests the |
|
5359 // hang). The JVM is vulernable via sleep(), Object.wait(timo), LockSupport.parkNanos() |
|
5360 // and monitorenter when we're using 1-0 locking. All those operations may result in |
|
5361 // calls to pthread_cond_timedwait(). Using LD_ASSUME_KERNEL to use an older version |
|
5362 // of libpthread avoids the problem, but isn't practical. |
|
5363 // |
|
5364 // Possible remedies: |
|
5365 // |
|
5366 // 1. Establish a minimum relative wait time. 50 to 100 msecs seems to work. |
|
5367 // This is palliative and probabilistic, however. If the thread is preempted |
|
5368 // between the call to compute_abstime() and pthread_cond_timedwait(), more |
|
5369 // than the minimum period may have passed, and the abstime may be stale (in the |
|
5370 // past) resultin in a hang. Using this technique reduces the odds of a hang |
|
5371 // but the JVM is still vulnerable, particularly on heavily loaded systems. |
|
5372 // |
|
5373 // 2. Modify park-unpark to use per-thread (per ParkEvent) pipe-pairs instead |
|
5374 // of the usual flag-condvar-mutex idiom. The write side of the pipe is set |
|
5375 // NDELAY. unpark() reduces to write(), park() reduces to read() and park(timo) |
|
5376 // reduces to poll()+read(). This works well, but consumes 2 FDs per extant |
|
5377 // thread. |
|
5378 // |
|
5379 // 3. Embargo pthread_cond_timedwait() and implement a native "chron" thread |
|
5380 // that manages timeouts. We'd emulate pthread_cond_timedwait() by enqueuing |
|
5381 // a timeout request to the chron thread and then blocking via pthread_cond_wait(). |
|
5382 // This also works well. In fact it avoids kernel-level scalability impediments |
|
5383 // on certain platforms that don't handle lots of active pthread_cond_timedwait() |
|
5384 // timers in a graceful fashion. |
|
5385 // |
|
5386 // 4. When the abstime value is in the past it appears that control returns |
|
5387 // correctly from pthread_cond_timedwait(), but the condvar is left corrupt. |
|
5388 // Subsequent timedwait/wait calls may hang indefinitely. Given that, we |
|
5389 // can avoid the problem by reinitializing the condvar -- by cond_destroy() |
|
5390 // followed by cond_init() -- after all calls to pthread_cond_timedwait(). |
|
5391 // It may be possible to avoid reinitialization by checking the return |
|
5392 // value from pthread_cond_timedwait(). In addition to reinitializing the |
|
5393 // condvar we must establish the invariant that cond_signal() is only called |
|
5394 // within critical sections protected by the adjunct mutex. This prevents |
|
5395 // cond_signal() from "seeing" a condvar that's in the midst of being |
|
5396 // reinitialized or that is corrupt. Sadly, this invariant obviates the |
|
5397 // desirable signal-after-unlock optimization that avoids futile context switching. |
|
5398 // |
|
5399 // I'm also concerned that some versions of NTPL might allocate an auxilliary |
|
5400 // structure when a condvar is used or initialized. cond_destroy() would |
|
5401 // release the helper structure. Our reinitialize-after-timedwait fix |
|
5402 // put excessive stress on malloc/free and locks protecting the c-heap. |
|
5403 // |
|
5404 // We currently use (4). See the WorkAroundNTPLTimedWaitHang flag. |
|
5405 // It may be possible to refine (4) by checking the kernel and NTPL verisons |
|
5406 // and only enabling the work-around for vulnerable environments. |
|
5407 |
5352 |
5408 // utility to compute the abstime argument to timedwait: |
5353 // utility to compute the abstime argument to timedwait: |
5409 // millis is the relative timeout time |
5354 // millis is the relative timeout time |
5410 // abstime will be the absolute timeout time |
5355 // abstime will be the absolute timeout time |
5411 // TODO: replace compute_abstime() with unpackTime() |
5356 // TODO: replace compute_abstime() with unpackTime() |
5527 // TODO: properly differentiate simultaneous notify+interrupt. |
5472 // TODO: properly differentiate simultaneous notify+interrupt. |
5528 // In that case, we should propagate the notify to another waiter. |
5473 // In that case, we should propagate the notify to another waiter. |
5529 |
5474 |
5530 while (_Event < 0) { |
5475 while (_Event < 0) { |
5531 status = pthread_cond_timedwait(_cond, _mutex, &abst); |
5476 status = pthread_cond_timedwait(_cond, _mutex, &abst); |
5532 if (status != 0 && WorkAroundNPTLTimedWaitHang) { |
|
5533 pthread_cond_destroy(_cond); |
|
5534 pthread_cond_init(_cond, os::Linux::condAttr()); |
|
5535 } |
|
5536 assert_status(status == 0 || status == EINTR || |
5477 assert_status(status == 0 || status == EINTR || |
5537 status == ETIME || status == ETIMEDOUT, |
5478 status == ETIME || status == ETIMEDOUT, |
5538 status, "cond_timedwait"); |
5479 status, "cond_timedwait"); |
5539 if (!FilterSpuriousWakeups) break; // previous semantics |
5480 if (!FilterSpuriousWakeups) break; // previous semantics |
5540 if (status == ETIME || status == ETIMEDOUT) break; |
5481 if (status == ETIME || status == ETIMEDOUT) break; |
5574 // Wait for the thread associated with the event to vacate |
5515 // Wait for the thread associated with the event to vacate |
5575 int status = pthread_mutex_lock(_mutex); |
5516 int status = pthread_mutex_lock(_mutex); |
5576 assert_status(status == 0, status, "mutex_lock"); |
5517 assert_status(status == 0, status, "mutex_lock"); |
5577 int AnyWaiters = _nParked; |
5518 int AnyWaiters = _nParked; |
5578 assert(AnyWaiters == 0 || AnyWaiters == 1, "invariant"); |
5519 assert(AnyWaiters == 0 || AnyWaiters == 1, "invariant"); |
5579 if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) { |
|
5580 AnyWaiters = 0; |
|
5581 pthread_cond_signal(_cond); |
|
5582 } |
|
5583 status = pthread_mutex_unlock(_mutex); |
5520 status = pthread_mutex_unlock(_mutex); |
5584 assert_status(status == 0, status, "mutex_unlock"); |
5521 assert_status(status == 0, status, "mutex_unlock"); |
5585 if (AnyWaiters != 0) { |
5522 if (AnyWaiters != 0) { |
5586 // Note that we signal() *after* dropping the lock for "immortal" Events. |
5523 // Note that we signal() *after* dropping the lock for "immortal" Events. |
5587 // This is safe and avoids a common class of futile wakeups. In rare |
5524 // This is safe and avoids a common class of futile wakeups. In rare |
5755 _cur_index = REL_INDEX; // arbitrary choice when not timed |
5692 _cur_index = REL_INDEX; // arbitrary choice when not timed |
5756 status = pthread_cond_wait(&_cond[_cur_index], _mutex); |
5693 status = pthread_cond_wait(&_cond[_cur_index], _mutex); |
5757 } else { |
5694 } else { |
5758 _cur_index = isAbsolute ? ABS_INDEX : REL_INDEX; |
5695 _cur_index = isAbsolute ? ABS_INDEX : REL_INDEX; |
5759 status = pthread_cond_timedwait(&_cond[_cur_index], _mutex, &absTime); |
5696 status = pthread_cond_timedwait(&_cond[_cur_index], _mutex, &absTime); |
5760 if (status != 0 && WorkAroundNPTLTimedWaitHang) { |
|
5761 pthread_cond_destroy(&_cond[_cur_index]); |
|
5762 pthread_cond_init(&_cond[_cur_index], isAbsolute ? NULL : os::Linux::condAttr()); |
|
5763 } |
|
5764 } |
5697 } |
5765 _cur_index = -1; |
5698 _cur_index = -1; |
5766 assert_status(status == 0 || status == EINTR || |
5699 assert_status(status == 0 || status == EINTR || |
5767 status == ETIME || status == ETIMEDOUT, |
5700 status == ETIME || status == ETIMEDOUT, |
5768 status, "cond_timedwait"); |
5701 status, "cond_timedwait"); |
5784 } |
5717 } |
5785 } |
5718 } |
5786 |
5719 |
5787 void Parker::unpark() { |
5720 void Parker::unpark() { |
5788 int status = pthread_mutex_lock(_mutex); |
5721 int status = pthread_mutex_lock(_mutex); |
5789 assert(status == 0, "invariant"); |
5722 assert_status(status == 0, status, "invariant"); |
5790 const int s = _counter; |
5723 const int s = _counter; |
5791 _counter = 1; |
5724 _counter = 1; |
5792 if (s < 1) { |
5725 // must capture correct index before unlocking |
5793 // thread might be parked |
5726 int index = _cur_index; |
5794 if (_cur_index != -1) { |
5727 status = pthread_mutex_unlock(_mutex); |
5795 // thread is definitely parked |
5728 assert_status(status == 0, status, "invariant"); |
5796 if (WorkAroundNPTLTimedWaitHang) { |
5729 if (s < 1 && _cur_index != -1) { |
5797 status = pthread_cond_signal(&_cond[_cur_index]); |
5730 // thread is definitely parked |
5798 assert(status == 0, "invariant"); |
5731 status = pthread_cond_signal(&_cond[index]); |
5799 status = pthread_mutex_unlock(_mutex); |
5732 assert_status(status == 0, status, "invariant"); |
5800 assert(status == 0, "invariant"); |
|
5801 } else { |
|
5802 // must capture correct index before unlocking |
|
5803 int index = _cur_index; |
|
5804 status = pthread_mutex_unlock(_mutex); |
|
5805 assert(status == 0, "invariant"); |
|
5806 status = pthread_cond_signal(&_cond[index]); |
|
5807 assert(status == 0, "invariant"); |
|
5808 } |
|
5809 } else { |
|
5810 pthread_mutex_unlock(_mutex); |
|
5811 assert(status == 0, "invariant"); |
|
5812 } |
|
5813 } else { |
|
5814 pthread_mutex_unlock(_mutex); |
|
5815 assert(status == 0, "invariant"); |
|
5816 } |
5733 } |
5817 } |
5734 } |
5818 |
5735 |
5819 |
5736 |
5820 extern char** environ; |
5737 extern char** environ; |