aboutsummaryrefslogtreecommitdiff
path: root/ldo.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2009-03-10 14:14:37 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2009-03-10 14:14:37 -0300
commitba484b9eb16dd62a7c3a5400a66eb952b654d3f0 (patch)
tree31692ddf85265e5a46eab0cd55a0b0757a225e68 /ldo.c
parentf9d015523ef48266cea37e13717c223c16941b23 (diff)
downloadlua-ba484b9eb16dd62a7c3a5400a66eb952b654d3f0.tar.gz
lua-ba484b9eb16dd62a7c3a5400a66eb952b654d3f0.tar.bz2
lua-ba484b9eb16dd62a7c3a5400a66eb952b654d3f0.zip
yielding across lua_call (first version)
Diffstat (limited to 'ldo.c')
-rw-r--r--ldo.c103
1 files changed, 41 insertions, 62 deletions
diff --git a/ldo.c b/ldo.c
index effef571..bf21e609 100644
--- a/ldo.c
+++ b/ldo.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ldo.c,v 2.53 2009/03/03 18:51:24 roberto Exp roberto $ 2** $Id: ldo.c,v 2.54 2009/03/04 13:32:29 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*/
@@ -14,6 +14,7 @@
14 14
15#include "lua.h" 15#include "lua.h"
16 16
17#include "lapi.h"
17#include "ldebug.h" 18#include "ldebug.h"
18#include "ldo.h" 19#include "ldo.h"
19#include "lfunc.h" 20#include "lfunc.h"
@@ -365,7 +366,7 @@ int luaD_poscall (lua_State *L, StkId firstResult) {
365** When returns, all the results are on the stack, starting at the original 366** When returns, all the results are on the stack, starting at the original
366** function position. 367** function position.
367*/ 368*/
368void luaD_call (lua_State *L, StkId func, int nResults) { 369void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) {
369 global_State *g = G(L); 370 global_State *g = G(L);
370 if (++g->nCcalls >= LUAI_MAXCCALLS) { 371 if (++g->nCcalls >= LUAI_MAXCCALLS) {
371 if (g->nCcalls == LUAI_MAXCCALLS) 372 if (g->nCcalls == LUAI_MAXCCALLS)
@@ -373,64 +374,41 @@ void luaD_call (lua_State *L, StkId func, int nResults) {
373 else if (g->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) 374 else if (g->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
374 luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ 375 luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
375 } 376 }
377 if (!allowyield) L->nny++;
376 if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ 378 if (!luaD_precall(L, func, nResults)) /* is a Lua function? */
377 luaV_execute(L); /* call it */ 379 luaV_execute(L); /* call it */
380 if (!allowyield) L->nny--;
378 g->nCcalls--; 381 g->nCcalls--;
379 luaC_checkGC(L); 382 luaC_checkGC(L);
380} 383}
381 384
382 385
386static void finishCcall (lua_State *L) {
387 int n;
388 lua_assert(L->ci->u.c.cont != NULL); /* must have a continuation */
389 lua_assert(L->nny == 0);
390 /* finish 'luaD_call' */
391 G(L)->nCcalls--;
392 /* finish 'lua_callcont' */
393 adjustresults(L, (L->ci + 1)->nresults);
394 /* call continuation function */
395 lua_unlock(L);
396 n = (*L->ci->u.c.cont)(L);
397 lua_lock(L);
398 /* finish 'luaD_precall' */
399 luaD_poscall(L, L->top - n);
400}
401
402
383static void unroll (lua_State *L) { 403static void unroll (lua_State *L) {
384 for (;;) { 404 for (;;) {
385 Instruction inst; 405 if (L->ci == L->base_ci) /* stack is empty? */
386 luaV_execute(L); /* execute down to higher C 'boundary' */
387 if (L->ci == L->base_ci) { /* stack is empty? */
388 lua_assert(L->baseCcalls == G(L)->nCcalls);
389 return; /* coroutine finished normally */ 406 return; /* coroutine finished normally */
390 } 407 if (!isLua(L->ci)) /* C function? */
391 L->baseCcalls--; /* undo increment that allows yields */ 408 finishCcall(L);
392 inst = *(L->savedpc - 1); /* interrupted instruction */ 409 else { /* Lua function */
393 switch (GET_OPCODE(inst)) { /* finish its execution */ 410 luaV_finishOp(L); /* finish interrupted instruction */
394 case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: 411 luaV_execute(L); /* execute down to higher C 'boundary' */
395 case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN:
396 case OP_GETGLOBAL: case OP_GETTABLE: case OP_SELF: {
397 setobjs2s(L, L->base + GETARG_A(inst), --L->top);
398 break;
399 }
400 case OP_LE: case OP_LT: case OP_EQ: {
401 int res = !l_isfalse(L->top - 1);
402 L->top--;
403 /* metamethod should not be called when operand is K */
404 lua_assert(!ISK(GETARG_B(inst)));
405 if (GET_OPCODE(inst) == OP_LE && /* "<=" using "<" instead? */
406 ttisnil(luaT_gettmbyobj(L, L->base + GETARG_B(inst), TM_LE)))
407 res = !res; /* invert result */
408 lua_assert(GET_OPCODE(*L->savedpc) == OP_JMP);
409 if (res != GETARG_A(inst)) /* condition failed? */
410 L->savedpc++; /* skip jump instruction */
411 break;
412 }
413 case OP_CONCAT: {
414 StkId top = L->top - 1; /* top when __concat was called */
415 int last = cast_int(top - L->base) - 2; /* last element and ... */
416 int b = GETARG_B(inst); /* ... first element to concatenate */
417 int total = last - b + 1; /* number of elements to concatenate */
418 setobj2s(L, top - 2, top); /* put TM result in proper position */
419 L->top = L->ci->top; /* correct top */
420 if (total > 1) /* are there elements to concat? */
421 luaV_concat(L, total, last); /* concat them (may yield again) */
422 /* move final result to final position */
423 setobj2s(L, L->base + GETARG_A(inst), L->base + b);
424 continue;
425 }
426 case OP_TFORCALL: {
427 lua_assert(GET_OPCODE(*L->savedpc) == OP_TFORLOOP);
428 L->top = L->ci->top; /* correct top */
429 break;
430 }
431 case OP_SETGLOBAL: case OP_SETTABLE:
432 break; /* nothing to be done */
433 default: lua_assert(0);
434 } 412 }
435 } 413 }
436} 414}
@@ -441,23 +419,22 @@ static void resume (lua_State *L, void *ud) {
441 CallInfo *ci = L->ci; 419 CallInfo *ci = L->ci;
442 if (L->status == LUA_OK) { /* start coroutine? */ 420 if (L->status == LUA_OK) { /* start coroutine? */
443 lua_assert(ci == L->base_ci && firstArg > L->base); 421 lua_assert(ci == L->base_ci && firstArg > L->base);
444 if (luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* C function? */ 422 if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */
445 return; /* done */ 423 luaV_execute(L); /* call it */
446 } 424 }
447 else { /* resuming from previous yield */ 425 else { /* resuming from previous yield */
448 lua_assert(L->status == LUA_YIELD); 426 lua_assert(L->status == LUA_YIELD);
449 L->status = LUA_OK; 427 L->status = LUA_OK;
450 if (isLua(ci)) /* yielded inside a hook? */ 428 if (isLua(ci)) { /* yielded inside a hook? */
451 L->base = L->ci->base; /* just continue its execution */ 429 L->base = L->ci->base; /* just continue its execution */
430 luaV_execute(L);
431 }
452 else { /* 'common' yield */ 432 else { /* 'common' yield */
453 /* finish interrupted execution of `OP_CALL' */ 433 G(L)->nCcalls--; /* finish 'luaD_call' */
454 lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || 434 luaD_poscall(L, firstArg); /* finish 'luaD_precall' */
455 GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL);
456 if (luaD_poscall(L, firstArg)) /* complete it... */
457 L->top = L->ci->top; /* and correct top if not multiple results */
458 } 435 }
436 unroll(L);
459 } 437 }
460 unroll(L);
461} 438}
462 439
463 440
@@ -484,7 +461,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) {
484 if (G(L)->nCcalls >= LUAI_MAXCCALLS) 461 if (G(L)->nCcalls >= LUAI_MAXCCALLS)
485 return resume_error(L, "C stack overflow"); 462 return resume_error(L, "C stack overflow");
486 ++G(L)->nCcalls; /* count resume */ 463 ++G(L)->nCcalls; /* count resume */
487 L->baseCcalls += G(L)->nCcalls; 464 L->nny = 0; /* allow yields */
488 status = luaD_rawrunprotected(L, resume, L->top - nargs); 465 status = luaD_rawrunprotected(L, resume, L->top - nargs);
489 if (status != LUA_OK && status != LUA_YIELD) { /* error? */ 466 if (status != LUA_OK && status != LUA_YIELD) { /* error? */
490 L->status = cast_byte(status); /* mark thread as `dead' */ 467 L->status = cast_byte(status); /* mark thread as `dead' */
@@ -494,7 +471,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) {
494 else { 471 else {
495 lua_assert(status == L->status); 472 lua_assert(status == L->status);
496 } 473 }
497 L->baseCcalls -= G(L)->nCcalls; 474 L->nny = 1; /* do not allow yields */
498 --G(L)->nCcalls; 475 --G(L)->nCcalls;
499 lua_unlock(L); 476 lua_unlock(L);
500 return status; 477 return status;
@@ -504,7 +481,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) {
504LUA_API int lua_yield (lua_State *L, int nresults) { 481LUA_API int lua_yield (lua_State *L, int nresults) {
505 luai_userstateyield(L, nresults); 482 luai_userstateyield(L, nresults);
506 lua_lock(L); 483 lua_lock(L);
507 if (G(L)->nCcalls > L->baseCcalls) 484 if (L->nny > 0)
508 luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); 485 luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
509 L->base = L->top - nresults; /* protect stack slots below */ 486 L->base = L->top - nresults; /* protect stack slots below */
510 L->status = LUA_YIELD; 487 L->status = LUA_YIELD;
@@ -521,6 +498,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u,
521 int status; 498 int status;
522 ptrdiff_t old_ci = saveci(L, L->ci); 499 ptrdiff_t old_ci = saveci(L, L->ci);
523 lu_byte old_allowhooks = L->allowhook; 500 lu_byte old_allowhooks = L->allowhook;
501 unsigned short old_nny = L->nny;
524 ptrdiff_t old_errfunc = L->errfunc; 502 ptrdiff_t old_errfunc = L->errfunc;
525 L->errfunc = ef; 503 L->errfunc = ef;
526 status = luaD_rawrunprotected(L, func, u); 504 status = luaD_rawrunprotected(L, func, u);
@@ -532,6 +510,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u,
532 L->base = L->ci->base; 510 L->base = L->ci->base;
533 L->savedpc = L->ci->savedpc; 511 L->savedpc = L->ci->savedpc;
534 L->allowhook = old_allowhooks; 512 L->allowhook = old_allowhooks;
513 L->nny = old_nny;
535 restore_stack_limit(L); 514 restore_stack_limit(L);
536 } 515 }
537 L->errfunc = old_errfunc; 516 L->errfunc = old_errfunc;