2003-08-15 18:00:22 +00:00
|
|
|
#include "ltask.h"
|
|
|
|
#include "lmem.h"
|
|
|
|
#include "ldo.h"
|
|
|
|
#include "lvm.h"
|
|
|
|
|
|
|
|
int task_tag;
|
|
|
|
|
|
|
|
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 &&
|
|
|
|
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 &&
|
|
|
|
tfvalue(t->stack.stack) == tfvalue(f))
|
|
|
|
break;
|
|
|
|
break;
|
2003-08-21 10:29:36 +00:00
|
|
|
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 = 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;
|
|
|
|
}
|
|
|
|
|
2003-08-16 20:12:02 +00:00
|
|
|
void GetCurrentScript (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);
|
|
|
|
}
|