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