static struct sys_thread * thread_newvm (lua_State *L, struct sys_thread *reftd, unsigned int loadlibs) { struct sys_vmthread *vmtd; lua_State *NL; if (L) { NL = lua_newthread(L); if (!NL) return NULL; } else { NL = luaL_newstate(); if (!NL) return NULL; L = NL; thread_openlibs(L, loadlibs); thread_createmeta(L); lua_pushthread(L); } vmtd = lua_newuserdata(L, sizeof(struct sys_vmthread)); memset(vmtd, 0, sizeof(struct sys_vmthread)); vmtd->td.L = NL; vmtd->td.vmtd = vmtd; luaL_getmetatable(L, THREAD_TYPENAME); lua_setmetatable(L, -2); if (reftd) { struct sys_vmthread *vmref = reftd->vmtd; vmtd->td.reftd = reftd; vmtd->cpu = vmref->cpu; vmtd->stack_size = vmref->stack_size; } if (thread_critsect_new(&vmtd->vmcs)) return NULL; vmtd->td.vmcsp = &vmtd->vmcs; if (thread_cond_new(&vmtd->td.cond)) return NULL; thread_settable(L, &vmtd->td); /* save thread to avoid GC */ return &vmtd->td; }
/* * Arguments: filename (string) | function_dump (string), * [arguments (string | number | boolean | lightuserdata) ...] * Returns: [thread_ludata] */ static int thread_runvm (lua_State *L) { const char *path = luaL_checkstring(L, 1); lua_State *NL = NULL; struct sys_vmthread *vmtd = (struct sys_vmthread *) sys_get_thread(); #ifndef _WIN32 pthread_attr_t attr; #else HANDLE hThr; #endif int res = 0; if (!vmtd) luaL_argerror(L, 0, "Threading not initialized"); NL = luaL_newstate(); if (!NL) goto err; thread_openlibs(NL); if (path[0] == LUA_SIGNATURE[0] ? luaL_loadbuffer(NL, path, lua_rawlen(L, 1), "thread") : luaL_loadfile(NL, path)) { lua_pushstring(L, lua_tostring(NL, -1)); /* error message */ lua_close(NL); lua_error(L); } /* Arguments */ lua_pushlightuserdata(NL, vmtd); /* master */ { int i, top = lua_gettop(L); for (i = 2; i <= top; ++i) { switch (lua_type(L, i)) { case LUA_TSTRING: lua_pushstring(NL, lua_tostring(L, i)); break; case LUA_TNUMBER: lua_pushnumber(NL, lua_tonumber(L, i)); break; case LUA_TBOOLEAN: lua_pushboolean(NL, lua_toboolean(L, i)); break; case LUA_TLIGHTUSERDATA: case LUA_TUSERDATA: lua_pushlightuserdata(NL, lua_touserdata(L, i)); break; default: luaL_argerror(L, i, "primitive type expected"); } } } if (vmthread_new(NL, &vmtd)) goto err_clean; #ifndef _WIN32 res = pthread_attr_init(&attr); if (res) goto err_clean; pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); res = pthread_create(&vmtd->td.tid, &attr, (thread_func_t) thread_startvm, vmtd); pthread_attr_destroy(&attr); if (!res) { #else hThr = (HANDLE) _beginthreadex(NULL, 0, (thread_func_t) thread_startvm, vmtd, 0, &vmtd->td.tid); if (hThr) { CloseHandle(hThr); #endif lua_pushlightuserdata(L, vmtd); return 1; } err_clean: lua_close(NL); err: return sys_seterror(L, res); } /* * Arguments: thread_ludata */ static int thread_interrupt (lua_State *L) { struct sys_thread *td = lua_touserdata(L, 1); td->interrupted = 1; #ifndef _WIN32 pthread_kill(td->tid, SYS_SIGINTR); #endif return 0; } static int thread_yield (lua_State *L) { (void) L; sys_vm_leave(); #ifndef _WIN32 sched_yield(); #else Sleep(0); #endif sys_vm_enter(); return 0; }