Synchronizing JDWP startup

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux Kernel]     [Linux Cryptography]     [Fedora]     [Fedora Directory]     [Red Hat Development]

  Powered by Linux