How to swap coroutine ?

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

How to swap coroutine ?

Gaspard Bucher
Hi list !

I would like to create a coroutine and then continue execution in the coroutine so that the original calling code can yield.

Usage:

-- ...
co = coroutine.create(function()
  -- A
  -- co == main running code (B)
  scheduler:run()
end)

-- transform running thread into a coroutine and continue execution in "A"
-- B
coroutine.swap(co)

Is this possible ?

                                                               Gaspard

Reply | Threaded
Open this post in threaded view
|

Re: How to swap coroutine ?

Tony Finch
Gaspard Bucher <[hidden email]> wrote:
>
> I would like to create a coroutine and then continue execution in the
> coroutine so that the original calling code can yield.

You need to create the coroutine, tell your scheduler about it, then
yield, and allow the scheduler to start the new coroutine.

There is a stack of "normal" coroutines with the currently "running"
coroutine at the top. (Terminology is according to coro.status.) Calling
coro.resume pushes a coroutine onto the stack, switching the caller from
"running" to "normal" and the callee from "suspended" to "running".
Calling coro.yield pops the top coroutine, switching it from "running" to
"suspended".

There aren't any functions that allow you to manipulate coroutines other
than in this stack-like manner, so if you want to re-arrange the stack you
need to code it explicitly. This generally means you need a scheduler
running in the deepest coroutine in the stack, and some utility functions
that the other coroutines call to co-operate with the scheduler.

Tony.
--
f.anthony.n.finch  <[hidden email]>  http://dotat.at/
Viking, North Utsire: Cyclonic, becoming westerly or northwesterly 5 to 7,
occasionally gale 8. Moderate or rough, becoming rough or very rough. Rain.
Good, occasionally poor.

Reply | Threaded
Open this post in threaded view
|

Re: How to swap coroutine ?

Gaspard Bucher


On Mon, Sep 12, 2011 at 7:59 PM, Tony Finch <[hidden email]> wrote:
Gaspard Bucher <[hidden email]> wrote:
>
> I would like to create a coroutine and then continue execution in the
> coroutine so that the original calling code can yield.

You need to create the coroutine, tell your scheduler about it, then
yield, and allow the scheduler to start the new coroutine.

There is a stack of "normal" coroutines with the currently "running"
coroutine at the top. (Terminology is according to coro.status.) Calling
coro.resume pushes a coroutine onto the stack, switching the caller from
"running" to "normal" and the callee from "suspended" to "running".
Calling coro.yield pops the top coroutine, switching it from "running" to
"suspended".

There aren't any functions that allow you to manipulate coroutines other
than in this stack-like manner, so if you want to re-arrange the stack you
need to code it explicitly. This generally means you need a scheduler
running in the deepest coroutine in the stack, and some utility functions
that the other coroutines call to co-operate with the scheduler.

Tony.


I know it is not that hard to add a "scheduler:run()" at the end of a main script, but I would like the main thread to give up control before reaching the end of the script:

quit = false
function run(main)
  print("run started")
  while not quit do
    print(coroutine.resume(main))
  end
end

print('[0] main')
coroutine.swap(run) --<<< magick here

print('[1] main')
coroutine.yield('yield1')

print('[2] main')
coroutine.yield('yield2')
quit = true       

---

Trying to create this, I either get C boundary yield errors or "cannot resume normal coroutine" (and I suspect that I cannot just alter 'main' to make it 'suspended')...

Reply | Threaded
Open this post in threaded view
|

Re: How to swap coroutine ?

Wesley Smith
> I know it is not that hard to add a "scheduler:run()" at the end of a main
> script, but I would like the main thread to give up control before reaching
> the end of the script:

If you run the entire script as the body of a coroutine, it can yield
at any point.
wes

Reply | Threaded
Open this post in threaded view
|

Re: How to swap coroutine ?

Graham Wakefield-2
Exactly. Start your script with lua_resume() rather than lua_call().

On Sep 12, 2011, at 1:36 PM, Wesley Smith wrote:

>> I know it is not that hard to add a "scheduler:run()" at the end of a main
>> script, but I would like the main thread to give up control before reaching
>> the end of the script:
>
> If you run the entire script as the body of a coroutine, it can yield
> at any point.
> wes
>


Reply | Threaded
Open this post in threaded view
|

Re: How to swap coroutine ?

Gaspard Bucher
On Tue, Sep 13, 2011 at 8:53 AM, Graham Wakefield <[hidden email]> wrote:
Exactly. Start your script with lua_resume() rather than lua_call().

On Sep 12, 2011, at 1:36 PM, Wesley Smith wrote:

>> I know it is not that hard to add a "scheduler:run()" at the end of a main
>> script, but I would like the main thread to give up control before reaching
>> the end of the script:
>
> If you run the entire script as the body of a coroutine, it can yield
> at any point.
> wes
>


This is a good idea if you run a custom executable, which I don't (I want to use plain Lua).
Technically, what I want to do doesn't seem impossible (it's some kind of resumable goto)
and it would enable to completely hide the scheduling stuff. For example, I wrap
coroutine.yield(timeout) as "sleep(timeout)" which is very easy to grok and it worked fine
as long as I used real OS threads. If you do the same with coroutines you get errors. For
a total beginner, code "A" and "B" are the same, but "B" has some boilerplate code that
I would *love* to hide:

-- ========== A
play('C#')
sleep(500)  -- error
play('E')
sleep(500)

-- ========== B
sched:thread(function()
  play('C#')
  sleep(500)  -- ok
  play('E')
  sleep(500)
end)

sched:run()
-- 

If there is no solution apart from altering the bytecode (a job for Peter Cawley...),
I can live with "B".

                                                               Gaspard

Reply | Threaded
Open this post in threaded view
|

Re: How to swap coroutine ?

Tony Finch
Gaspard Bucher <[hidden email]> wrote:
> On Tue, Sep 13, 2011 at 8:53 AM, Graham Wakefield <[hidden email]>wrote:
>
> > Exactly. Start your script with lua_resume() rather than lua_call().
>
> This is a good idea if you run a custom executable, which I don't (I want to
> use plain Lua).

You can do the equivalent in plain Lua if you have a wrapper script that
loads the user's script and calls coroutine.resume on it.

> Technically, what I want to do doesn't seem impossible (it's some kind
> of resumable goto) and it would enable to completely hide the scheduling
> stuff.

Yes, symmetric coroutines are possible but Lua has asymmetric coroutines.
There is a rationale in this paper:
http://www.inf.puc-rio.br/~roberto/docs/corosblp.pdf

Tony.
--
f.anthony.n.finch  <[hidden email]>  http://dotat.at/
Hebrides, Southeast Bailey: Northwesterly 4, increasing 5 to 7, perhaps gale 8
later. Very rough, occasionally high later. Rain. Mainly moderate.