Tom Tromey wrote: > Instead of sleeping, how about wait/notify? > > In the VM startup: > > if (debugging enabled) > synchronized (whatever) > while (! thread1_started || ! thread2_started) > whatever.wait(); > > Then each thread will synchronize, set their flag, and notify(). For gcj specifically, this won't work because of the finnicky startup procedure. The JDWP threads must be created AND ready before the main user thread starts running. So, for example, calling Object.wait causes a SEGV because there are no threads running yet. If it's a problem in gcj, I figure it's probably a problem in other VMs. Perhaps some code will demonstrate approximately how gcj starts up. Here's _Jv_RunMain from gcj (I've left my original implementation for this intact but ifdef'd out): void _Jv_RunMain (JvVMInitArgs *vm_args, jclass klass, const char *name, int argc, const char **argv, bool is_jar) { #ifndef DISABLE_MAIN_ARGS _Jv_SetArgs (argc, argv); #endif java::lang::Runtime *runtime = NULL; try { if (_Jv_CreateJavaVM (vm_args) < 0) { fprintf (stderr, "libgcj: couldn't create virtual machine\n"); exit (1); } // Get the Runtime here. We want to initialize it before searching // for `main'; that way it will be set up if `main' is a JNI method. runtime = java::lang::Runtime::getRuntime (); #ifdef DISABLE_MAIN_ARGS arg_vec = JvConvertArgv (0, 0); #else arg_vec = JvConvertArgv (argc - 1, argv + 1); #endif // Start JDWP if (remoteDebug) { using namespace gnu::classpath::jdwp; Jdwp* jdwp = new Jdwp (); jdwp->setDaemon (true); jdwp->configure (JvNewStringLatin1 (jdwpOptions)); jdwp->start (); // Wait for JDWP to initialize and start #if 0 while (!gnu::classpath::jdwp::Jdwp::isInitialized ()) { struct timespec t; t.tv_sec = 0; t.tv_nsec = 1000 * 1000 * 50; nanosleep (&t, NULL); } #else gnu::classpath::jdwp::Jdwp::waitForInitialization (); #endif } using namespace gnu::java::lang; if (klass) main_thread = new MainThread (klass, arg_vec); else main_thread = new MainThread (JvNewStringLatin1 (name), arg_vec, is_jar); // Send VmInit gnu::classpath::jdwp::event::VmInitEvent* event; event = new gnu::classpath::jdwp::event::VmInitEvent (main_thread); gnu::classpath::jdwp::Jdwp::notify (event); } catch (java::lang::Throwable *t) { java::lang::System::err->print (JvNewStringLatin1 ("Exception during runtime initialization: ")); java::lang::System::err->println(t); t->printStackTrace(); if (runtime) runtime->exit (1); // In case the runtime creation failed. ::exit (1); } _Jv_AttachCurrentThread (main_thread); if (gnu::classpath::jdwp::Jdwp::isDebugging && gnu::classpath::jdwp::Jdwp::suspendOnStartup ()) { // Suspend this thread for JDWP _Jv_ThreadDebugSuspend (_Jv_ThreadGetData (main_thread)); } _Jv_ThreadRun (main_thread); if (::gnu::classpath::jdwp::Jdwp::isDebugging) { using namespace ::gnu::classpath::jdwp; event::VmDeathEvent* event = new event::VmDeathEvent (); Jdwp::notify (event); } int status = (int) java::lang::ThreadGroup::had_uncaught_exception; runtime->exit (status); // If we got here then something went wrong, as MainThread is not // supposed to terminate. ::exit (1); } As you can see, the startup sequence remains relatively unchanged. We just create some new threads when JDWP is initialized and send two events to indicate that the VM is live/dead. Keith