JDK-8212173 : Thread._stack_base/_stack_size initialized too late for new threads
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 12
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2018-10-15
  • Updated: 2019-10-15
  • Resolved: 2018-10-26
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.
JDK 11 JDK 12
11.0.3Fixed 12 b18Fixed
Description
Thread._stack_base/_stack_size are initialized in the Thread child classes' implementation of Thread.run(), typically right at the beginning. Still this is too late since by that time the new Thread has already been added to the Threads list. 

Code iterating that list by e.g. Threads::do_threads() may see the Thread object without stack information. Also, accessing Thread::stack_size() will assert in that case. 

Prior discussion: http://mail.openjdk.java.net/pipermail/hotspot-runtime-dev/2018-October/030516.html

--

Details:

During initialization of newborn (created by VM) threads, things happen in the following sequence (on Linux and BSD):


(parent thread)
JVM_StartThread
	calls new JavaThread
		calls os::create_thread()
			- calls pthread_create.
			- Child thread starts.
			- parent thread waits on Child thread coming up (Handshake part 1)
			- child waits. parent continues.
	calls JavaThread::prepare()
		calls Threads::add and adds newly created thread to thread list  (A)
		
	calls Thread::start(Thread)
		calls os::start_thread()
			- wakes up child thread
			- child thread continues to run. Child thread calls <ChildThreadClass>::run(). That function has to be overwritten by every child class. 
			- Inside <ChildThreadClass>::run(), Thread::record_stack_base_and_size() is called which sets Thread::stack_base and Thread::stack_stize. (B)

On Solaris, Windows and AIX the situations is a bit different:


(parent thread)
JVM_StartThread
	calls new JavaThread
		calls os::create_thread()
			- calls pthread_create.
			- Child thread does *not* start but is suspended for now.
			- parent continues.
	calls JavaThread::prepare()
		calls Threads::add and adds newly created thread to thread list  (A)
		
	calls Thread::start(Thread)
		calls os::start_thread()
			- unsuspends the child thread. Child thread starts running for the first time.
			- Child thread calls <ChildThreadClass>::run(). That function has to be overwritten by every child class. 
			- Inside <ChildThreadClass>::run(), Thread::record_stack_base_and_size() is called which sets Thread::stack_base and Thread::stack_stize. (B)

			
Between (A) and (B) the newly created thread is visible when iterating the Threads list, and has no stack dimensions set.


-------------

Solution: move the initialization of Thread::stack_base/stack_size up, before the Thread is added to the Threads list. This is possible on Linux+BSD, but it is not possible on Windows+Solaris+AIX.

We only can get the stack dimensions from within the newly created thread. On Linux+BSD, we have a time window where the newly created child thread runs and is not yet visible from the outside (before the handshake with the parent thread). This time window does not exist on Windows+Solaris+AIX. Even if we move the initialization of Thread::stack_base/stack_size up to the start of thread_native_entry, this is still too late since by that time the thread is already visible via Threads list.





Comments
Fix Request: This bug is important to fix for the same reason it is important to fix in 12: we risk encountering threads with stack boundaries not set when iterating the ThreadList. The fix changes the initialization of newly created threads: We now initialize the members Thread::_stack_size and Thread::_stack_base as soon as possible (at the start of the native entry function). To do that, we hat to move code around a bit, since the function Thread::record_stack_base_and_size() - which does this initialization - was loaded with stuff which needed to be initialized later. The risk is small. The bugfix is live since some weeks in jdk12 and no issues showed up. The patch applies to jdk11u cleanly.
21-11-2018

This proves to be more difficult than I initially thought :/ The problem is that we need to initialize stack base, size from within the newly started thread itself. But on some platforms the thread-start-handshake is differently implemented than on Linux. On Linux, native_thread_entry() starts runnning right away after pthread_create(), and then waits for the handshake. On Solaris/AIX/Windows we simply create the new thread in suspended state, and in os::start_thread(), we resume it. So native_thread_entry() never ran. Now we have a hen-end-egg problem: we want to call Threads::add() before os::start_thread() (I suppose, since the Thread may be short lived and we do not want to add a possibly dead thread to the Threads list). But we do not have the stack dimensions, since the thread on these platforms never ran and hence had no opportunity to initialize Thread::_stack_base/size. Not really sure what to do here: I guess one could replace the resume mechanism on Solaris/Windows/AIx with the type of monitor-based handshake we do on Linux. But that seems heavy handed and may also make thread creation slower.
17-10-2018