Tuesday, November 30, 2010

How to Debug and Detect Deadlocks

Deadlocks in 2 minutes

Deadlocks are software bugs where multiple threads (typically one of them being the main thread) wait indefinitely on common synchronization primitives (locks) because their resolution is mutually interdependent.

Thread A waits on lock L1 to be released, but it held by thread B, who in turns waits on lock L2 to be released while it is held by thread A.

The scenario above is by far the most common source of deadlocks. The fundamental cause is that the locks are acquired in a different order by two different threads, and depending on an unpredictable race condition, can deadlock at runtime.

For example, the following snippet can cause a deadlock when Property.get() and Property.set() are accessed by two different threads:

class Property {
    static final public String DEFAULT_VALUE = "...";
    HashMap map = new HashMap();
    ArrayList listeners = new ArrayList();

    synchronized void set(String key, String value) {
        synchronized (map) {
            map.put(key, value);
        }
        for (Listener listener : listeners)
            listener.notifyChanged();
    }

    String get(String key) {
        synchronized (map) {
            String value = map.get(key);
            if (value == null) {
                value = DEFAULT_VALUE;
                set(key, value);
            }
            return value;
        }
    }
}

When the method Property.set() is called, the lock for "this" and "map" are acquired (using the synchronized keyword), while when Property.get() is called, the locks "map" and "this" are acquired, in the opposite order than Property.set().

This can cause a random deadlock when Property.get() and Property.set() are called from two different threads.

The example illustrate that:

  1. It is easy to write code that has incorrect lock acquisition order.
  2. It is hard to detect such errors, until a deadlock occurs randomly at runtime, and it might not be consistently reproducible.

Considering large source base where thousand of line of code acquire locks and have a very complex code path, it is often nearly impossible to prevent deadlocks from occurring at runtime, at the developer are faced with reducing the concurrency of the software, leading to poor usability, and sub-optimal performance.

Here is where the deadlock preventer tool comes to help.


The Deadlock Preventer

The deadlock preventer is a tool that dynamically instruments the java bytecode of an application when running in a java virtual machine in order to analyze the lock ordering and detect potential deadlocks without the need to rely on unpredictable and unreliable race conditions.

By running the deadlock preventer while executing the java program (the Eclipse IDE in our case) with a good code coverage (basically covering all features that the customers are susceptible to use), we can ensure that the code does not contain incorrect lock order, and is prone to deadlocks at runtime.

When we run the Property class in the example above with the following junit test code:

@Test
public void testProperty() {
    final Property property = new Property();
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            property.get("foo");
        }
    });
    thread.start();
    try {
        thread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    try {
        property.set("bar", "value");
        fail("should throw an exception");
    } catch (RuntimeException e) {
        assertTrue(e.getMessage().contains("ERROR"));
    }
}

We obtain a RuntimeException (as validated by the junit test case - something optional for the deadlock preventer to issue), but also the following error report on the console:

***DEADLOCK PREVENTER*** ERROR: Inconsistent locking order while acquiring lock: java.util.HashMap (id=0) in thread: 1 (main)
Property.set(Main.java:812)
Main.testProperty(Main.java:38)
...
(junit stack)
with predecent : Property (id=1)
Property.set(Main.java:811)
Main.testProperty(Main.java:38)
...
(junit stack)
Previously acquired lock: java.util.HashMap (id=0) in thread: 9 (Thread-0)
Property.get(Main.java:818)
Main$1.run(Main.java:28)
java.lang.Thread.run(Thread.java:619)
Previously acquired precedent: Property (id=1)
Property.set(Main.java:811)
Property.get(Main.java:822)
Main$1.run(Main.java:28)
java.lang.Thread.run(Thread.java:619)

The important aspect is that we receive this error report deterministically, each time the code runs, whether or not the code actually deadlocks at runtime given a race condition (something we made impossible with the thread.join() call).

Once the error is detected, it can then be corrected by the developer.

Note also that the deadlock preventer will report the error whether or not the code is actually susceptible to run concurrently or not, which in our case was impossible because we made the main thread block until the second thread finished execution (something that defeats the purpose to have a separate thread to begin with).

The deadlock preventer can also issue warnings when an inverse lock acquisition is detected in the same thread, but never run in different thread - it is always a good programming practice to have consistent lock order.

Using the deadlock preventer agent in a java program does not change any of the application logic and code path, but it does change its performance characteristics. Specifically, acquiring and releasing locks become computationally expensive. Ricks of actual deadlocks are effectively increased too, since the time spent while an incorrect lock acquisition order is progress is longer, especially if the 'Interactive' setting is used (see below).

Therefor, if the java program deadlocks, the last conflict reported by the deadlock preventer agent will be the out that refers to the deadlock obtained.

Using the Deadlock Preventer Agent

The deadlock preventer agent is available in two forms for two different development role.

  1. As a set of eclipse plugins for developers to test existing code, and investigate potential deadlocks.
  2. As a standalone launcher for testers, to run on a test machine in the background while the Eclipse Workbench is performing automated tests.

The Deadlock Preventer Eclipse integration.

agent_view

The deadlock preventer Eclipse integration consist of 3 plugins that contribute a new view in eclipse, as shown above (the view is accessible from the menu "Menu / Show View/Other..." under the "Other/Deadlock Preventer" section).

The Deadlock Preventer view allows the developer to select an existing launch configuration (only launch configurations for "Eclipse Application" as listed), configure settings, and click "Debug". The debugged Eclipse session will be automatically instrumented, and report any error in the view, under the "Conflicts" tab.

The best way to use the tool for an Eclipse developer, is first to add a breakpoint on the RuntimeException, then use the 'Interactive' mode, which allows to skip over some errors that are not of interest, and throw an exception for the relevant one.

Important: Note that if the 'throw exception' mode is selected, it will cause the code path to divert from the normal execution path, so it could cause sub-sequent errors, and bugs that would not otherwise happen.

Correcting incorrect lock acquisition order

Generally speaking, when two locks (A, B) are acquired in an inverse order by two different code paths susceptible to be called concurrently (i.e. by two different threads), a deadlock can occur.

For example, if thread 1 acquires the locks A and then B, while thread 2 acquires the locks B and then A, a deadlock is possible.

Thread 1: A -> B

Thread 2: B -> A

There are only 2 ways to avoid the problem:

  1. Re-order the lock acquisition, so that both threads acquire the locks in the same order

or

  1. Introduce a third lock, C, and make both threads acquire it before acquiring either A or B.

In the last case, the pattern would become:

Thread 1: C-> A –> B

Thread 2: C-> B -> A

The lock "C" would be in effect a "guard", preventing the locks A and B to be acquired concurrently, and avoiding the deadlock. The deadlock preventer agent recognize such patterns, and do not report any errors.

Obviously, the first solution is optimal, since it does not reduce concurrency as the second does, but it is sometimes impractical to re-order lock acquisition order, especially when access or modification of existing code is not possible.

Needless to say, removing (even partially) the locks is probably not a good solution, since the deadlock preventer agent does not report data corruption due to concurrent data access.

Miscellaneous comments

Running a full instrumented Eclipse workbench while the deadlock preventer agent analyzes the lock acquisition order, especially through the debugger, is demanding in computational resources. A recent (preferably 4 core or more) CPU is highly recommended.


Not all causes of deadlocks are detected at the moment by the deadlock preventer engine, such as Semaphore release leaks, or async execution from a background thread to the main thread.

(source code of the deadlock preventer to be posted within a few days)

Friday, April 16, 2010

Use the new Resource Filters in 3.6M7 and JDK 1.7 to simulate snapshots

Suppose you are working in a project in Eclipse, but after updating from your source control server, new files were populated in your workspace that cause some build errors.

How to continue to work in your project without being temporarily distracted by the newly created files?

In Eclipse 3.6, Helios, some new powerful features were added to the Eclipse project management that allows the users to configure exactly what files get to populate a project hierarchy.

By using the new Resource Filter feature (improved in M7), the user can either include only or exclude all files based on a rich set of configurable and extensible filters.

When running on JDK 1.7, another condition is available for filtering, the file creation date.

By creating a resource filter that excludes all files having a creation date newer than a given date, you can prevent those files from even appearing in the workspace, so they not be seen by JDT and generate build errors.

The condition for filtering files and folders are broad, including file name, location, workspace path, last modified, file length, etc... The user can also group those condition in logical prepositions with and, or, and not operators.

3rd party plugins can even contribute new matchers through a core.resources extension point to further extend the filtering ability available to the user (think filtering by CVS status, etc...).

Wednesday, March 31, 2010

Tip: How to Debug SWT components in Modal Dialogs

SWT and JFace components, and especially layouts can be quite time consuming to debug when some unexpected behavior is observed at runtime.

Some tools (such as the YARI tool set) can be used to debug SWT components and layouts at runtime, but when modal dialogs are displayed, such tools can't be used because the developer can't setup the inspector window and inspect the components in the list while the dialog is up.

To resolve this issue, one can

  1. Detach the inspector view so it displays in a floating window outside of the workbench.
  2. Put a breakpoint in the modal dialog source code, few lines after the setShellStyle() call, with a breakpoint condition so that it removes the MODAL SWT flag.

For example, for making the WizardDialog non modal, a breakpoint with the following condition:

   setShellStyle(SWT.CLOSE | SWT.MAX | SWT.TITLE | SWT.BORDER       
      | SWT.RESIZE | getDefaultOrientation());    
   return false; 

needs to be added to the "setWizard(newWizard)" line below:

   public WizardDialog(Shell parentShell, IWizard newWizard) {
       super(parentShell);       
       setShellStyle(SWT.CLOSE | SWT.MAX | SWT.TITLE | SWT.BORDER
               | SWT.APPLICATION_MODAL | SWT.RESIZE | getDefaultOrientation());
       setWizard(newWizard); 

This way, you will be able to debug the SWT components at runtime even in modal dialogs:



Wednesday, April 1, 2009

EclipseCon last week was quite rewarding. The talks were great and finally being able to meet face to face with the people I've been collaborating with for the last year is priceless.

Here's a video I made of the talk I gave on Tuesday about the e4 project file structure improvements:


Note that the format isn't ideal, since it contains screenshots that are hard to read in the youtube format.

The slides (without audio) are available below (best seen in full screen mode):


Monday, February 2, 2009

Hello to Planet Eclipse

Hello all Planet Eclipse readers :)

My blog has just been included today, so I'd like to say two words to introduce myself.

I've been working for Metrowerks/Motorola now Freescale since the old days of CodeWarrior on the C/C++ IDE, and with Eclipse since we switched to Eclipse in 2005-2006.

I'm interested in a lot of different components in Eclipse that helps it be a great C/C++ IDE for our customers, and have been especially involved lately in the e4 project (where I am a committer) to bring improvements to the Core Resources plugin so that it can now brag to be more powerful and feature complete than the old CW IDE or Visual Studio - at least in terms of project file structure :)

You can see more of my recents posts in the following links:


I will give a short talk at EclipseCon 2009, so I hope to see a lot of you there, thanks! :)

Friday, January 30, 2009

Latest e4 resource changes

Here is an overview of the changes in the e4 resources available in the latest e4 build:

  1. Editable linked resource locations.

    The user can now conveniently change the location of a linked resource by clicking the "Edit..." button in the resource property page.

  2. Project Linked Resource Variables

    Linked resources that are variable relative can now use a variable list that is defined in the project itself, instead of only relying on the workspace variables. The linked resources can also be specified as relative to the project directory itself, making projects referencing other files outside of the project directory portable across workspace and computers.

  3. Groups
    Groups are virtual folders that the user can use to create an arbitrarily complex logical project independent of the file system hierarchy.

    Groups, as opposed to regular folders, do not exist on the file system and therefor a) do not pickup any additional resources underneath them when a refreshLocal() is performed, and b) can only contain other groups or linked resources as children.

    Groups are fully compatible with the existing 3.4 Core Resource API, and all plugins work just as expected. Groups are seen internally by clients as an linked resource folder with an invalid location (that returns null from getLocation()).

  4. Resource Filters
    Resource filters can be added on any project, folder, linked resource folder or group to automatically build the project structure by limiting what files and folders are visible to the resource workspace layer when a refreshLocal() is performed.

    Resource filters is a powerful feature that allows an Eclipse project to include folders that contains thousands of elements, but only including a fraction of them in the project. As opposed to UI view filters, resource filters are applied at the lowest level, and do not cause resources to be wasted for elements excluded from the directory.

  5. Drag and Drop auto-generation of linked resources


    (A somewhat better version of the video is available here)



    When files are dragged and dropped from Windows Explorer on a projet in the Navigator, the user can choose either to
    1. Copy the files under the target directory (the previous operation)
    2. Create a hierarchy of groups and linked resources replicating the file system file and folder hierarchy<
    3. Create only linked resources

     Linked resources can also be creating when dragging resources from one project to another, transparently transfering the path variables the linked resource might be referring to.  

    Note that this linked-resource drag and drop awareness is currently only available to the Navigator view. 

  6. Linked Resource Editor

    Under the new Linked Resource project property page, a new Linked Resources tab is available. This tab shows a list of all resources in the project, and group them by their location path, being either invalid (for broken paths), absolute paths (which makes them non-portable) and correct paths.

    The user can then easily see which linked resource requires modification, and change it directly in the dialog by choosing the "Edit..." button.

    The user can also automatically convert one or many linked resources to absolute or relatives paths by clicking on the Convert Relative/Absolute button. This command will automatically generate linked resources if needed and try to make the path as portable as possible.

Thursday, January 22, 2009

Flexible Project Improvements in e4

Several improvements to the Core Resources have been made for e4.

Installing the new build

In order to try them out, go to the following web site:

http://download.eclipse.org/e4/downloads/

Select a recent build, and use the link under the "update" column to use in an Eclipse 3.5M4 installation in the UI available from the menu "Help | Install New Software ...".

Once the "Install" dialog comes up, click on "Add Site..." and enter the update site you selected from the download page ( http://download.eclipse.org/e4/downloads/drops/I20090108-1930/repository for example).


The list will refresh, and you can them select the item "org.eclipse.e4.resources.feature" and click "Next, "Finish", etc...

This will enable all the current e4 Core Resources in the current 3.5M4 layout.

more to come...