From 48611c50f7711e7ae62df5a79b52c0e2902477ed Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Mon, 2 Jan 2023 18:53:58 +0800 Subject: [PATCH] :rocket: coroutine.resume can pass arguments --- doc/dev.md | 2 +- doc/dev_zh.md | 2 +- nasal_builtin.h | 14 +++++++++++++- nasal_gc.h | 2 +- nasal_vm.h | 1 + stl/lib.nas | 10 +++++----- test/coroutine.nas | 14 ++++++++++++++ 7 files changed, 36 insertions(+), 9 deletions(-) diff --git a/doc/dev.md b/doc/dev.md index ecb087c..dd03a9f 100644 --- a/doc/dev.md +++ b/doc/dev.md @@ -587,7 +587,7 @@ Then we call `resume`, this function will change stack. As we can see, coroutine stack already has some values on it, but if we first enter it, the stack top will be `vm_ret`, and the return `pc` is `0`. -So for safe running, `resume` will return `gc.top[0]`. +So for safe running, when first calling the coroutine, `resume` will return `gc.top[0]`. `op_callb` will do `top[0]=resume()`, so the value does not change. ```C++ diff --git a/doc/dev_zh.md b/doc/dev_zh.md index da245af..83e5dda 100644 --- a/doc/dev_zh.md +++ b/doc/dev_zh.md @@ -526,7 +526,7 @@ __接下来我们解释这个协程的运行原理:__ 接着我们调用`resume`,这个函数会替换操作数栈。我们会看到,协程的操作数栈上已经保存了一些数据,但是我们首次进入协程执行时,这个操作数栈的栈顶将会是`vm_ret`,并且返回的`pc`值是`0`。 -为了保证栈顶的数据不会被破坏,`resume`会返回`gc.top[0]`。`op_callb`将会执行`top[0]=resume()`,所以栈顶的数据虽然被覆盖了一次,但是实际上还是原来的数据。 +首次调用时,为了保证栈顶的数据不会被破坏,`resume`会返回`gc.top[0]`。`op_callb`将会执行`top[0]=resume()`,所以栈顶的数据虽然被覆盖了一次,但是实际上还是原来的数据。 ```C++ +----------------------+(协程操作数栈) diff --git a/nasal_builtin.h b/nasal_builtin.h index bc0bdcb..8a3339a 100644 --- a/nasal_builtin.h +++ b/nasal_builtin.h @@ -1165,7 +1165,19 @@ var builtin_coresume(var* local,gc& ngc) { // fetch coroutine's stack top and return // so the coroutine's stack top in fact is not changed - return ngc.top[0]; + if (ngc.top[0].type==vm_ret) { + // when first calling this coroutine, the stack top must be vm_ret + return ngc.top[0]; + } + + // after first calling the coroutine, each time coroutine.yield triggered + // a new space will be reserved on stack with value nil + // so we could fill this place with args + + // the coroutine seems like coroutine.yield returns the value + // but in fact coroutine.yield stop the coroutine + // until main context calls the coroutine.resume + return local[2]; } var builtin_coyield(var* local,gc& ngc) { diff --git a/nasal_gc.h b/nasal_gc.h index 823de2e..43bfd68 100644 --- a/nasal_gc.h +++ b/nasal_gc.h @@ -715,7 +715,7 @@ void gc::ctxchg(nas_co& ctx) { void gc::ctxreserve() { // pc=0 means this coroutine is finished - cort->status=pc?nas_co::suspended:nas_co::dead; + cort->status=pc? nas_co::suspended:nas_co::dead; cort->pc=pc; cort->localr=localr; cort->memr=memr; diff --git a/nasal_vm.h b/nasal_vm.h index 2e59fb1..c05745e 100644 --- a/nasal_vm.h +++ b/nasal_vm.h @@ -624,6 +624,7 @@ void vm::o_feach() { } void vm::o_callg() { + // get main stack directly (++top)[0]=stack[imm[pc]]; } diff --git a/stl/lib.nas b/stl/lib.nas index c8c82e1..07e54fa 100644 --- a/stl/lib.nas +++ b/stl/lib.nas @@ -507,9 +507,9 @@ var compile=func(code,filename=""){ } var coroutine={ - create: func(function){return __cocreate;}, - resume: func(co) {return __coresume;}, - yield: func(args...) {return __coyield; }, - status: func(co) {return __costatus;}, - running:func() {return __corun; } + create: func(function) {return __cocreate;}, + resume: func(co,args...) {return __coresume;}, + yield: func(args...) {return __coyield; }, + status: func(co) {return __costatus;}, + running:func() {return __corun; } }; diff --git a/test/coroutine.nas b/test/coroutine.nas index dc71170..5022534 100644 --- a/test/coroutine.nas +++ b/test/coroutine.nas @@ -40,6 +40,20 @@ func(){ } }(); +# test coroutine.resume passing arguments to coroutine +func{ + var co=coroutine.create(func(){ + var (a,b)=coroutine.yield(a+b); + println("coroutine.yield get ",a," ",b); + (a,b)=coroutine.yield(a+b); + println("coroutine.yield get ",a," ",b); + return "end"; + }); + + for(var i=0;i<5;i+=1) + println("coroutine.resume get ",coroutine.resume(co,i,i+1)); +}(); + # test crash in coroutines var co=coroutine.create(func{ var b=func(){b()}