aboutsummaryrefslogtreecommitdiff
path: root/ldo.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2009-04-08 15:04:33 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2009-04-08 15:04:33 -0300
commit70a63fa5adfb2480ce385502f1d0306000217690 (patch)
treebcf7b3e8ac2c1c995a5bbc83678d1be7e6eef62c /ldo.c
parentfffbaede758abe3b460621962113c352dbd7c605 (diff)
downloadlua-70a63fa5adfb2480ce385502f1d0306000217690.tar.gz
lua-70a63fa5adfb2480ce385502f1d0306000217690.tar.bz2
lua-70a63fa5adfb2480ce385502f1d0306000217690.zip
first implementation of yieldable 'pcall'
Diffstat (limited to 'ldo.c')
-rw-r--r--ldo.c65
1 files changed, 53 insertions, 12 deletions
diff --git a/ldo.c b/ldo.c
index 2afcd7af..79bc41d6 100644
--- a/ldo.c
+++ b/ldo.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ldo.c,v 2.56 2009/03/23 14:26:12 roberto Exp roberto $ 2** $Id: ldo.c,v 2.57 2009/03/26 12:56:38 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*/
@@ -369,9 +369,14 @@ static void finishCcall (lua_State *L) {
369 lua_assert(L->nny == 0); 369 lua_assert(L->nny == 0);
370 /* finish 'luaD_call' */ 370 /* finish 'luaD_call' */
371 G(L)->nCcalls--; 371 G(L)->nCcalls--;
372 /* finish 'lua_callcont' */ 372 /* finish 'lua_callk' */
373 adjustresults(L, (L->ci + 1)->nresults); 373 adjustresults(L, (L->ci + 1)->nresults);
374 /* call continuation function */ 374 /* call continuation function */
375 if (!(L->ci->callstatus & CIST_STAT)) /* no call status? */
376 L->ci->u.c.status = LUA_YIELD; /* 'default' status */
377 lua_assert(L->ci->u.c.status != LUA_OK);
378 L->ci->callstatus = (L->ci->callstatus & ~(CIST_YPCALL | CIST_STAT))
379 | CIST_YIELDED;
375 lua_unlock(L); 380 lua_unlock(L);
376 n = (*L->ci->u.c.k)(L); 381 n = (*L->ci->u.c.k)(L);
377 lua_lock(L); 382 lua_lock(L);
@@ -380,7 +385,8 @@ static void finishCcall (lua_State *L) {
380} 385}
381 386
382 387
383static void unroll (lua_State *L) { 388static void unroll (lua_State *L, void *ud) {
389 UNUSED(ud);
384 for (;;) { 390 for (;;) {
385 if (L->ci == L->base_ci) /* stack is empty? */ 391 if (L->ci == L->base_ci) /* stack is empty? */
386 return; /* coroutine finished normally */ 392 return; /* coroutine finished normally */
@@ -413,7 +419,7 @@ static void resume (lua_State *L, void *ud) {
413 G(L)->nCcalls--; /* finish 'luaD_call' */ 419 G(L)->nCcalls--; /* finish 'luaD_call' */
414 luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ 420 luaD_poscall(L, firstArg); /* finish 'luaD_precall' */
415 } 421 }
416 unroll(L); 422 unroll(L, NULL);
417 } 423 }
418} 424}
419 425
@@ -427,6 +433,39 @@ static int resume_error (lua_State *L, const char *msg) {
427} 433}
428 434
429 435
436/*
437** check whether thread has a suspended protected call
438*/
439static CallInfo *findpcall (lua_State *L) {
440 CallInfo *ci;
441 for (ci = L->ci; ci > L->base_ci; ci--) { /* search for first pcall */
442 if (ci->callstatus & CIST_YPCALL)
443 return ci;
444 }
445 return NULL; /* no pending pcall */
446}
447
448
449static int recover (lua_State *L, int status) {
450 StkId oldtop;
451 CallInfo *ci = findpcall(L);
452 if (ci == NULL) return 0; /* no recovery point */
453 /* "finish" luaD_pcall */
454 oldtop = restorestack(L, ci->u.c.oldtop);
455 luaF_close(L, oldtop);
456 luaD_seterrorobj(L, status, oldtop);
457 L->ci = ci;
458 L->base = L->ci->base;
459 L->allowhook = ci->u.c.old_allowhook;
460 L->nny = 0; /* should be zero to be yieldable */
461 restore_stack_limit(L);
462 L->errfunc = ci->u.c.old_errfunc;
463 ci->callstatus |= CIST_STAT; /* call has error status */
464 ci->u.c.status = status; /* (here it is) */
465 return 1; /* continue running the coroutine */
466}
467
468
430LUA_API int lua_resume (lua_State *L, int nargs) { 469LUA_API int lua_resume (lua_State *L, int nargs) {
431 int status; 470 int status;
432 lua_lock(L); 471 lua_lock(L);
@@ -437,20 +476,22 @@ LUA_API int lua_resume (lua_State *L, int nargs) {
437 return resume_error(L, "cannot resume non-suspended coroutine"); 476 return resume_error(L, "cannot resume non-suspended coroutine");
438 } 477 }
439 luai_userstateresume(L, nargs); 478 luai_userstateresume(L, nargs);
440 lua_assert(L->errfunc == 0);
441 if (G(L)->nCcalls >= LUAI_MAXCCALLS) 479 if (G(L)->nCcalls >= LUAI_MAXCCALLS)
442 return resume_error(L, "C stack overflow"); 480 return resume_error(L, "C stack overflow");
443 ++G(L)->nCcalls; /* count resume */ 481 ++G(L)->nCcalls; /* count resume */
444 L->nny = 0; /* allow yields */ 482 L->nny = 0; /* allow yields */
445 status = luaD_rawrunprotected(L, resume, L->top - nargs); 483 status = luaD_rawrunprotected(L, resume, L->top - nargs);
446 if (status != LUA_OK && status != LUA_YIELD) { /* error? */ 484 while (status != LUA_OK && status != LUA_YIELD) { /* error? */
447 L->status = cast_byte(status); /* mark thread as `dead' */ 485 if (recover(L, status)) /* recover point? */
448 luaD_seterrorobj(L, status, L->top); 486 status = luaD_rawrunprotected(L, unroll, NULL); /* run continuation */
449 L->ci->top = L->top; 487 else { /* unrecoverable error */
450 } 488 L->status = cast_byte(status); /* mark thread as `dead' */
451 else { 489 luaD_seterrorobj(L, status, L->top);
452 lua_assert(status == L->status); 490 L->ci->top = L->top;
491 break;
492 }
453 } 493 }
494 lua_assert(status == L->status);
454 L->nny = 1; /* do not allow yields */ 495 L->nny = 1; /* do not allow yields */
455 --G(L)->nCcalls; 496 --G(L)->nCcalls;
456 lua_unlock(L); 497 lua_unlock(L);