diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2009-04-08 15:04:33 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2009-04-08 15:04:33 -0300 |
commit | 70a63fa5adfb2480ce385502f1d0306000217690 (patch) | |
tree | bcf7b3e8ac2c1c995a5bbc83678d1be7e6eef62c /ldo.c | |
parent | fffbaede758abe3b460621962113c352dbd7c605 (diff) | |
download | lua-70a63fa5adfb2480ce385502f1d0306000217690.tar.gz lua-70a63fa5adfb2480ce385502f1d0306000217690.tar.bz2 lua-70a63fa5adfb2480ce385502f1d0306000217690.zip |
first implementation of yieldable 'pcall'
Diffstat (limited to 'ldo.c')
-rw-r--r-- | ldo.c | 65 |
1 files changed, 53 insertions, 12 deletions
@@ -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 | ||
383 | static void unroll (lua_State *L) { | 388 | static 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 | */ | ||
439 | static 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 | |||
449 | static 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 | |||
430 | LUA_API int lua_resume (lua_State *L, int nargs) { | 469 | LUA_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); |