JDK-4776858 : regression: java_suspend_self() has race with external suspend
  • Type: Bug
  • Component: vm-legacy
  • Sub-Component: jvmdi
  • Affected Version: 1.4.2
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: solaris_8
  • CPU: sparc
  • Submitted: 2002-11-11
  • Updated: 2002-11-19
  • Resolved: 2002-11-19
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.2 mantisFixed
Related Reports
Relates :  
Description
###@###.### 2002-11-11

JavaThread::java_suspend_self() has a race with a subsequent external
suspend request. I believe this race has been lying dormant in the code
since we implemented the self-suspend logic (in Ladybird?). Mantis-B05
contains a fix for the following bug:

4683006 3/3 3rd party memory managers risk deadlock with JVMDI/JVMPI/JVM_Suspend

This fix stops using forced suspension with native threads which is the
right thing to do. However, there is an unfortunate side effect of
exposing this race. The fix for 4683006 is _not_ broken! It merely
exposes a race condition. The condition appears to be pretty rare. I've
only seen it on my Ultra-80 2x450MHZ machine running Solaris 8 with the
java_g PepTest stress test. It has not been seen on any other stress
test config nor on any other OS platform.

sampler                       target
============================  ===========================================
SuspendThreadList()                :
  enter(SR_lock)                   :
  set_external_suspend()           :
  exit(SR_lock)                    :
  :                           post_event()
  :                             ThreadToNativeFromVM
  :                               handle_special_runtime_exit_condition()
  :                                 if (is_external_suspend_with_lock() {
  :                                   StateSaver sv
  :                                   java_suspend_self() {
  :                                     enter(SR_lock)
  :                                     set_self_suspended()
  :                                     while (is_self_suspended())
  :                                       SR_lock.wait()
  java_suspend(target)                    :
    VM_ThreadSuspend                      :
  VM_ForceSafepoint                       :
                                          :
GetCallTrace()                            :
  wait_for_ext_suspend...()               :
  fill_call_trace()                       :
                                          :
ResumeThreadList()                        :
  enter(SR_lock)                          :
  clear_external_suspend()                :
  if (is_self_suspended()) {              :
    clear_self_suspended();               :
    SR_lock->notify_all();                : notify received but
  }                                       : thread doesn't run
                                          :
SuspendThreadList()                       :
  enter(SR_lock)                          :
  set_external_suspend()                  :
  exit(SR_lock)                           :
  java_suspend(target)                    :
    VM_ThreadSuspend                      :
  VM_ForceSafepoint                       :
                                          :
GetCallTrace()                            :
  wait_for_ext_suspend...()               :
  fill_call_trace()                       : thread runs finally
  :                                       : reenter SR_lock
  :                                       : sees no longer self suspended
  :                                     exit(SR_lock)
  :                                   } // end java_suspend_self()
  : sampler thread crashes          // StateSaver destructor called here
  : at this point                   // which whacks the _post_Java_state
  :                                 // field while sampler is walking
  :                                 } // end if (is_external_suspend...()
  :                               } // end handle_special_....()
  :
  :                             <hprof-code>
  :                               raw_monitor_enter()
  :                                 enter(SR_lock)
  :                                 while (is_external_suspend())
  :                                   exit(SR_lock)
  :                                   {
  :                                   StateSaver sv
  :                                   // this StateSaver makes the thread
  :                                   // look okay
  :                                   java_suspend_self() {
  :                                     enter(SR_lock)
  :                                     set_self_suspended()
  :                                     while (is_self_suspended())
  :                                       SR_lock.wait()
  :                                       // we find target thread here

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mantis FIXED IN: mantis INTEGRATED IN: mantis
14-06-2004

EVALUATION ###@###.### 2002-11-11 The description pretty much says it all. One way to verify that the race exists it to add: guarantee(!this->is_external_suspend(), "XXX - we have a race"); after the pd_self_suspend() call in java_suspend_self().
11-06-2004

PUBLIC COMMENTS .
10-06-2004

SUGGESTED FIX ###@###.### 2002-11-11 See attached 4776858-webrev.tar for the proposed (pre-code review) fix.
11-11-2002