ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From peter reilly <peter.rei...@corvil.com>
Subject Re: Macrodef and parallel in a recursive situation
Date Mon, 20 Oct 2003 08:59:07 GMT
I have written the code to support local properties.
While I was doing this, I realized that the attributes
of a macrodef could/should be local properties as well,
removing some of the issues seen last week (use of
attribute in a bsf script and support of parallel/recursive).

The following shows it in using a new task called local.

<project name="local">
  <property name="prop1" value="a global value"/>
  <target name="test1">
    <local name="prop1" value="a local value"/>
    <echo>prop1 is "${prop1}"</echo>
  </target>
  <target name="test2" depends="test1">
    <echo>prop1 is "${prop1}"</echo>
  </target>
</project>

This ant test2 generates the following:

test1:
prop1 is "a local value"

test2:
prop1 is "a global value"

Each taskcontainer sets up a new local scope:

  <target name="sequential">
    <local name="prop2" value="in target"/>
    <sequential>
      <local name="prop2" value="in sequential"/>
      <echo>prop2 is "${prop2}"</echo>
    </sequential>
    <echo>prop2 is "${prop2}"</echo>
  </target>

will generate the following:
sequential:
prop2 is "in sequential"
prop2 is "in target"

The value part of <local> is optional, and  the local
property may be set by a subsequent <property>, <property>
will only set it if the value is not set.

  <target name="notset">
    <local name="prop3"/>
    <echo>prop3 is "${prop3}"</echo>
    <property name="prop3" value="is set"/>
    <property name="prop3" value="is set again"/>
    <echo>prop3 is "${prop3}"</echo>
  </target>

will generate the following:
notset:
prop3 is "${prop3}"
prop3 is "is set"

prop3 is still a local variable and will not be seen outside the target.

The local properties are thread local so the following works as expected:
  <target name="parallel">
    <local name="prop4"/>
    <parallel>
      <sequential>
        <property name="prop4" value="thread1"/>
        <echo>t1: prop4 is "${prop4}"</echo>
      </sequential>
      <sequential>
        <property name="prop4" value="thread2"/>
        <echo>t2: prop4 is "${prop4}"</echo>
      </sequential>
      <sequential>
        <property name="prop4" value="thread3"/>
        <echo>t3: prop4 is "${prop4}"</echo>
      </sequential>
    </parallel>
  </target>

parallel:
t2: prop4 is "thread2"
t1: prop4 is "thread1"
t3: prop4 is "thread3"

Use with macrodef.
-----------------

Attributes may now be implemented as local properties, which means that
they will be seen as normal properties by ant tasks - including script.

  <target name="macro">
    <macrodef name="callscript">
      <attribute name="x"/>
      <sequential>
        <script language="beanshell">
          System.out.println("x is '" + project.getProperty("x") + "'");
        </script>
      </sequential>
    </macrodef>

    <callscript x="this is x"/>
  </target>

will generate:
macro:
x is 'this is x'

Macrodef does not do the attribute substitutions so the following
  <target name="macro2">
    <macrodef name="callscript">
      <attribute name="x"/>
      <sequential>
        <script language="beanshell">
          System.out.println("x is '${x}'");
        </script>
      </sequential>
    </macrodef>

    <callscript x="this is x"/>
  </target>
will generate:
macro2:
x is '${x}'
as <script/> does not do property expansion.

A variation of the recurive macrodef last week may be done by:
  <target name="recur">
    <macrodef name="recur">
      <attribute name="thread"/>
      <attribute name="current"/>
      <sequential>
        <antcontrib:if>
          <equals arg1="0" arg2="${current}"/>
          <then>
            <echo message="Thread: ${thread} done"/>
          </then>
          <else>
            <antcontrib:math
              datatype  = "int"
              operand1  = "${current}"
              operation = "-"
              operand2  = "1"
              result    = "current"
              />
            <echo message = "T: ${thread}, C: ${current}" />
            <sleep seconds="1"/>
            <recur current = "${current}" thread  = "${thread}" />
          </else>
        </antcontrib:if>
      </sequential>
    </macrodef>
    
    <parallel>
      <recur thread="1" current="5"/>
      <recur thread="2" current="6"/>
      <recur thread="3" current="2"/>
    </parallel>
  </target>

The output is:
recur:
T: 3, C: 1
T: 1, C: 4
T: 2, C: 5
T: 3, C: 0
T: 1, C: 3
T: 2, C: 4
Thread: 3 done
T: 1, C: 2
T: 2, C: 3
T: 1, C: 1
T: 2, C: 2
T: 1, C: 0
T: 2, C: 1
Thread: 1 done
T: 2, C: 0
Thread: 2 done



I realize that it is late in the day to get this
into ant1.6, but I think that it will make macrodef
much more usefull and easy to port current antcalls.

The changes are quite small (mostly to PropertyHelper).

Peter

On Saturday 18 October 2003 16:22, Jose Alberto Fernandez wrote:
> > From: peter reilly [mailto:peter.reilly@corvil.com]
> >
> > I think that we may need a thread local variable to
> > handle parallel.
> >
> > This would mean some deep messing with the Property handling.
>
> I do not see how thread locals would help here. I guess the
> question is whether tasks in parallel should be able to modify
> the global properties in the frame, or should the changes be
> local to the parallel branch (and somehow joined at the end of
> execution).
>
> That would mean each parallel computation branch is
> independent. I guess I am suggesting the second type of
> implementation proposed for <local-property> to be used instead
> for <parallel>. I think that would be a much more efficient way
> to do it. So here is how it would work:
>
> 1) Add new attribute independent (default false) to <parallel>.
>
> 2) When independent is true, each thread will use a cloned project
> frame for its execution. So all properties and reference manipulation
> will be independent of each other. When the thread ends, any new
> properties added in the cloned frame, will be added to the original
> parent frame, following the common rules for setting properties.
> Which means that the first thread that finish will win on setting
> the property, if another thread ends later and tries to set the same
> variable, it will loose. For references, we need to copy any changes
> and due to its semantics all threads will contribute as they end.
>
> 3) When independent is false, parallel works as today (for backward
> compatibility), all threads see each others changes.
>
> This rules seem easy programable without big changes to CORE.
>
> I would still like having <local-property> which could be implemented
> as per the first description proposed below.
>
> Jose Alberto
>
> > Peter
> >
> > On Friday 17 October 2003 17:57, Jose Alberto Fernandez wrote:
> > > > From: peter reilly [mailto:peter.reilly@corvil.com]
> > > >
> > > > I would rather have Jose's idea of a <local-property/> task.
> > > >
> > > > This could be used outside of macrodef.
> > > >
> > > > The only problem is the implementation.
> > >
> > > Indeed, there is an easy implementation but will not solve
> >
> > the case of
> >
> > > <parallel>, because the local definition would really be a
> >
> > temporary
> >
> > > global one:
> > >
> > > public class LocalProperty extends Sequential {
> > >   private String property;
> > >   private String oldValue;
> > >
> > >   public setName(String i_property){property = i_property;}
> > >
> > >   public void execute() {
> > >     if (property == null) throw new BuildException("name
> >
> > attribute is
> >
> > > mandatory");
> > >     try {
> > >       oldValue = getProject().getProperty(property);
> > >       getProject().setProperty(property, null); // This may need
> > > changes to core
> > >       super.execute();
> > >     }
> > >     finally {
> > >       // This is using the deprecated setProperty method
> > >       // that actually changes the properties even if set
> > >       getProject().setProperty(property, oldValue);
> > >     }
> > >   }
> > > }
> > >
> > > Here we just change the property value on the project
> >
> > frame, for the
> >
> > > duration of the task. And put the old value back before we leave.
> > >
> > > The problem with this simple implementation is that all the
> >
> > parallel
> >
> > > branches will see the change, which is exactly what we were
> >
> > trying to
> >
> > > avoid. To do it
> > > right, we would need to create a new execution frame that
> >
> > would be use
> >
> > > in the
> > > "super" call.
> > >
> > > But if we do that (which is like what <ant> or <antcall> do), what
> > > happens if the user defines properties other than the
> >
> > local-property
> >
> > > inside the code?
> > > Somehow, we would need to find them and propagate them back
> >
> > to the frame
> >
> > > above
> > > upon exit.
> > >
> > >   <local-property name="x">
> > >    <property name="y" value="myY"/>
> > >   <local-property>
> > >   <echo message="${y}"/>
> > >
> > > [echo] myY
> > >
> > > Doable, but not that easy anymore.
> > >
> > > What do you guys think?
> > >
> > > Jose Alberto
> > >
> > > > Peter
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
> For additional commands, e-mail: dev-help@ant.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Mime
View raw message