diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-11-06 17:08:00 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-11-06 17:08:00 -0200 |
commit | 118347d8c3b83ea0291918e81c5367937316fabb (patch) | |
tree | b77d5b6e03d9ae20841bd80a50cc56237bdf16f5 | |
parent | 6820da509686ce06fdb3de58856056476f55f534 (diff) | |
download | lua-118347d8c3b83ea0291918e81c5367937316fabb.tar.gz lua-118347d8c3b83ea0291918e81c5367937316fabb.tar.bz2 lua-118347d8c3b83ea0291918e81c5367937316fabb.zip |
new API for coroutines
-rw-r--r-- | lapi.c | 15 | ||||
-rw-r--r-- | lbaselib.c | 46 | ||||
-rw-r--r-- | ldo.c | 97 | ||||
-rw-r--r-- | lstate.h | 5 | ||||
-rw-r--r-- | lua.h | 7 | ||||
-rw-r--r-- | lvm.c | 3 |
6 files changed, 85 insertions, 88 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lapi.c,v 1.214 2002/10/25 20:05:28 roberto Exp roberto $ | 2 | ** $Id: lapi.c,v 1.215 2002/10/25 21:31:28 roberto Exp roberto $ |
3 | ** Lua API | 3 | ** Lua API |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -105,6 +105,19 @@ LUA_API int lua_checkstack (lua_State *L, int size) { | |||
105 | } | 105 | } |
106 | 106 | ||
107 | 107 | ||
108 | LUA_API void lua_movethread (lua_State *from, lua_State *to, int n) { | ||
109 | int i; | ||
110 | lua_lock(to); | ||
111 | api_checknelems(from, n); | ||
112 | from->top -= n; | ||
113 | for (i = 0; i < n; i++) { | ||
114 | setobj(to->top, from->top + i); | ||
115 | api_incr_top(to); | ||
116 | } | ||
117 | lua_unlock(to); | ||
118 | } | ||
119 | |||
120 | |||
108 | LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { | 121 | LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { |
109 | lua_CFunction old; | 122 | lua_CFunction old; |
110 | lua_lock(L); | 123 | lua_lock(L); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lbaselib.c,v 1.102 2002/10/25 21:31:28 roberto Exp roberto $ | 2 | ** $Id: lbaselib.c,v 1.103 2002/10/25 21:36:54 roberto Exp roberto $ |
3 | ** Basic library | 3 | ** Basic library |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -557,12 +557,23 @@ static const luaL_reg base_funcs[] = { | |||
557 | ** ======================================================= | 557 | ** ======================================================= |
558 | */ | 558 | */ |
559 | 559 | ||
560 | 560 | static int auxresume (lua_State *L, lua_State *co, int narg) { | |
561 | static int luaB_auxresume (lua_State *L, lua_State *co) { | ||
562 | int status; | 561 | int status; |
563 | int oldtop = lua_gettop(L); | 562 | if (!lua_checkstack(co, narg)) |
564 | status = lua_resume(L, co); | 563 | luaL_error(L, "too many arguments to resume"); |
565 | return (status != 0) ? -1 : lua_gettop(L) - oldtop; | 564 | lua_movethread(L, co, narg); |
565 | status = lua_resume(co, narg); | ||
566 | if (status == 0) { | ||
567 | int nres = lua_gettop(co); | ||
568 | if (!lua_checkstack(L, narg)) | ||
569 | luaL_error(L, "too many results to resume"); | ||
570 | lua_movethread(co, L, nres); /* move yielded values */ | ||
571 | return nres; | ||
572 | } | ||
573 | else { | ||
574 | lua_movethread(co, L, 1); /* move error message */ | ||
575 | return -1; /* error flag */ | ||
576 | } | ||
566 | } | 577 | } |
567 | 578 | ||
568 | 579 | ||
@@ -570,7 +581,7 @@ static int luaB_coresume (lua_State *L) { | |||
570 | lua_State *co = lua_tothread(L, 1); | 581 | lua_State *co = lua_tothread(L, 1); |
571 | int r; | 582 | int r; |
572 | luaL_arg_check(L, co, 1, "coroutine/thread expected"); | 583 | luaL_arg_check(L, co, 1, "coroutine/thread expected"); |
573 | r = luaB_auxresume(L, co); | 584 | r = auxresume(L, co, lua_gettop(L) - 1); |
574 | if (r < 0) { | 585 | if (r < 0) { |
575 | lua_pushboolean(L, 0); | 586 | lua_pushboolean(L, 0); |
576 | lua_insert(L, -2); | 587 | lua_insert(L, -2); |
@@ -585,28 +596,19 @@ static int luaB_coresume (lua_State *L) { | |||
585 | 596 | ||
586 | 597 | ||
587 | static int luaB_auxwrap (lua_State *L) { | 598 | static int luaB_auxwrap (lua_State *L) { |
588 | int r = luaB_auxresume(L, lua_tothread(L, lua_upvalueindex(1))); | 599 | lua_State *co = lua_tothread(L, lua_upvalueindex(1)); |
589 | if (r < 0) lua_error(L); | 600 | int r = auxresume(L, co, lua_gettop(L)); |
601 | if (r < 0) lua_error(L); /* propagate error */ | ||
590 | return r; | 602 | return r; |
591 | } | 603 | } |
592 | 604 | ||
593 | 605 | ||
594 | static int luaB_cocreate (lua_State *L) { | 606 | static int luaB_cocreate (lua_State *L) { |
595 | lua_State *NL; | 607 | lua_State *NL = lua_newthread(L); |
596 | int ref; | ||
597 | int i; | ||
598 | int n = lua_gettop(L); | ||
599 | luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, | 608 | luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, |
600 | "Lua function expected"); | 609 | "Lua function expected"); |
601 | NL = lua_newthread(L); | 610 | lua_pushvalue(L, 1); /* move function to top */ |
602 | /* move function and arguments from L to NL */ | 611 | lua_movethread(L, NL, 1); /* move function from L to NL */ |
603 | for (i = 1; i <= n; i++) { | ||
604 | lua_pushvalue(L, i); | ||
605 | ref = lua_ref(L, 1); | ||
606 | lua_getref(NL, ref); | ||
607 | lua_unref(L, ref); | ||
608 | } | ||
609 | lua_cobegin(NL, n-1); | ||
610 | return 1; | 612 | return 1; |
611 | } | 613 | } |
612 | 614 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ldo.c,v 1.196 2002/10/09 13:42:01 roberto Exp roberto $ | 2 | ** $Id: ldo.c,v 1.197 2002/10/25 20:05:28 roberto Exp roberto $ |
3 | ** Stack and Call structure of Lua | 3 | ** Stack and Call structure of Lua |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -44,22 +44,23 @@ struct lua_longjmp { | |||
44 | }; | 44 | }; |
45 | 45 | ||
46 | 46 | ||
47 | static void seterrorobj (lua_State *L, int errcode) { | 47 | static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { |
48 | switch (errcode) { | 48 | switch (errcode) { |
49 | case LUA_ERRMEM: { | 49 | case LUA_ERRMEM: { |
50 | setsvalue(L->top, luaS_new(L, MEMERRMSG)); | 50 | setsvalue(oldtop, luaS_new(L, MEMERRMSG)); |
51 | break; | 51 | break; |
52 | } | 52 | } |
53 | case LUA_ERRERR: { | 53 | case LUA_ERRERR: { |
54 | setsvalue(L->top, luaS_new(L, "error in error handling")); | 54 | setsvalue(oldtop, luaS_new(L, "error in error handling")); |
55 | break; | 55 | break; |
56 | } | 56 | } |
57 | case LUA_ERRSYNTAX: | 57 | case LUA_ERRSYNTAX: |
58 | case LUA_ERRRUN: { | 58 | case LUA_ERRRUN: { |
59 | return; /* error message already on top */ | 59 | setobj(oldtop, L->top - 1); /* error message on current top */ |
60 | break; | ||
60 | } | 61 | } |
61 | } | 62 | } |
62 | L->top++; | 63 | L->top = oldtop + 1; |
63 | } | 64 | } |
64 | 65 | ||
65 | 66 | ||
@@ -298,67 +299,46 @@ void luaD_call (lua_State *L, StkId func, int nResults) { | |||
298 | } | 299 | } |
299 | 300 | ||
300 | 301 | ||
301 | LUA_API void lua_cobegin (lua_State *L, int nargs) { | ||
302 | lua_lock(L); | ||
303 | luaD_precall(L, L->top - (nargs+1)); | ||
304 | lua_unlock(L); | ||
305 | } | ||
306 | |||
307 | |||
308 | static void move_results (lua_State *L, TObject *from, TObject *to) { | ||
309 | while (from < to) { | ||
310 | setobj(L->top, from); | ||
311 | from++; | ||
312 | incr_top(L); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | |||
317 | static void resume (lua_State *L, void *ud) { | 302 | static void resume (lua_State *L, void *ud) { |
318 | StkId firstResult; | 303 | StkId firstResult; |
304 | int nargs = *cast(int *, ud); | ||
319 | CallInfo *ci = L->ci; | 305 | CallInfo *ci = L->ci; |
320 | if (ci->state & CI_C) { /* not first time (i.e. inside a yield)? */ | 306 | if (ci == L->base_ci) { /* no activation record? */ |
307 | if (nargs >= L->top - L->ci->base) | ||
308 | luaG_runerror(L, "cannot resume dead coroutine"); | ||
309 | luaD_precall(L, L->top - (nargs + 1)); /* start coroutine */ | ||
310 | } | ||
311 | else if (ci->state && CI_YIELD) { /* inside a yield? */ | ||
321 | /* finish interrupted execution of `OP_CALL' */ | 312 | /* finish interrupted execution of `OP_CALL' */ |
322 | int nresults; | 313 | int nresults; |
323 | lua_assert((ci-1)->state & CI_SAVEDPC); | 314 | lua_assert((ci-1)->state & CI_SAVEDPC); |
324 | lua_assert(GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_CALL || | 315 | lua_assert(GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_CALL || |
325 | GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TAILCALL); | 316 | GET_OPCODE(*((ci-1)->u.l.savedpc - 1)) == OP_TAILCALL); |
326 | nresults = GETARG_C(*((ci-1)->u.l.savedpc - 1)) - 1; | 317 | nresults = GETARG_C(*((ci-1)->u.l.savedpc - 1)) - 1; |
327 | luaD_poscall(L, nresults, L->top); /* complete it */ | 318 | luaD_poscall(L, nresults, L->top - nargs); /* complete it */ |
328 | if (nresults >= 0) L->top = L->ci->top; | 319 | if (nresults >= 0) L->top = L->ci->top; |
329 | } | 320 | } |
321 | else | ||
322 | luaG_runerror(L, "cannot resume non-suspended coroutine"); | ||
330 | firstResult = luaV_execute(L); | 323 | firstResult = luaV_execute(L); |
331 | if (firstResult == NULL) /* yield? */ | 324 | if (firstResult != NULL) /* return? */ |
332 | *cast(int *, ud) = L->ci->u.c.yield_results; | ||
333 | else { /* return */ | ||
334 | *cast(int *, ud) = L->top - firstResult; | ||
335 | luaD_poscall(L, LUA_MULTRET, firstResult); /* finalize this coroutine */ | 325 | luaD_poscall(L, LUA_MULTRET, firstResult); /* finalize this coroutine */ |
336 | } | ||
337 | } | 326 | } |
338 | 327 | ||
339 | 328 | ||
340 | LUA_API int lua_resume (lua_State *L, lua_State *co) { | 329 | LUA_API int lua_resume (lua_State *L, int nargs) { |
341 | CallInfo *ci; | ||
342 | int numres; | ||
343 | int status; | 330 | int status; |
331 | int old_allowhooks; | ||
344 | lua_lock(L); | 332 | lua_lock(L); |
345 | ci = co->ci; | 333 | old_allowhooks = allowhook(L); |
346 | if (ci == co->base_ci) { /* no activation record? ?? */ | 334 | lua_assert(L->errfunc == 0); |
347 | luaO_pushfstring(L, "cannot resume dead thread"); | 335 | status = luaD_rawrunprotected(L, resume, &nargs); |
348 | status = LUA_ERRRUN; | 336 | if (status != 0) { |
349 | } | 337 | L->ci = L->base_ci; /* `kill' thread (??) */ |
350 | else if (co->errorJmp != NULL) { /* ?? */ | 338 | seterrorobj(L, status, L->ci->base); |
351 | luaO_pushfstring(L, "cannot resume active thread"); | 339 | luaF_close(L, L->top); /* close eventual pending closures */ |
352 | status = LUA_ERRRUN; | 340 | setallowhook(L, old_allowhooks); |
353 | } | 341 | restore_stack_limit(L); |
354 | else { | ||
355 | status = luaD_rawrunprotected(co, resume, &numres); | ||
356 | if (status == 0) | ||
357 | move_results(L, co->top - numres, co->top); | ||
358 | else { | ||
359 | setobj(L->top++, co->top - 1); /* move error message to other stack */ | ||
360 | co->ci = co->base_ci; /* `kill' thread */ | ||
361 | } | ||
362 | } | 342 | } |
363 | lua_unlock(L); | 343 | lua_unlock(L); |
364 | return status; | 344 | return status; |
@@ -372,7 +352,12 @@ LUA_API int lua_yield (lua_State *L, int nresults) { | |||
372 | if ((ci-1)->state & CI_C) | 352 | if ((ci-1)->state & CI_C) |
373 | luaG_runerror(L, "cannot yield a C function"); | 353 | luaG_runerror(L, "cannot yield a C function"); |
374 | lua_assert(ci->state & CI_C); /* current function is not Lua */ | 354 | lua_assert(ci->state & CI_C); /* current function is not Lua */ |
375 | ci->u.c.yield_results = nresults; | 355 | if (L->top - nresults > ci->base) { /* is there garbage in the stack? */ |
356 | int i; | ||
357 | for (i=0; i<nresults; i++) /* move down results */ | ||
358 | setobj(ci->base + i, L->top - nresults + i); | ||
359 | L->top = ci->base + nresults; | ||
360 | } | ||
376 | lua_unlock(L); | 361 | lua_unlock(L); |
377 | return -1; | 362 | return -1; |
378 | } | 363 | } |
@@ -405,12 +390,8 @@ int luaD_pcall (lua_State *L, int nargs, int nresults, ptrdiff_t errfunc) { | |||
405 | c.nresults = nresults; | 390 | c.nresults = nresults; |
406 | status = luaD_rawrunprotected(L, &f_call, &c); | 391 | status = luaD_rawrunprotected(L, &f_call, &c); |
407 | if (status != 0) { /* an error occurred? */ | 392 | if (status != 0) { /* an error occurred? */ |
408 | StkId err; /* error msg. position */ | 393 | StkId oldtop = restorestack(L, old_top) - (nargs+1); |
409 | seterrorobj(L, status); | 394 | seterrorobj(L, status, oldtop); |
410 | err = L->top - 1; | ||
411 | /* remove parameters and func from the stack */ | ||
412 | L->top = restorestack(L, old_top) - (nargs+1); | ||
413 | setobj(L->top++, err); /* copy error message to corrected top */ | ||
414 | luaF_close(L, L->top); /* close eventual pending closures */ | 395 | luaF_close(L, L->top); /* close eventual pending closures */ |
415 | L->ci = restoreci(L, old_ci); | 396 | L->ci = restoreci(L, old_ci); |
416 | setallowhook(L, old_allowhooks); | 397 | setallowhook(L, old_allowhooks); |
@@ -461,9 +442,7 @@ int luaD_protectedparser (lua_State *L, ZIO *z, int bin) { | |||
461 | } | 442 | } |
462 | else { /* error */ | 443 | else { /* error */ |
463 | StkId oldtop = restorestack(L, oldtopr); | 444 | StkId oldtop = restorestack(L, oldtopr); |
464 | seterrorobj(L, status); | 445 | seterrorobj(L, status, oldtop); |
465 | setobj(oldtop, L->top - 1); /* copy error message to old top */ | ||
466 | L->top = oldtop+1; | ||
467 | } | 446 | } |
468 | return status; | 447 | return status; |
469 | } | 448 | } |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstate.h,v 1.98 2002/10/22 17:58:14 roberto Exp roberto $ | 2 | ** $Id: lstate.h,v 1.99 2002/10/25 20:05:28 roberto Exp roberto $ |
3 | ** Global State | 3 | ** Global State |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -83,7 +83,7 @@ typedef struct CallInfo { | |||
83 | StkId *pb; /* points to `base' variable in `luaV_execute' */ | 83 | StkId *pb; /* points to `base' variable in `luaV_execute' */ |
84 | } l; | 84 | } l; |
85 | struct { /* for C functions */ | 85 | struct { /* for C functions */ |
86 | int yield_results; | 86 | int dummy; /* just to avoid an empty struct */ |
87 | } c; | 87 | } c; |
88 | } u; | 88 | } u; |
89 | } CallInfo; | 89 | } CallInfo; |
@@ -99,6 +99,7 @@ typedef struct CallInfo { | |||
99 | `pc' is being used by the other, and therefore CI_SAVEDPC is 1 too) */ | 99 | `pc' is being used by the other, and therefore CI_SAVEDPC is 1 too) */ |
100 | #define CI_CALLING 4 | 100 | #define CI_CALLING 4 |
101 | #define CI_SAVEDPC 8 /* 1 if `savedpc' is updated */ | 101 | #define CI_SAVEDPC 8 /* 1 if `savedpc' is updated */ |
102 | #define CI_YIELD 16 /* 1 if thread is suspended */ | ||
102 | 103 | ||
103 | 104 | ||
104 | #define ci_func(ci) (clvalue((ci)->base - 1)) | 105 | #define ci_func(ci) (clvalue((ci)->base - 1)) |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lua.h,v 1.160 2002/10/25 20:05:28 roberto Exp roberto $ | 2 | ** $Id: lua.h,v 1.161 2002/10/25 21:31:28 roberto Exp roberto $ |
3 | ** Lua - An Extensible Extension Language | 3 | ** Lua - An Extensible Extension Language |
4 | ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil | 4 | ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil |
5 | ** http://www.lua.org mailto:info@lua.org | 5 | ** http://www.lua.org mailto:info@lua.org |
@@ -123,6 +123,8 @@ LUA_API void lua_insert (lua_State *L, int idx); | |||
123 | LUA_API void lua_replace (lua_State *L, int idx); | 123 | LUA_API void lua_replace (lua_State *L, int idx); |
124 | LUA_API int lua_checkstack (lua_State *L, int sz); | 124 | LUA_API int lua_checkstack (lua_State *L, int sz); |
125 | 125 | ||
126 | LUA_API void lua_movethread (lua_State *from, lua_State *to, int n); | ||
127 | |||
126 | 128 | ||
127 | /* | 129 | /* |
128 | ** access functions (stack -> C) | 130 | ** access functions (stack -> C) |
@@ -201,9 +203,8 @@ LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data); | |||
201 | /* | 203 | /* |
202 | ** coroutine functions | 204 | ** coroutine functions |
203 | */ | 205 | */ |
204 | LUA_API void lua_cobegin (lua_State *L, int nargs); | ||
205 | LUA_API int lua_yield (lua_State *L, int nresults); | 206 | LUA_API int lua_yield (lua_State *L, int nresults); |
206 | LUA_API int lua_resume (lua_State *L, lua_State *co); | 207 | LUA_API int lua_resume (lua_State *L, int narg); |
207 | 208 | ||
208 | /* | 209 | /* |
209 | ** Garbage-collection functions | 210 | ** Garbage-collection functions |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 1.257 2002/10/08 18:46:08 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 1.258 2002/10/25 20:05:28 roberto Exp roberto $ |
3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -592,6 +592,7 @@ StkId luaV_execute (lua_State *L) { | |||
592 | if (firstResult > L->top) { /* yield? */ | 592 | if (firstResult > L->top) { /* yield? */ |
593 | (L->ci - 1)->u.l.savedpc = pc; | 593 | (L->ci - 1)->u.l.savedpc = pc; |
594 | (L->ci - 1)->state = CI_SAVEDPC; | 594 | (L->ci - 1)->state = CI_SAVEDPC; |
595 | L->ci->state |= CI_YIELD; | ||
595 | return NULL; | 596 | return NULL; |
596 | } | 597 | } |
597 | /* it was a C function (`precall' called it); adjust results */ | 598 | /* it was a C function (`precall' called it); adjust results */ |