diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2009-03-10 14:14:37 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2009-03-10 14:14:37 -0300 |
commit | ba484b9eb16dd62a7c3a5400a66eb952b654d3f0 (patch) | |
tree | 31692ddf85265e5a46eab0cd55a0b0757a225e68 /ldo.c | |
parent | f9d015523ef48266cea37e13717c223c16941b23 (diff) | |
download | lua-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.c | 103 |
1 files changed, 41 insertions, 62 deletions
@@ -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 | */ |
368 | void luaD_call (lua_State *L, StkId func, int nResults) { | 369 | void 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 | ||
386 | static 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 | |||
383 | static void unroll (lua_State *L) { | 403 | static 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) { | |||
504 | LUA_API int lua_yield (lua_State *L, int nresults) { | 481 | LUA_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; |