Hi Stefan,

Thanks for the clarification.

I investigated into this problem in our user's environment, and found
that it was using Ant-contrib's "forget" task
(http://ant-contrib.sourceforge.net/tasks/tasks/forget.html). The task
simply created a child thread of main ant thread, and using this new
thread to run nested ant tasks in background. I think this might be
the cause. Below are my observation, can you please review and see if
it makes sense.

While "parallel" task provided by ant always makes a new copy of
LocalPropertyStack for the child thread when it enters the run()
method, the ant-contrib "forget" task does not do that. It simply
creates a new thread and perform the task using the thread.

==== from Parallel.java ====
        public void run() {
            try {
                LocalProperties.get(getProject()).copy();
          ....

==== from ForgetTask.java ====
    public void execute()
    {
        Thread t = new Thread(this);
        t.setDaemon(daemon);
        t.start();
    }

    public void run()
    {
        super.execute();
    }

On the other hand, LocalProperties is an InheritableThreadLocal, which
means the parent thread and child threads are sharing the same
LocalPropertyTask. In this case, the child thread that runs nested
tasks is the child of the main Ant thread, thus it actually has the
same LocalThreadStack as main ant thread. So this leads to the
concurrent issue between main ant thread and child forget tasks
thread, or between different child threads of "forget" tasks.

I also wrote below reproducer to verify above thought.

  <target name="run-forget">
    <forget>
      <antcall target="job1" />
    </forget>
    <forget>
      <antcall target="job2" >
        <param name="dummy" value="foo" />
      </antcall>
    </forget>
  </target>

  <target name="job1">
      <property name="dummy" value="job1" />
      <echo message="JOB1: dummy=${dummy}" />
      <sleep seconds="1" />
  </target>

  <target name="job2">
      <property name="dummy" value="job2" />
      <echo message="JOB2: dummy=${dummy}" />
  </target>

When I call above "run-forget" task in a couple times, I get various
of exceptions quite often.

But when I use <parallel> to simulate above, I don't get any problem.
So it seems that "forget" usage was the cause. I guess this task was
wrote before LocalProperties was introduced, and hadn't been updated
since then.

Anyway, with above assumption, I'm going to fix the problem in our
framework by overriding the ant-contrib "forget" task with ours, which
does copy the LocalPropertyStack for new threads. Hopefully, it can
resolve the issue in our environment.

However, I still have a question. Do you think there would be a good
way from Ant side to prevent such concurrent issue happens again. I
mean, we can't stop users from writing custom tasks that can run tasks
in a multithreading way. But can we improve LocalProperties and make
it immune from such usage.

Thanks,
Gan

On Tue, Jan 20, 2015 at 11:11 PM, Stefan Bodewig <bode...@apache.org> wrote:
> On 2015-01-15, Gan Dong wrote:
>
>> Recently, I came across a problem in Ant and the solution seems to
>> write a custom LocalProperties implementation to fix the issue. But I
>> found that this class has a sole privet constructor which prevents me
>> from sub-classing it:
>
>> 55     /**
>> 56      * Construct a new LocalProperties object.
>> 57      */
>> 58     private LocalProperties() {
>> 59     }
>
>> I'd like to know, is such design on purpose? What's the consideration
>> in making it private?
>
> Basically because we never felt this is an extension point we want to
> support.  The class is not meant to be subclassed.
>
>> I know Ant provided a mechanism as following which seems to have the
>> ability to register user-defined LocalProperties class:
>
>> LocalProperties l = (LocalProperties) project.getReference(
>>  MagicNames.REFID_LOCAL_PROPERTIES);
>
> Ah, no.  There should only be a single LocalProperties stack for a
> project and the code above is getting access to that.  Like a global
> variable but hidden behind some smoke and mirrors.
>
>> Some additional context on why I want to extend the class. Due to this
>> ant bug: https://issues.apache.org/bugzilla/show_bug.cgi?id=55074, our
>> framework, which calls ant, occasionally throws
>> ConcurrentModificationException when parallel is used.
>
> I've been meaning to look into this, but failed to find the time to do
> so so far.  LocalPropertyStack is supposed to be used only by a single
> thread at a time, I'm surprised to see the
> ConcurrentModificationException.  Rather than synchronizing the stack
> I'd like to figure out where it leaks outside of its Thread and fix
> that.
>
> Cheers
>
>         Stefan
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscr...@ant.apache.org
> For additional commands, e-mail: user-h...@ant.apache.org
>

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscr...@ant.apache.org
For additional commands, e-mail: user-h...@ant.apache.org

Reply via email to