Routine / AppClock broken

View: New views
8 Messages — Rating Filter:   Alert me  

Routine / AppClock broken

by Sciss :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

hi,

Routine or AppClock is really broken.

{ thisFunction.canCallOS.postln }.fork( AppClock )

--> true


fork { { thisFunction.canCallOS.postln }.fork( AppClock )}

--> false


this is probably related to the problem that you cannot use  
Condition.wait inside a Routine that runs on AppClock without braking  
the canCallOS property.

i think this very secure, so i put it in the bug tracker. hope this  
can be found ......

ciao, -sciss-


_______________________________________________
sc-users mailing list

info (subscribe and unsubscribe): http://swiki.hfbk-hamburg.de:8888/MusicTechnology/880
archive: http://www.listarc.bham.ac.uk/marchives/sc-users/
search: http://www.listarc.bham.ac.uk/lists/sc-users/search/

Re: Routine / AppClock broken

by James Harkins-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Expand your function this way...

fork { thisThread.dump; thisThread.clock.dump; { thisThread.dump;
thisThread.clock.dump; thisFunction.canCallOS.postln }.fork( AppClock
)}

... and it becomes evident that canCallOS is doing exactly what it
should. The inner .fork(AppClock) is not behaving correctly, though.

I don't know why but the inner fork is going onto TempoClock.default.
Since it is on a tempoclock, naturally canCallOS should return false.

hjh


On Mon, Jul 21, 2008 at 3:13 PM, Sciss <contact@...> wrote:

> hi,
>
> Routine or AppClock is really broken.
>
> { thisFunction.canCallOS.postln }.fork( AppClock )
>
> --> true
>
>
> fork { { thisFunction.canCallOS.postln }.fork( AppClock )}
>
> --> false
>
>
> this is probably related to the problem that you cannot use Condition.wait
> inside a Routine that runs on AppClock without braking the canCallOS
> property.
>
> i think this very secure, so i put it in the bug tracker. hope this can be
> found ......



--
James Harkins /// dewdrop world
jamshark70@...
http://www.dewdrop-world.net

"Come said the Muse,
Sing me a song no poet has yet chanted,
Sing me the universal."  -- Whitman

_______________________________________________
sc-users mailing list

info (subscribe and unsubscribe): http://swiki.hfbk-hamburg.de:8888/MusicTechnology/880
archive: http://www.listarc.bham.ac.uk/marchives/sc-users/
search: http://www.listarc.bham.ac.uk/lists/sc-users/search/

Re: Routine / AppClock broken

by Stefan Nussbaumer-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

James Harkins schrieb:

> Expand your function this way...
>
> fork { thisThread.dump; thisThread.clock.dump; { thisThread.dump;
> thisThread.clock.dump; thisFunction.canCallOS.postln }.fork( AppClock
> )}
>
> ... and it becomes evident that canCallOS is doing exactly what it
> should. The inner .fork(AppClock) is not behaving correctly, though.
>
> I don't know why but the inner fork is going onto TempoClock.default.
> Since it is on a tempoclock, naturally canCallOS should return false.

sorry for intervening ... I certainly wouldn't have been able to detect
these pecularities by my personal experiences ...

I'm currently working with revision 7693 and above code-snippet returns
'false' as expected for canCallOS (or did I misunderstand the dump?)

stefan


_______________________________________________
sc-users mailing list

info (subscribe and unsubscribe): http://swiki.hfbk-hamburg.de:8888/MusicTechnology/880
archive: http://www.listarc.bham.ac.uk/marchives/sc-users/
search: http://www.listarc.bham.ac.uk/lists/sc-users/search/

Re: Routine / AppClock broken

by James Harkins-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On Jul 21, 2008, at 4:21 PM, James Harkins wrote:
I don't know why but the inner fork is going onto TempoClock.default.
Since it is on a tempoclock, naturally canCallOS should return false.

OK, I found it and it is really f*ed up.

Forking a function on AppClock eventually dispatches to Clock *play:

*play { arg task;
var beats, seconds;
task.clock = this;
seconds = thisThread.seconds;
beats = this.secs2beats(seconds);
this.sched(task.value(beats, seconds, this), task)
}

Now, check this out... in sciss' test, "task" is a Routine. Note that .value gets called on the task before the task is actually put in the scheduler -- this is to find the time at which the task should be scheduled. For Routines, 'value' is synonymous with 'next' -- meaning that the Routine's function (which doesn't yield anything) runs through to completion under control of the outer clock -- this is before AppClock takes over. The routine does actually get scheduled on AppClock, but (since there is no yield) the routine is finished at that point and has nothing left to do.

The same thing is true of SystemClock:

fork {
SystemClock.play(Routine({
thisThread.clock.debug("pre-yield");
1.0.yield;
thisThread.clock.debug("post-yield");
}))
};

pre-yield: a TempoClock
post-yield: class SystemClock


I can see a reason for doing this -- it allows the routine to communicate scheduling information back to the clock by immediately yielding -- but this is really confusing and not documented. It's especially confusing because most of the time you'll be scheduling on TempoClock, which behaves very differently.

I think a strong case could be made for changing this.

In any case, one workaround is always to write 0.yield as the first thing in your forked function.

The other way is to schedule explicitly, instead of relying on what is really nothing more than syntactic sugar. This works perfectly well without any changes:

AppClock.sched(0, Routine({ ... }))

Or, if you can't go entirely sugar-free:

AppClock.sched(0, r {  })

hjh


: H. James Harkins

: jamshark70@...

: http://www.dewdrop-world.net

.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:


"Come said the Muse,

Sing me a song no poet has yet chanted,

Sing me the universal."  -- Whitman



Re: Routine / AppClock broken

by James Harkins-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Or, perhaps best, we change fork to use clock.sched(0, Routine(this)) instead of relying on play (which in its current state is a big mistake).

hjh

On Jul 21, 2008, at 10:30 PM, James Harkins wrote:

In any case, one workaround is always to write 0.yield as the first thing in your forked function.

The other way is to schedule explicitly, instead of relying on what is really nothing more than syntactic sugar. This works perfectly well without any changes:

AppClock.sched(0, Routine({ ... }))

Or, if you can't go entirely sugar-free:

AppClock.sched(0, r {  })

hjh


: H. James Harkins

: jamshark70@...

: http://www.dewdrop-world.net

.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:


"Come said the Muse,

Sing me a song no poet has yet chanted,

Sing me the universal."  -- Whitman



Re: Routine / AppClock broken

by James Harkins-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

This appears to clear up the fork issue.

fork { arg clock, quant=0.0, stackSize=64;
var routine = Routine(this, stackSize);
clock = clock ?? { TempoClock.default };
clock.sched(quant.nextTimeOnGrid(clock) - clock.beats, routine);
^routine
}

As for SystemClock.play and AppClock.play... dunno if it's worth it.

hjh

On Jul 21, 2008, at 10:35 PM, James Harkins wrote:

Or, perhaps best, we change fork to use clock.sched(0, Routine(this)) instead of relying on play (which in its current state is a big mistake).

hjh

On Jul 21, 2008, at 10:30 PM, James Harkins wrote:

In any case, one workaround is always to write 0.yield as the first thing in your forked function.

The other way is to schedule explicitly, instead of relying on what is really nothing more than syntactic sugar. This works perfectly well without any changes:

AppClock.sched(0, Routine({ ... }))

Or, if you can't go entirely sugar-free:

AppClock.sched(0, r {  })

hjh


: H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:

"Come said the Muse,
Sing me a song no poet has yet chanted,
Sing me the universal."  -- Whitman



: H. James Harkins

: jamshark70@...

: http://www.dewdrop-world.net

.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:


"Come said the Muse,

Sing me a song no poet has yet chanted,

Sing me the universal."  -- Whitman



Re: Routine / AppClock broken

by Sciss :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

hooo looks complicated. ok, i understand that fork { ... } ends up in  
Meta_Clock:play

                this.sched(task.value(beats, seconds, this), task)

and hence the problem of task.value. but then still:

c = Condition.new;
AppClock.sched(0, r {  ("Can? " ++ thisThread.canCallOS).postln;  
1.wait; ("Can? " ++ thisThread.canCallOS).postln; c.wait; ("Can? " ++  
thisThread.canCallOS).postln; })
c.test = true; c.signal;

the condition wakes up the routine again on the wrong clock....

so at least the latter is defintely wrong, and the former is at best  
very confusing. i think Meta_Clock:play should be changed, because  
look at what TempoClock:play does:

        play { arg task, quant = 1;
                this.schedAbs(quant.nextTimeOnGrid(this), task)
        }

so here task is definitely not evaluated beforehand, so the behaviour  
is inconsistent:

fork {
SystemClock.play(Routine({
        thisThread.clock.debug("pre-yield"); // --> TempoClock (IMO wrong)
        1.0.yield;
        thisThread.clock.debug("post-yield"); // --> SystemClock (OK)
}))
}

fork {
AppClock.play(Routine({
        thisThread.clock.debug("pre-yield"); // --> TempoClock (IMO wrong)
        1.0.yield;
        thisThread.clock.debug("post-yield"); // --> SystemClock (obviously  
wrong again!!)
}))
}

SystemClock.play( r {
TempoClock.new.play(Routine({
        thisThread.clock.debug("pre-yield"); // --> TempoClock (OK)
        1.0.yield;
        thisThread.clock.debug("post-yield"); // --> TempoClock (OK)
}))
})

so TempoClock is the only one that behaves in the expected way.

ciao, -sciss-




Am 22.07.2008 um 04:30 schrieb James Harkins:

>
> On Jul 21, 2008, at 4:21 PM, James Harkins wrote:
>> I don't know why but the inner fork is going onto TempoClock.default.
>> Since it is on a tempoclock, naturally canCallOS should return false.
>
> OK, I found it and it is really f*ed up.
>
> Forking a function on AppClock eventually dispatches to Clock *play:
>
> *play { arg task;
> var beats, seconds;
> task.clock = this;
> seconds = thisThread.seconds;
> beats = this.secs2beats(seconds);
> this.sched(task.value(beats, seconds, this), task)
> }
>
> Now, check this out... in sciss' test, "task" is a Routine. Note  
> that .value gets called on the task before the task is actually put  
> in the scheduler -- this is to find the time at which the task  
> should be scheduled. For Routines, 'value' is synonymous with  
> 'next' -- meaning that the Routine's function (which doesn't yield  
> anything) runs through to completion under control of the outer  
> clock -- this is before AppClock takes over. The routine does  
> actually get scheduled on AppClock, but (since there is no yield)  
> the routine is finished at that point and has nothing left to do.
>
> The same thing is true of SystemClock:
>
> fork {
> SystemClock.play(Routine({
> thisThread.clock.debug("pre-yield");
> 1.0.yield;
> thisThread.clock.debug("post-yield");
> }))
> };
>
> pre-yield: a TempoClock
> post-yield: class SystemClock
>
>
> I can see a reason for doing this -- it allows the routine to  
> communicate scheduling information back to the clock by immediately  
> yielding -- but this is really confusing and not documented. It's  
> especially confusing because most of the time you'll be scheduling  
> on TempoClock, which behaves very differently.
>
> I think a strong case could be made for changing this.
>
> In any case, one workaround is always to write 0.yield as the first  
> thing in your forked function.
>
> The other way is to schedule explicitly, instead of relying on what  
> is really nothing more than syntactic sugar. This works perfectly  
> well without any changes:
>
> AppClock.sched(0, Routine({ ... }))
>
> Or, if you can't go entirely sugar-free:
>
> AppClock.sched(0, r {  })
>
> hjh
>
>
> : H. James Harkins
> : jamshark70@...
> : http://www.dewdrop-world.net
> .::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:
>
> "Come said the Muse,
> Sing me a song no poet has yet chanted,
> Sing me the universal."  -- Whitman
>


_______________________________________________
sc-users mailing list

info (subscribe and unsubscribe): http://swiki.hfbk-hamburg.de:8888/MusicTechnology/880
archive: http://www.listarc.bham.ac.uk/marchives/sc-users/
search: http://www.listarc.bham.ac.uk/lists/sc-users/search/

Re: Routine / AppClock broken

by Scott Wilson-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

This is definitely a bug not a feature, IMO, so I think it would be best to fix Clock:play (not that I have a solution to hand... ;-)

At the very least the current implementation is extremely counterintuitive.

S.

On 22 Jul 2008, at 03:35, James Harkins wrote:

Or, perhaps best, we change fork to use clock.sched(0, Routine(this)) instead of relying on play (which in its current state is a big mistake).

hjh

On Jul 21, 2008, at 10:30 PM, James Harkins wrote:

In any case, one workaround is always to write 0.yield as the first thing in your forked function.

The other way is to schedule explicitly, instead of relying on what is really nothing more than syntactic sugar. This works perfectly well without any changes:

AppClock.sched(0, Routine({ ... }))

Or, if you can't go entirely sugar-free:

AppClock.sched(0, r {  })

hjh


: H. James Harkins
.::!:.:.......:.::........:..!.::.::...:..:...:.:.:.:..:

"Come said the Muse,
Sing me a song no poet has yet chanted,
Sing me the universal."  -- Whitman


LightInTheBox - Buy quality products at wholesale price