A bundle that is starting is in the middle of a state change (i.e., RESOLVED->STARTING->ACTIVE), so the framework must hold a lock on that bundle to ensure its state isn't messed with externally why it is in the process of starting. So, when the activator start() method is called, the thread holds a lock for the bundle being started.

When a bundle registers a service, this is also state sensitive, since a bundle can only register a service while it is active. Thus, this requires that we hold a lock on the bundle until the service is registered.

Given your scenario, you have the calling thread holding the bundle lock and the registering thread wanting the bundle lock, so deadlock.

In general, it is not a good thing to spawn another thread which calls back into the framework while blocking the original thread.

-> richard

On 6/9/09 2:53 PM, jgunz wrote:
You're absolutely correct. I oversimplified my use case and made one that
worked. Below is what I'm really trying to do, and I verified it does
deadlock this time. I'm trying to make a safe wrapper around BundleActivator
that makes sure developers don't block in the start() method indefinitely so
we can more quickly diagnose problems during development...


public final static long bundleStartupTimeoutInSeconds = 15;

public void start(final BundleContext bundleContext) throws Exception
{
         final Semaphore bundleStartedSemaphore = new Semaphore(1);
         bundleStartedSemaphore.acquire();

         Thread bundleStartupThread = new Thread(new Runnable(){
             public void run()
             {
                 try
                 {
                     Hashtable properties = new Hashtable();
                     properties.put(Constants.SERVICE_PID,"foo.bar");
                     bundleContext.registerService(Integer.class.getName(),
new Integer(4) , properties);

                     bundleStartedSemaphore.release();
                 }
                 catch(Throwable t)
                 {
                     t.printStackTrace();
                 }
             }
         });

         bundleStartupThread.start();

         if(!bundleStartedSemaphore.tryAcquire(bundleStartupTimeoutInSeconds,
TimeUnit.SECONDS))
         {
             bundleStartupThread.interrupt();

             String message =
                 "Bundle start-up timeout exceeded
("+bundleStartupTimeoutInSeconds+" secs) " +
                 "when starting bundle
'"+bundleContext.getBundle().getSymbolicName()+"'.";

             throw new TimeoutException(message);
         }
}

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to