On Mon, 2009-12-07 at 12:42 +0200, Pekka Enberg wrote:
> AFAICT entering GC from a JIT trampoline is irrelevant to this 
> discussion. We're really looking at a generic problem where one or more 
> of the threads are already blocked with pthread_mutex_lock() or whatever 
> and we try to stop the world which leads to an instant deadlock. There 
> needs to be some way to wake up the blocked threads and drive them into 
> do_safepoint(). Or alternatively, we need to update nr_running_threads 
> before blocking and fixing make root set detection deal with blocked 
> threads.
> 
> I suspect the latter will lead to better results but I can't yet 
> convince myself that we'll always find references that are stored in 
> registers.

OK, assuming that we can send a signal to a thread that is either running or
blocked in native code with pthread_kill(), I think we can do something like
the following.

The GC root set consists of references in:

  - Class variables

  - Native stack frame of all threads

  - Native registers of all threads

A thread can be in one of the following states:

  - Running JIT'd code

  - Running native code

  - Blocked in JIT'd code (object monitor)

  - Blocked in native code (pthread_mutex_lock(), etc.)

Finding root set references when a thread is running in native code or is
blocked is the most difficult part because when we're running in JIT'd code,
we can simply wait for the thread to enter a safepoint and we're done. This
will happen automatically as the thread polls the guard page at method
invocation or backward branch.

As for the case of a thread running in native code, we know that there has
been a transition from JIT code to native code through a call-site which
always has a GC map attached to it. As all references that are visible to the
native code are either class variables or have been passed as function
arguments (and are part of a GC map), we can detect them. Furthermore, as
native code is only allowed to create new instances through the JNI API, we
can track the new references separately and include them in the root set.
Therefore, we can simply interrupt the thread running in native code with a
signal using pthread_kill() that forces the thread to enter a safepoint.

Blocking in JIT'd code is identical to blocking in native code because the JIT
compiler generates VM native calls for the _monitorenter_ and _monitorexit_
bytecodes and rest of the blocking methods are also implemented as VM native
functions. Fortunately, we can consider the blocked in native code case to be
identical to the running in native code case and rely on the fact that we
entered the native code through a call-site that has a GC map. If we also
force the blocked thread to enter a safepoint through a signal, we can make
sure the thread does not wake up spuriously while it's supposed to be in the
safepoint.

Tomek, what do you think? Am I missing something here?


------------------------------------------------------------------------------
Join us December 9, 2009 for the Red Hat Virtual Experience,
a free event focused on virtualization and cloud computing. 
Attend in-depth sessions from your desk. Your couch. Anywhere.
http://p.sf.net/sfu/redhat-sfdev2dev
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to