aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2002-11-06 17:08:00 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2002-11-06 17:08:00 -0200
commit118347d8c3b83ea0291918e81c5367937316fabb (patch)
treeb77d5b6e03d9ae20841bd80a50cc56237bdf16f5
parent6820da509686ce06fdb3de58856056476f55f534 (diff)
downloadlua-118347d8c3b83ea0291918e81c5367937316fabb.tar.gz
lua-118347d8c3b83ea0291918e81c5367937316fabb.tar.bz2
lua-118347d8c3b83ea0291918e81c5367937316fabb.zip
new API for coroutines
-rw-r--r--lapi.c15
-rw-r--r--lbaselib.c46
-rw-r--r--ldo.c97
-rw-r--r--lstate.h5
-rw-r--r--lua.h7
-rw-r--r--lvm.c3
6 files changed, 85 insertions, 88 deletions
diff --git a/lapi.c b/lapi.c
index 2c5b8a06..e86d2ac6 100644
--- a/lapi.c
+++ b/lapi.c
@@ -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
108LUA_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
108LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { 121LUA_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);
diff --git a/lbaselib.c b/lbaselib.c
index 1e80c42a..226c7a4b 100644
--- a/lbaselib.c
+++ b/lbaselib.c
@@ -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 560static int auxresume (lua_State *L, lua_State *co, int narg) {
561static 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
587static int luaB_auxwrap (lua_State *L) { 598static 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
594static int luaB_cocreate (lua_State *L) { 606static 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
diff --git a/ldo.c b/ldo.c
index 9ae6a116..19968f32 100644
--- a/ldo.c
+++ b/ldo.c
@@ -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
47static void seterrorobj (lua_State *L, int errcode) { 47static 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
301LUA_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
308static 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
317static void resume (lua_State *L, void *ud) { 302static 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
340LUA_API int lua_resume (lua_State *L, lua_State *co) { 329LUA_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}
diff --git a/lstate.h b/lstate.h
index 9d88de6c..f14738ba 100644
--- a/lstate.h
+++ b/lstate.h
@@ -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))
diff --git a/lua.h b/lua.h
index 3fef586d..6bcc2d4d 100644
--- a/lua.h
+++ b/lua.h
@@ -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);
123LUA_API void lua_replace (lua_State *L, int idx); 123LUA_API void lua_replace (lua_State *L, int idx);
124LUA_API int lua_checkstack (lua_State *L, int sz); 124LUA_API int lua_checkstack (lua_State *L, int sz);
125 125
126LUA_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*/
204LUA_API void lua_cobegin (lua_State *L, int nargs);
205LUA_API int lua_yield (lua_State *L, int nresults); 206LUA_API int lua_yield (lua_State *L, int nresults);
206LUA_API int lua_resume (lua_State *L, lua_State *co); 207LUA_API int lua_resume (lua_State *L, int narg);
207 208
208/* 209/*
209** Garbage-collection functions 210** Garbage-collection functions
diff --git a/lvm.c b/lvm.c
index 8b72ae92..86e1596b 100644
--- a/lvm.c
+++ b/lvm.c
@@ -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 */