/* * Returns: [thread_ludata] */ static int thread_init (lua_State *L) { struct sys_thread *td; /* TLS Index */ if (g_TLSIndex == INVALID_TLS_INDEX) { #ifndef _WIN32 const int res = pthread_key_create(&g_TLSIndex, NULL); if (res) { errno = res; goto err; } #else if ((g_TLSIndex = TlsAlloc()) == INVALID_TLS_INDEX) goto err; #endif } /* VM Mutex */ td = sys_get_thread(); if (!td) { if (vmthread_new(L, (void *) &td)) goto err; thread_settable(L, L, td->tid); sys_set_thread(td); sys_vm2_enter(td); } lua_pushlightuserdata(L, td->vmtd); return 1; err: return sys_seterror(L, 0); }
struct sys_thread * sys_del_thread (struct sys_thread *td) { lua_State *L = td->L; const thread_id_t tid = td->tid; td = (struct sys_thread *) td->vmtd; /* remove reference to self */ lua_pushnil(L); lua_pushnil(L); thread_settable(L, L, tid); return td; }
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; }
struct sys_thread * sys_new_thread (struct sys_thread *td) { lua_State *L = td->L; lua_State *NL; struct sys_thread *ntd; NL = lua_newthread(L); if (!NL) return NULL; ntd = lua_newuserdata(L, sizeof(struct sys_thread)); memset(ntd, 0, sizeof(struct sys_thread)); ntd->mutex = td->mutex; ntd->L = NL; ntd->vmtd = td->vmtd; ntd->tid = thread_getid(); thread_settable(L, NL, ntd->tid); /* save thread to avoid GC */ return ntd; }
/* * Returns: [thread_udata] */ struct sys_thread * sys_thread_new (lua_State *L, struct sys_thread *vmtd, struct sys_thread *vmtd2, const int push_udata) { struct sys_vmthread *vmref = vmtd->vmtd; struct sys_thread *td; lua_State *NL; if (vmtd2) { NL = vmref->td.L; lua_pushnil(L); } else { NL = lua_newthread(L); if (!NL) return NULL; } td = lua_newuserdata(L, sizeof(struct sys_thread)); memset(td, 0, sizeof(struct sys_thread)); td->vmcsp = vmtd->vmcsp; td->L = NL; td->vmtd = vmref; luaL_getmetatable(L, THREAD_TYPENAME); lua_setmetatable(L, -2); td->reftd = vmtd2 ? vmtd2 : &vmref->td; vmref->nref++; if (thread_cond_new(&td->cond)) return NULL; if (push_udata) { lua_pushvalue(L, -1); lua_insert(L, -3); /* thread_udata */ } thread_settable(L, td); /* save thread to avoid GC */ return td; }
/* * Arguments: function, [arguments (any) ...] * Returns: [thread_ludata] */ static int thread_run (lua_State *L) { struct sys_thread *vmtd = sys_get_thread(); lua_State *NL; struct sys_thread *td; #ifndef _WIN32 pthread_attr_t attr; int res = 0; #else HANDLE hThr; const int res = 0; #endif if (!vmtd) luaL_argerror(L, 0, "Threading not initialized"); luaL_checktype(L, 1, LUA_TFUNCTION); NL = lua_newthread(L); if (!NL) goto err; td = lua_newuserdata(L, sizeof(struct sys_thread)); memset(td, 0, sizeof(struct sys_thread)); td->mutex = vmtd->mutex; td->L = NL; td->vmtd = vmtd->vmtd; #ifndef _WIN32 if ((res = pthread_attr_init(&attr)) || (res = pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE))) goto err; pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); res = pthread_create(&td->tid, &attr, (thread_func_t) thread_start, td); pthread_attr_destroy(&attr); if (!res) { #else hThr = (HANDLE) _beginthreadex(NULL, THREAD_STACK_SIZE, (thread_func_t) thread_start, td, 0, &td->tid); if (hThr) { CloseHandle(hThr); #endif thread_settable(L, NL, td->tid); /* save thread to avoid GC */ lua_xmove(L, NL, lua_gettop(L)); /* move function and args to NL */ lua_pushlightuserdata(L, td); return 1; } err: return sys_seterror(L, res); } /* * Arguments: function, master (thread_ludata), * [arguments (string | number | boolean | lightuserdata) ...], * thread, thread_udata */ static THREAD_FUNC_API thread_startvm (struct sys_thread *td) { lua_State *L = td->L; thread_settable(L, L, td->tid); sys_set_thread(td); sys_vm2_enter(td); if (lua_pcall(L, lua_gettop(L) - 1, 0, 0)) { if (td->interrupted && lua_touserdata(L, -1) == &g_TLSIndex) lua_pop(L, 1); else lua_error(L); } /* notify event_queue */ if (td->trigger) sys_trigger_notify(&td->trigger, SYS_EVEOF | SYS_EVDEL); lua_close(L); return 0; }