Bug 225891 - Deadlock due to synchronization in the org.eclipse.equinox.log bundle's Activator's stop(BundleContext) method
Summary: Deadlock due to synchronization in the org.eclipse.equinox.log bundle's Activ...
Status: RESOLVED FIXED
Alias: None
Product: Equinox
Classification: Eclipse Project
Component: Compendium (show other bugs)
Version: 3.4   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.4 M7   Edit
Assignee: equinox.compendium-inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords: contributed, greatbug
Depends on:
Blocks:
 
Reported: 2008-04-06 00:43 EDT by Simon Archer CLA
Modified: 2008-04-08 13:12 EDT (History)
1 user (show)

See Also:


Attachments
An example project that demonstrates the problem. (4.20 KB, application/octet-stream)
2008-04-06 00:52 EDT, Simon Archer CLA
no flags Details
Patch to org.eclipse.equinox.log.Activator (2.14 KB, patch)
2008-04-06 00:53 EDT, Simon Archer CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Simon Archer CLA 2008-04-06 00:43:23 EDT
Using Eclipse 3.4 M6.

While stopping the org.eclipse.equinox.log bundle it is possible for a deadlock to happen due to too much synchronization in the bundle Activator's stop(BundleContext) method.  When a bundle unregisters a service the OSGi framework dispatches events, so holding a lock at this time can cause a deadlock.

Today, the stop(BundleContext) method signature includes the synchronized keyword, making the entire method synchronized.  The scope of the synchronization should not include the unregistration of the various services.

I shall attach a patch to the bundle's Activator that:

1. Replaces the synchronized keyword in the method signature with a block of
   synchronized code.

2. Moves the unregistration of the various services to the top of the method
   and placed them outside of the block of synchronized code.


-- Steps to Reproduce --

0.  Unzip the attached example project zip directly into an Eclipse
    workspace and import the project using File > Import... > Existing
    Project into Workspace.

1.  Place a breakpoint on line 37 of the Counter example class.

2.  Place a breakpoint on line 45 of the ServiceComponent example class.

3.  In the com.sample.counter project, debug using the file
    /launch/Counter.launch file.

4.  Upon execution the "Counter" thread will hit the breakpoint in step 1.

5.  At the Equinox console type ss.  The bundles should be as follows:

  0	ACTIVE      org.eclipse.osgi_3.4.0.v20080326
  1	ACTIVE      org.eclipse.equinox.util_1.0.0.v20080303
  2	ACTIVE      org.eclipse.equinox.log_1.1.0.v20080303
  3	ACTIVE      com.sample.counter_1.0.0
  4	ACTIVE      org.eclipse.osgi.services_3.1.200.v20071203
  5	ACTIVE      org.eclipse.equinox.ds_1.0.0.v20080310

6.  Use the console's stop command to stop the org.eclipse.equinox.log
    bundle.

7.  The "OSGi Console" thread will hit the breakpoint in step 2. Do not
    touch this thread yet.

8.  Back on the "Counter" thread, step into the log(int, String) method:
      logService.log(LogService.LOG_INFO, message);

9.  Continue stepping over the next couple of lines until you are on the
    line:
      tempLog.log(level, message, bundle, null, null);

10. Step into this line. You'll now be in the org.eclipse.equinox.log
    bundle's Activator.

11. Keep stepping over lines until you are inside the synchronized block.
    Due to a previously held lock you will not be able to step in to the
    synchronized block, but try.

12. Go back to the "OSGi Console" thread and step into the line:
      counter.unbind(logService);

13. Keep stepping over until you are inside the synchronized. Due to a
    previously held lock you will not be able to step in to the
    synchronized block, but try.

14. You are now deadlocked. The "OSGi Console" thread hold the Acviator's
    lock first, then it tries to hold the Counter's lock. The "Counter"
    thread holds the Counter's lock first, then it tries to hold the
    Activator's lock.

15. You can confirm the deadlock by suspending the "OSGi Console" thread and
    the "Counter" thread.  Also, the console is unresponsive.


The cause of the problem is that the org.eclipse.equinox.log bundle's Activator is holding a lock on "this" while unregistering its services, which prevents the Counter class' thread from cleanly finishing up.

The Counter class has appropriate synchronization to ensure that the LogService is not pulled out from under it.  The LogService is an optional service and is bound dynamically to the Counter using a DS service component.  This is just background information that is not part of the bug itself.  This is not a DS problem.
Comment 1 Simon Archer CLA 2008-04-06 00:52:34 EDT
Created attachment 94984 [details]
An example project that demonstrates the problem.
Comment 2 Simon Archer CLA 2008-04-06 00:53:40 EDT
Created attachment 94985 [details]
Patch to org.eclipse.equinox.log.Activator
Comment 3 Thomas Watson CLA 2008-04-07 09:28:35 EDT
Look at for M7.
Comment 4 Thomas Watson CLA 2008-04-08 12:27:30 EDT
Patch looks good.  As always thanks for the great bug description Simon.  Marking as greatbug and contributed.
Comment 5 Simon Archer CLA 2008-04-08 13:12:58 EDT
Thank you Tom, it's my pleasure.