scummvm/lua/ltask.cpp

231 lines
5.6 KiB
C++
Raw Normal View History

2003-08-15 18:00:22 +00:00
#include "ltask.h"
#include "lmem.h"
#include "ldo.h"
#include "lvm.h"
int task_tag;
void pause_scripts (void) {
}
void unpause_scripts (void) {
}
2003-08-15 18:00:22 +00:00
void start_script (void) {
struct lua_Task *old_task = L->curr_task, *new_task;
TObject *f;
int i;
f = L->stack.stack + L->Cstack.lua2C;
if (ttype(f) == LUA_T_CLOSURE)
f = &clvalue(f)->consts[0];
if (ttype(f) != LUA_T_PROTO)
lua_error("can only start_script with a Lua function");
/* Create a new task with an empty stack */
new_task = luaI_newtask();
/* Put the function and arguments onto the new task's stack */
for (i = 0; i < old_task->Cstack.num; i++) {
*(L->stack.top) = *(old_task->stack.stack + old_task->Cstack.lua2C + i);
incr_top;
}
/* Create a CallInfo frame */
luaD_precall(L->stack.stack, 1, MULT_RET);
ttype(L->stack.stack) = (ttype(L->stack.stack) == LUA_T_CLOSURE) ?
LUA_T_CLMARK : LUA_T_PMARK;
/* Switch back to the old task */
L->Tstate = YIELD;
luaI_switchtask(old_task);
L->curr_task = old_task;
/* Insert new task at end of list */
L->last_task->next = new_task;
L->last_task = new_task;
/* Return task handle */
lua_pushusertag(new_task, task_tag);
}
void stop_script (void) {
struct lua_Task *prev, *t;
TObject *f = L->stack.stack + L->Cstack.lua2C;
int match;
if (ttype(f) != LUA_T_CLOSURE && ttype(f) != LUA_T_PROTO &&
! (ttype(f) == LUA_T_USERDATA && f->value.ts->u.d.tag == task_tag))
lua_error("Bad argument to stop_script");
prev = L->root_task;
while ((t = prev->next) != NULL) {
switch (ttype(f)) {
case LUA_T_CLOSURE:
match = (ttype(t->stack.stack) == LUA_T_CLMARK &&
clvalue(t->stack.stack) == clvalue(f));
break;
case LUA_T_PROTO:
match = (ttype(t->stack.stack) == LUA_T_PMARK &&
tfvalue(t->stack.stack) == tfvalue(f));
break;
case LUA_T_USERDATA:
match = (t == f->value.ts->u.d.v);
break;
default: /* Shut up gcc */
break;
}
if (match) {
prev->next = t->next; /* Remove from list of active tasks */
t->next = NULL;
if (prev->next == NULL)
L->last_task = prev;
if (t == L->curr_task)
L->Tstate = DONE;
else {
t->Tstate = DONE;
if (t->auto_delete)
luaM_free(t);
}
}
else
prev = t;
}
}
void next_script (void) {
struct lua_Task *t;
if (lua_isnil(lua_getparam(1)))
t = L->root_task;
else if (lua_isuserdata(lua_getparam(1)) &&
lua_tag(lua_getparam(1)) == task_tag)
t = (struct lua_Task *) lua_getuserdata(lua_getparam(1));
else
lua_error("Bad argument to next_script");
t = t->next;
if (t == NULL)
lua_pushnil();
else {
t->auto_delete = 0;
lua_pushusertag(t, task_tag);
}
}
void identify_script (void) {
struct lua_Task *t;
if (! lua_isuserdata(lua_getparam(1)) ||
lua_tag(lua_getparam(1)) != task_tag)
lua_error("Bad argument to identify_script");
t = (struct lua_Task *) lua_getuserdata(lua_getparam(1));
if (t->Tstate == DONE)
ttype(L->stack.top) = LUA_T_NIL;
else
*L->stack.top = *t->stack.stack;
incr_top;
}
void find_script (void) {
struct lua_Task *t;
TObject *f = L->stack.stack + L->Cstack.lua2C;
switch (ttype(f)) {
case LUA_T_CLOSURE:
for (t = L->root_task->next; t != NULL; t = t->next)
if ((ttype(t->stack.stack) == LUA_T_CLOSURE ||
ttype(t->stack.stack) == LUA_T_CMARK) &&
2003-08-15 18:00:22 +00:00
clvalue(t->stack.stack) == clvalue(f))
break;
break;
case LUA_T_PROTO:
for (t = L->root_task->next; t != NULL; t = t->next)
if ((ttype(t->stack.stack) == LUA_T_PROTO ||
ttype(t->stack.stack) == LUA_T_PMARK) &&
2003-08-15 18:00:22 +00:00
tfvalue(t->stack.stack) == tfvalue(f))
break;
break;
case LUA_T_USERDATA:
if (f->value.ts->u.d.tag != task_tag)
lua_error("Bad argument to find_script");
/* Shortcut: just see whether it's still running */
t = (lua_Task *)f->value.ts->u.d.v;
if (t->Tstate == DONE)
lua_pushnil();
else
lua_pushusertag(t, task_tag);
return;
2003-08-15 18:00:22 +00:00
default:
lua_error("Bad argument to find_script");
}
if (t == NULL)
lua_pushnil();
else {
t->auto_delete = 0;
lua_pushusertag(t, task_tag);
}
}
void break_here (void) {
struct CallInfo *ci;
if (L->curr_task == L->root_task)
lua_error("Cannot break in root thread");
/* Check for any C functions in the call stack */
for (ci = L->ci-1; ci > L->base_ci; ci--)
if (ci->tf == NULL)
lua_error("Cannot yield through C function");
L->Tstate = YIELD;
}
void current_script (void) {
if (L->curr_task == L->root_task)
lua_pushnil();
else {
L->curr_task->auto_delete = 0;
lua_pushusertag(L->curr_task, task_tag);
}
}
2003-08-15 18:00:22 +00:00
void lua_runtasks (void) {
struct lua_Task *t, *prev;
struct lua_Task *old_task = L->curr_task;
jmp_buf myErrorJmp;
prev = L->root_task;
while ((t = prev->next) != NULL) {
luaI_switchtask(t);
L->errorJmp = &myErrorJmp;
L->Tstate = RUN;
if (setjmp(myErrorJmp) == 0) {
luaV_execute(L->base_ci+1);
if (L->Tstate == RUN) /* Must have run to completion */
L->Tstate = DONE;
}
else /* an error occurred */
L->Tstate = DONE;
L->errorJmp = NULL;
if (L->Tstate == DONE) { /* Remove from list of active tasks */
luaI_switchtask(old_task);
prev->next = t->next;
t->next = NULL;
if (prev->next == NULL)
L->last_task = prev;
if (t->auto_delete)
luaM_free(t);
}
else
prev = t;
}
if (L->curr_task != old_task)
luaI_switchtask(old_task);
}
void gc_task (void) {
struct lua_Task *t = (struct lua_Task *) lua_getuserdata(lua_getparam(1));
t->auto_delete = 1;
if (t != L->curr_task && t->Tstate == DONE)
luaM_free(t);
}