static SQInteger thread_wakeup(HSQUIRRELVM v) { SQObjectPtr o = stack_get(v,1); if(type(o) == OT_THREAD) { SQVM *thread = _thread(o); SQInteger state = sq_getvmstate(thread); if(state != SQ_VMSTATE_SUSPENDED) { switch(state) { case SQ_VMSTATE_IDLE: return sq_throwerror(v,_SC("cannot wakeup a idle thread")); break; case SQ_VMSTATE_RUNNING: return sq_throwerror(v,_SC("cannot wakeup a running thread")); break; } } SQInteger wakeupret = sq_gettop(v)>1?1:0; if(wakeupret) { sq_move(thread,v,2); } if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,1,SQFalse))) { sq_move(v,thread,-1); sq_pop(thread,1); if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) { sq_pop(thread,1); } return 1; } return SQ_ERROR; } return sq_throwerror(v,_SC("wrong parameter")); }
static SQInteger thread_call(HSQUIRRELVM v) { SQObjectPtr o = stack_get(v,1); if(type(o) == OT_THREAD) { SQInteger nparams = sq_gettop(v); _thread(o)->Push(_thread(o)->_roottable); for(SQInteger i = 2; i<(nparams+1); i++) sq_move(_thread(o),v,i); if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue,SQFalse))) { sq_move(v,_thread(o),-1); return 1; } return SQ_ERROR; } return sq_throwerror(v,_SC("wrong parameter")); }
static SQInteger thread_getstackinfos(HSQUIRRELVM v) { SQObjectPtr o = stack_get(v,1); if(type(o) == OT_THREAD) { SQVM *thread = _thread(o); SQInteger threadtop = sq_gettop(thread); SQInteger level; sq_getinteger(v,-1,&level); SQRESULT res = __getcallstackinfos(thread,level); if(SQ_FAILED(res)) { sq_settop(thread,threadtop); if(type(thread->_lasterror) == OT_STRING) { sq_throwerror(v,_stringval(thread->_lasterror)); } else { sq_throwerror(v,_SC("unknown error")); } } if(res > 0) { //some result sq_move(v,thread,-1); sq_settop(thread,threadtop); return 1; } //no result sq_settop(thread,threadtop); return 0; } return sq_throwerror(v,_SC("wrong parameter")); }
static SQInteger base_newthread(HSQUIRRELVM v) { SQObjectPtr &func = stack_get(v,2); SQInteger stksize = (_funcproto(_closure(func)->_function)->_stacksize << 1) +2; HSQUIRRELVM newv = sq_newthread(v, (stksize < MIN_STACK_OVERHEAD + 2)? MIN_STACK_OVERHEAD + 2 : stksize); sq_move(newv,v,-2); return 1; }
/** * ベースVM上でスクリプトを実行する。 * この呼び出しはスレッドによるものではないため、処理中に suspend() / wait() を * 呼ぶとエラーになるので注意してください。必ず1度で呼びきれるものを渡す必要があります。 * @param func グローバル関数。※ファイルは指定できません * @param ... 引数 */ SQRESULT Thread::global_execOnBase(HSQUIRRELVM v) { SQInteger max = sq_gettop(v); if (max <= 1) { return ERROR_INVALIDPARAM(v); } HSQUIRRELVM gv = getGlobalVM(); SQRESULT result = SQ_OK; if (gv == v) { sq_push(gv, 2); sq_pushroottable(gv); // 引数:self(root) int argc = 1; for (int i=3;i<=max;i++) { sq_push(v, i); argc++; } if (SQ_SUCCEEDED(result = sq_call(gv, argc, SQTrue, SQTrue))) { sq_remove(gv, -2); // func } else { sq_pop(gv, 1); // func } } else { sq_move(gv, v, 2); // func sq_pushroottable(gv); // 引数:self(root) int argc = 1; for (int i=3;i<=max;i++) { sq_move(gv, v, i); argc++; } if (SQ_SUCCEEDED(result = sq_call(gv, argc, SQTrue, SQTrue))) { sq_move(v, gv, sq_gettop(gv)); sq_pop(gv, 2); } else { sq_pop(gv, 1); // func } } return result; }
/** * 内部用:fork 処理。スレッドを1つ生成して VMにPUSHする * @param v squirrelVM * @return 成功したら true */ bool Thread::_fork(HSQUIRRELVM v) { // スレッドオブジェクトはグローバル上に生成する SQInteger max = sq_gettop(v); HSQUIRRELVM gv = getGlobalVM(); sq_pushroottable(gv); // root sq_pushstring(gv, SQTHREADNAME, -1); if (SQ_SUCCEEDED(sq_get(gv,-2))) { // class sq_pushroottable(gv); // 引数:self(root) sq_pushnull(gv); // 引数:delegate // 引数をコピー int argc = 2; if (gv == v) { for (int i=2;i<=max;i++) { sq_push(gv,i); argc++; } } else { for (int i=2;i<=max;i++) { sq_move(gv, v, i); argc++; } } if (SQ_SUCCEEDED(sq_call(gv, argc, SQTrue, SQTrue))) { // コンストラクタ呼び出し if (gv == v) { sq_remove(gv, -2); // class sq_remove(gv, -2); // root } else { sq_move(v, gv, sq_gettop(gv)); // 元VMのほうに移す sq_pop(gv, 3); // thread,class,root } return true; } sq_pop(gv, 1); // class } sq_pop(gv,1); // root return false; }