/* * Arguments: function, [arguments (any) ...] * Returns: [thread_udata] */ static int thread_run (lua_State *L) { struct sys_thread *td, *vmtd = sys_thread_get(); if (!vmtd) luaL_argerror(L, 0, "Threading not initialized"); luaL_checktype(L, 1, LUA_TFUNCTION); td = sys_thread_new(L, vmtd, NULL, 1); if (!td) goto err; lua_insert(L, 1); /* thread_udata */ /* function and arguments */ { const int n = lua_gettop(L) - 1; luaL_checkstack(td->L, n, NULL); lua_xmove(L, td->L, n); } if (!sys_thread_create(td, 0)) { return 1; } sys_thread_del(td); err: return sys_seterror(L, 0); }
sys_threadpool * sys_threadpool_create(uint32_t num_workers) { sys_threadpool *pool = (sys_threadpool *)calloc(1, sizeof(*pool)); sys_worker *worker = NULL; size_t i; if (!pool) return NULL; pool->task_mutex = sys_mutex_create(); pool->task_notify = sys_cond_var_create(); pool->num_workers = num_workers; pool->shutdown = false; if (pool->num_workers <= 0) { if ((pool->num_workers = sys_cpu_count()) <= 0) { log_entry(THREADPOOL_MODULE, LOG_WARNING, "Failed to determine processor count. Limiting server to one thread. To avoid this, specify the number of threads"); pool->num_workers = 1; } } if (rt_array_init(&pool->workers, pool->num_workers, sizeof(sys_worker)) != SYS_OK) goto free_task; if (rt_array_init(&pool->active_tasks, pool->num_workers, sizeof(sys_task *)) != SYS_OK) goto free_workers; if (rt_queue_init(&pool->task_queue, (size_t)pool->num_workers * 2, sizeof(sys_task)) != SYS_OK) goto free_active_tasks; pool->worker_key = sys_tls_alloc_key(); rt_array_fill(&pool->workers); for (i = 0; i < pool->num_workers; ++i) { worker = rt_array_get(&pool->workers, i); worker->id = i; worker->idle = true; worker->pool = pool; worker->thread = sys_thread_create(_threadpool_worker_proc); sys_thread_start(worker->thread, worker); sys_thread_detach(worker->thread); } return pool; free_active_tasks: rt_array_release(&pool->active_tasks); free_workers: rt_array_release(&pool->workers); free_task: sys_mutex_destroy(pool->task_mutex); sys_cond_var_destroy(pool->task_notify); free(pool); return NULL; }
/* * Arguments: options (table: {1..n: library names, "cpu": number}), * filename (string) | function_dump (string), * [arguments (string | number | boolean | ludata | share_object) ...] * Returns: [thread_udata] */ static int thread_runvm (lua_State *L) { const char *path = luaL_checkstring(L, 2); struct sys_thread *vmtd = sys_thread_get(); struct sys_thread *td, *faketd; lua_State *NL; unsigned int loadlibs = ~0U; /* load all standard libraries */ int is_affin = 0, cpu = 0; if (!vmtd) luaL_argerror(L, 0, "Threading not initialized"); /* options */ if (lua_istable(L, 1)) { unsigned int libs = 0; int i; for (i = 1; ; ++i) { const char *s; lua_rawgeti(L, 1, i); s = lua_tostring(L, -1); if (!s || !*s) { if (s) loadlibs = 0; /* don't load any libraries */ lua_pop(L, 1); break; } libs |= 1 << luaL_checkoption(L, -1, NULL, stdlib_names); lua_pop(L, 1); } if (libs) loadlibs = libs; /* CPU affinity */ lua_getfield(L, 1, "cpu"); if (lua_type(L, -1) == LUA_TNUMBER) { cpu = (int) lua_tointeger(L, -1); is_affin = 1; } lua_pop(L, 1); } td = thread_newvm(NULL, vmtd, loadlibs); if (!td) goto err; faketd = sys_thread_new(L, vmtd, td, 1); if (!faketd) goto err; lua_replace(L, 1); /* fake thread_udata */ if (is_affin) td->vmtd->cpu = cpu; NL = td->L; /* function */ if (path[0] == LUA_SIGNATURE[0] ? luaL_loadbuffer(NL, path, lua_rawlen(L, ARG_LAST), "thread") : luaL_loadfile(NL, path)) { lua_pushstring(L, lua_tostring(NL, -1)); /* error message */ lua_close(NL); lua_error(L); } /* arguments */ { int i, top = lua_gettop(L); luaL_checkstack(NL, top + LUA_MINSTACK, "too many arguments"); for (i = ARG_LAST + 1; i <= top; ++i) { switch (lua_type(L, i)) { case LUA_TSTRING: { size_t len; const char *s = lua_tolstring(L, i, &len); lua_pushlstring(NL, s, len); } 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: lua_pushlightuserdata(NL, lua_touserdata(L, i)); break; case LUA_TUSERDATA: if (!luaL_getmetafield(L, i, THREAD_XDUP_TAG)) luaL_argerror(L, i, "shareable object expected"); lua_pushvalue(L, i); lua_pushlightuserdata(L, NL); lua_call(L, 2, 0); break; case LUA_TNIL: lua_pushnil(NL); break; default: luaL_argerror(L, i, "primitive type expected"); } } } if (!sys_thread_create(td, is_affin)) { faketd->tid = td->tid; lua_settop(L, 1); return 1; } lua_close(NL); err: return sys_seterror(L, 0); }