ant-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bugzi...@apache.org
Subject DO NOT REPLY [Bug 45194] New: deadlock with parallel task and custom BuildListener
Date Thu, 12 Jun 2008 18:28:53 GMT
https://issues.apache.org/bugzilla/show_bug.cgi?id=45194

           Summary: deadlock with parallel task and custom BuildListener
           Product: Ant
           Version: 1.7.0
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: critical
          Priority: P2
         Component: Core
        AssignedTo: notifications@ant.apache.org
        ReportedBy: greg.schueler+bugzilla.asf@gmail.com


If a custom BuildListener retrieves a project property value inside the
messageLogged() method, this can cause a deadlock when the ParallelTask is
used, even in simple cases.  

In essence: Project.log locks the Project instance, and build listeners that
access synchronized PropertyHelper methods will then lock the PropertyHelper
instance: lock(Project) -> lock(PropertyHelper).  The race occurs when another
thread calls a synchronized method in PropertyHelper (e.g.
Project.getProperty()) since many of the PropertyHelper methods call
project.log: lock(PropertyHelper) -> lock(Project).

Perhaps this is a caveat of using the Parallel task, but I think that accessing
project properties (read-only) inside BuildListener.messageLogged should be
made safe in this situation, since this can occur in the simplest usage of the
parallel task.

This is a race condition on the Project object and its PropertyHelper instance:
 fireMessageLoggedEvent in Project locks the Project prior to notifying
BuildListeners.  And the synchronized method PropertyHelper.setNewProperty() 
can call Project.log which invokes fireMessageLoggedEvent which locks the
Project.  Thus if a BuildListener invokes the synchronized method
PropertyHelper.getProperty() it will attempt to lock the PropertyHelper,
causing a race condition if two threads are running.

1. Project.fireMessageLoggedEvent -> synchronized(Project) ->
BuildListener.messageLogged -> synchronized PropertyHelper.getProperty()

2. synchronized PropertyHelper.setNewProperty  -> Project.log ->
Project.fireMessageLoggedEvent -> synchronized(Project)

This can be reproduced with a simple <parallel> task with a few threads that
just set property values and use the <echo> task.  Additionally, running ant in
debug mode will cause extra Project.log() calls inside
PropertyHelper.setProperty() which also may trigger deadlock.

Perhaps the solution is to remove the calls to project.log inside the
synchronized methods of PropertyHelper?    Otherwise there should be a lock on
the Project instance prior to calling any of PropertyHelper's synchronized
methods.  

Running the following build with the custom TestBL BuildListener reaches
deadlock after a few attempts:

TestBL.java:

import org.apache.tools.ant.BuildListener;
import org.apache.tools.ant.BuildEvent;

public class TestBL implements BuildListener{
    public void messageLogged(BuildEvent event) {
        String blahval = event.getProject().getProperty("blah");
        String blahval2 = event.getProject().getProperty("blah2");
        String blahval3 = event.getProject().getProperty("blah3");
        String blahval4 = event.getProject().getProperty("blah");
        String blahval5 = event.getProject().getProperty("blah2");
        String blahval6 = event.getProject().getProperty("blah3");
        String blahval7= event.getProject().getProperty("blah");
        String blahval8 = event.getProject().getProperty("blah2");
        String blahval9 = event.getProject().getProperty("blah3");
    }
    public void buildStarted(BuildEvent event) { }
    public void buildFinished(BuildEvent event) { }
    public void targetStarted(BuildEvent event) { } 
    public void targetFinished(BuildEvent event) { } 
    public void taskStarted(BuildEvent event) { } 
    public void taskFinished(BuildEvent event) { }
}


build.xml:

<project name="test" default="execute">
    <target name="execute">
        <parallel threadCount="3">
            <sequential>
                <property name="blah" value="blahblah 1"/>
                <property name="blaha" value="blahblah 1"/>
                <property name="blahb" value="blahblah 1"/>
                <echo>This is a test 1: ${blah}</echo>
            </sequential>
            <sequential>
                <echo>This is a test 2: ${blah2}</echo>
                <echo>This is a test 2: ${blah2}</echo>
                <echo>This is a test 2: ${blah2}</echo>
                <property name="blah2" value="blahblah 2"/>
                <property name="blah2" value="blahblah 2"/>
                <property name="blah2" value="blahblah 2"/>
            </sequential>
            <sequential>
                <echo>This is a test 3: ${blah3}</echo>
                <echo>This is a test 3: ${blah3}</echo>
                <echo>This is a test 3: ${blah3}</echo>
                <property name="blah3" value="blahblah 3"/>
                <property name="blah3" value="blahblah 3"/>
                <property name="blah3" value="blahblah 3"/>
                <property name="blah3" value="blahblah 3"/>
            </sequential>
        </parallel>
    </target>
</project>

$ javac -classpath ant.jar TestBL.java
$ ant -lib . -listener TestBL -f build.xml


-- 
Configure bugmail: https://issues.apache.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are the assignee for the bug.

Mime
View raw message