🚀 coroutine.resume can pass arguments

This commit is contained in:
ValKmjolnir 2023-01-02 18:53:58 +08:00
parent e6e89039b8
commit 48611c50f7
7 changed files with 36 additions and 9 deletions

View File

@ -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++

View File

@ -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++
+----------------------+(协程操作数栈)

View File

@ -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) {

View File

@ -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;

View File

@ -624,6 +624,7 @@ void vm::o_feach() {
}
void vm::o_callg() {
// get main stack directly
(++top)[0]=stack[imm[pc]];
}

View File

@ -507,9 +507,9 @@ var compile=func(code,filename="<compile>"){
}
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; }
};

View File

@ -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()}