diff options
| author | ruki <[email protected]> | 2025-09-02 10:16:24 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-09-02 10:16:24 +0800 |
| commit | 148501afafa5e9e05da7a54bc804880d6c415849 (patch) | |
| tree | f5cbcee2b05d4b836478a45698c8a42b43ea38b7 | |
| parent | 90b7015682c5523dfa252ebfbab6ed16b3e4b16a (diff) | |
| parent | 37a499eeb5fd84be4ac83d639211e18e55dccd32 (diff) | |
Merge pull request #6324 from xmake-io/thread
Add native thread support
72 files changed, 4220 insertions, 147 deletions
diff --git a/core/src/tbox/tbox b/core/src/tbox/tbox -Subproject 7af204577394bb0364eef245f33e7cea6eed059 +Subproject 91a110d061d6486a7a0826919e0c60caf7586a3 diff --git a/core/src/xmake/engine.c b/core/src/xmake/engine.c index 69853c1f9..ee07da6ea 100644 --- a/core/src/xmake/engine.c +++ b/core/src/xmake/engine.c @@ -29,6 +29,7 @@ * includes */ #include "xmake.h" +#include "io/poller.h" #if defined(TB_CONFIG_OS_WINDOWS) # include <windows.h> # include <io.h> @@ -64,6 +65,11 @@ # include "lz4/prefix.h" #endif +// for lua +#ifndef USE_LUAJIT +# include "../../lua/lua/lstate.h" +#endif + /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ @@ -95,6 +101,10 @@ typedef struct __xm_engine_t // the engine name tb_char_t name[64]; + // the io poller + tb_poller_ref_t poller; + xm_poller_state_t poller_state; + #ifdef XM_EMBED_ENABLE // the temporary directory tb_char_t tmpdir[TB_PATH_MAXN]; @@ -329,6 +339,52 @@ tb_int_t xm_utils_bin2c(lua_State* lua); tb_int_t xm_lua_curses_register(lua_State* lua, tb_char_t const* module); #endif +// the thread functions +tb_int_t xm_thread_init(lua_State* lua); +tb_int_t xm_thread_exit(lua_State* lua); +tb_int_t xm_thread_wait(lua_State* lua); +tb_int_t xm_thread_suspend(lua_State* lua); +tb_int_t xm_thread_resume(lua_State* lua); + +// the thread/mutex functions +tb_int_t xm_thread_mutex_init(lua_State* lua); +tb_int_t xm_thread_mutex_exit(lua_State* lua); +tb_int_t xm_thread_mutex_lock(lua_State* lua); +tb_int_t xm_thread_mutex_trylock(lua_State* lua); +tb_int_t xm_thread_mutex_unlock(lua_State* lua); +tb_int_t xm_thread_mutex_incref(lua_State* lua); + +// the thread/event functions +tb_int_t xm_thread_event_init(lua_State* lua); +tb_int_t xm_thread_event_exit(lua_State* lua); +tb_int_t xm_thread_event_post(lua_State* lua); +tb_int_t xm_thread_event_wait(lua_State* lua); +tb_int_t xm_thread_event_incref(lua_State* lua); + +// the thread/semaphore functions +tb_int_t xm_thread_semaphore_init(lua_State* lua); +tb_int_t xm_thread_semaphore_exit(lua_State* lua); +tb_int_t xm_thread_semaphore_post(lua_State* lua); +tb_int_t xm_thread_semaphore_wait(lua_State* lua); +tb_int_t xm_thread_semaphore_incref(lua_State* lua); + +// the thread/queue functions +tb_int_t xm_thread_queue_init(lua_State* lua); +tb_int_t xm_thread_queue_exit(lua_State* lua); +tb_int_t xm_thread_queue_size(lua_State* lua); +tb_int_t xm_thread_queue_clear(lua_State* lua); +tb_int_t xm_thread_queue_incref(lua_State* lua); +tb_int_t xm_thread_queue_push(lua_State* lua); +tb_int_t xm_thread_queue_pop(lua_State* lua); + +// the thread/sharedata functions +tb_int_t xm_thread_sharedata_init(lua_State* lua); +tb_int_t xm_thread_sharedata_exit(lua_State* lua); +tb_int_t xm_thread_sharedata_clear(lua_State* lua); +tb_int_t xm_thread_sharedata_incref(lua_State* lua); +tb_int_t xm_thread_sharedata_set(lua_State* lua); +tb_int_t xm_thread_sharedata_get_(lua_State* lua); + // open cjson __tb_extern_c_enter__ tb_int_t luaopen_cjson(lua_State *l); @@ -615,6 +671,46 @@ static luaL_Reg const g_utils_functions[] = , { tb_null, tb_null } }; +// the thread functions +static luaL_Reg const g_thread_functions[] = +{ + { "thread_init", xm_thread_init } +, { "thread_exit", xm_thread_exit } +, { "thread_wait", xm_thread_wait } +, { "thread_resume", xm_thread_resume } +, { "thread_suspend", xm_thread_suspend } +, { "mutex_init", xm_thread_mutex_init } +, { "mutex_exit", xm_thread_mutex_exit } +, { "mutex_lock", xm_thread_mutex_lock } +, { "mutex_trylock", xm_thread_mutex_trylock } +, { "mutex_unlock", xm_thread_mutex_unlock } +, { "mutex_incref", xm_thread_mutex_incref } +, { "event_init", xm_thread_event_init } +, { "event_exit", xm_thread_event_exit } +, { "event_post", xm_thread_event_post } +, { "event_wait", xm_thread_event_wait } +, { "event_incref", xm_thread_event_incref } +, { "semaphore_init", xm_thread_semaphore_init } +, { "semaphore_exit", xm_thread_semaphore_exit } +, { "semaphore_post", xm_thread_semaphore_post } +, { "semaphore_wait", xm_thread_semaphore_wait } +, { "semaphore_incref", xm_thread_semaphore_incref } +, { "queue_init", xm_thread_queue_init } +, { "queue_exit", xm_thread_queue_exit } +, { "queue_size", xm_thread_queue_size } +, { "queue_clear", xm_thread_queue_clear } +, { "queue_incref", xm_thread_queue_incref } +, { "queue_push", xm_thread_queue_push } +, { "queue_pop", xm_thread_queue_pop } +, { "sharedata_init", xm_thread_sharedata_init } +, { "sharedata_exit", xm_thread_sharedata_exit } +, { "sharedata_clear", xm_thread_sharedata_clear } +, { "sharedata_incref", xm_thread_sharedata_incref } +, { "sharedata_set", xm_thread_sharedata_set } +, { "sharedata_get", xm_thread_sharedata_get_ } +, { tb_null, tb_null } +}; + // the lua global instance for signal handler static lua_State* g_lua = tb_null; @@ -1189,6 +1285,7 @@ static tb_void_t xm_engine_init_signal(xm_engine_t* engine) } #if XM_HOOK_LUA_MEMALLOC +// udata is unused, it has been used by engine. see xm_engine_bind_to_lua() static tb_pointer_t xm_engine_lua_realloc(tb_pointer_t udata, tb_pointer_t data, size_t osize, size_t nsize) { tb_pointer_t ptr = tb_null; @@ -1319,6 +1416,17 @@ static tb_bool_t xm_engine_extract_programfiles(xm_engine_t* engine, tb_char_t c } #endif +static tb_void_t xm_engine_bind_to_lua(lua_State* lua, xm_engine_t* engine) +{ +#ifdef USE_LUAJIT + lua_pushlightuserdata(lua, engine); + lua_setglobal(lua, "__global_engine"); +#else + global_State* g = G(lua); + g->ud = engine; +#endif +} + /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ @@ -1340,8 +1448,8 @@ xm_engine_ref_t xm_engine_init(tb_char_t const* name, xm_engine_lni_initalizer_c tb_assert_and_check_break(engine->lua); #if XM_HOOK_LUA_MEMALLOC - // hook lua memmory - lua_setallocf(engine->lua, xm_engine_lua_realloc, engine->lua); + // hook lua memmory, @note we cannot set udata argument, xm_engine_bind_to_lua() has used it. + lua_setallocf(engine->lua, xm_engine_lua_realloc, tb_null); #endif // open lua libraries @@ -1405,6 +1513,9 @@ xm_engine_ref_t xm_engine_init(tb_char_t const* name, xm_engine_lni_initalizer_c // bind utils functions xm_lua_register(engine->lua, "utils", g_utils_functions); + // bind thread functions + xm_lua_register(engine->lua, "thread", g_thread_functions); + #ifdef XM_CONFIG_API_HAVE_CURSES // bind curses xm_lua_curses_register(engine->lua, "curses"); @@ -1416,6 +1527,9 @@ xm_engine_ref_t xm_engine_init(tb_char_t const* name, xm_engine_lni_initalizer_c lua_setglobal(engine->lua, "cjson"); #endif + // bind engine to lua + xm_engine_bind_to_lua(engine->lua, engine); + // init host xm_engine_init_host(engine); @@ -1510,6 +1624,10 @@ tb_void_t xm_engine_exit(xm_engine_ref_t self) if (engine->lua) lua_close(engine->lua); engine->lua = tb_null; + // exit poller + if (engine->poller) tb_poller_exit(engine->poller); + engine->poller = tb_null; + // exit it tb_free(engine); } @@ -1600,6 +1718,33 @@ tb_void_t xm_engine_add_embedfiles(xm_engine_ref_t self, tb_byte_t const* data, engine->embedcount++; } #endif +lua_State* xm_engine_lua(xm_engine_ref_t self) +{ + // check + xm_engine_t* engine = (xm_engine_t*)self; + tb_assert_and_check_return_val(engine, tb_null); + + return engine->lua; +} +tb_poller_ref_t xm_engine_poller(xm_engine_ref_t self) +{ + // check + xm_engine_t* engine = (xm_engine_t*)self; + tb_assert_and_check_return_val(engine, tb_null); + + if (!engine->poller) + { + // init poller + engine->poller_state.lua = engine->lua; + tb_poller_ref_t poller = tb_poller_init(&engine->poller_state); + tb_assert_and_check_return_val(poller, tb_null); + + // attach poller to the current thread + tb_poller_attach(poller); + engine->poller = poller; + } + return engine->poller; +} tb_int_t xm_engine_run(tb_char_t const* name, tb_int_t argc, tb_char_t** argv, tb_char_t** taskargv, xm_engine_lni_initalizer_cb_t lni_initalizer) { tb_int_t ok = -1; @@ -1615,4 +1760,16 @@ tb_int_t xm_engine_run(tb_char_t const* name, tb_int_t argc, tb_char_t** argv, t } return ok; } +xm_engine_ref_t xm_engine_get(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, tb_null); + +#ifdef USE_LUAJIT + lua_getglobal(lua, "__global_engine"); + return (xm_engine_ref_t)lua_touserdata(lua, -1); +#else + global_State* g = G(lua); + return (xm_engine_ref_t)g->ud; +#endif +} diff --git a/core/src/xmake/engine.h b/core/src/xmake/engine.h index 89344cef1..04ef958d9 100644 --- a/core/src/xmake/engine.h +++ b/core/src/xmake/engine.h @@ -81,12 +81,28 @@ tb_void_t xm_engine_register(xm_engine_ref_t engine, tb_char_t /*! add the embed files * - * @param name the engine name + * @param engine the engine * @param data the embedfiles data * @param size the data size */ tb_void_t xm_engine_add_embedfiles(xm_engine_ref_t engine, tb_byte_t const* data, tb_size_t size); +/* get lua state from engine + * + * @param engine the engine + * + * @return the lua state + */ +lua_State* xm_engine_lua(xm_engine_ref_t engine); + +/* get poller from engine + * + * @param engine the engine + * + * @return the poller + */ +tb_poller_ref_t xm_engine_poller(xm_engine_ref_t engine); + /*! run main entry of the engine singleton * * @param name the engine name @@ -99,6 +115,14 @@ tb_void_t xm_engine_add_embedfiles(xm_engine_ref_t engine, tb_ */ tb_int_t xm_engine_run(tb_char_t const* name, tb_int_t argc, tb_char_t** argv, tb_char_t** taskargv, xm_engine_lni_initalizer_cb_t lni_initalizer); +/*! get engine from the given lua state + * + * @param lua the lua state + * + * @return the engine + */ +xm_engine_ref_t xm_engine_get(lua_State* lua); + /* ////////////////////////////////////////////////////////////////////////////////////// * extern */ diff --git a/core/src/xmake/engine_pool.c b/core/src/xmake/engine_pool.c new file mode 100644 index 000000000..78081399c --- /dev/null +++ b/core/src/xmake/engine_pool.c @@ -0,0 +1,107 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file engine_pool.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "engine_pool" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "xmake.h" +#include "engine.h" +#include "engine_pool.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * macros + */ + +// the max engine pool count +#define XM_ENGINE_POOL_MAXN (128) + +// the singleton type of engine pool +#define XM_ENGINE_POOL (TB_SINGLETON_TYPE_USER + 4) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * private implementation + */ +static tb_handle_t xm_engine_pool_instance_init(tb_cpointer_t* ppriv) +{ + xm_engine_pool_ref_t engine_pool = xm_engine_pool_init(); + tb_assert_and_check_return_val(engine_pool, tb_null); + + return (tb_handle_t)engine_pool; +} + +static tb_void_t xm_engine_pool_instance_exit(tb_handle_t engine_pool, tb_cpointer_t priv) +{ + if (engine_pool) xm_engine_pool_exit((xm_engine_pool_ref_t)engine_pool); +} + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +xm_engine_pool_ref_t xm_engine_pool() +{ + return (xm_engine_pool_ref_t)tb_singleton_instance(XM_ENGINE_POOL, xm_engine_pool_instance_init, xm_engine_pool_instance_exit, tb_null, tb_null); +} + +xm_engine_pool_ref_t xm_engine_pool_init() +{ + return tb_single_list_init(0, tb_element_ptr(tb_null, tb_null)); +} + +tb_void_t xm_engine_pool_exit(xm_engine_pool_ref_t engine_pool) +{ + if (engine_pool) + { + tb_for_all (xm_engine_ref_t, engine, engine_pool) + { + if (engine) + xm_engine_exit(engine); + } + tb_single_list_exit(engine_pool); + } +} + +xm_engine_ref_t xm_engine_pool_alloc(xm_engine_pool_ref_t engine_pool) +{ + xm_engine_ref_t engine = tb_null; + if (tb_single_list_size(engine_pool) > 0) + { + engine = (xm_engine_ref_t)tb_single_list_head(engine_pool); + tb_single_list_remove_head(engine_pool); + } + return engine; +} + +tb_bool_t xm_engine_pool_free(xm_engine_pool_ref_t engine_pool, xm_engine_ref_t engine) +{ + if (tb_single_list_size(engine_pool) < XM_ENGINE_POOL_MAXN) + { + tb_single_list_insert_tail(engine_pool, engine); + return tb_true; + } + return tb_false; +} + diff --git a/core/src/xmake/engine_pool.h b/core/src/xmake/engine_pool.h new file mode 100644 index 000000000..853856d1c --- /dev/null +++ b/core/src/xmake/engine_pool.h @@ -0,0 +1,82 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file engine_pool.h + * + */ +#ifndef XM_ENGINE_POOL_H +#define XM_ENGINE_POOL_H + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * extern + */ +__tb_extern_c_enter__ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * types + */ + +/// the xmake engine pool type +typedef tb_single_list_ref_t xm_engine_pool_ref_t; + +/* ////////////////////////////////////////////////////////////////////////////////////// + * interfaces + */ + +// get the engine pool singleton +xm_engine_pool_ref_t xm_engine_pool(tb_void_t); + +/*! init the engine_pool + * + * @return the engine pool + */ +xm_engine_pool_ref_t xm_engine_pool_init(tb_void_t); + +/*! exit the engine_pool + * + * @param engine_pool the engine_pool + */ +tb_void_t xm_engine_pool_exit(xm_engine_pool_ref_t engine_pool); + +/*! alloc a engine from the engine_pool + * + * @param engine_pool the engine_pool + * + * @return the engine + */ +xm_engine_ref_t xm_engine_pool_alloc(xm_engine_pool_ref_t engine_pool); + +/*! free a engine to the engine_pool + * + * @param engine_pool the engine_pool + * @param engine the engine + * + * @return tb_true or tb_false + */ +tb_bool_t xm_engine_pool_free(xm_engine_pool_ref_t engine_pool, xm_engine_ref_t engine); + +/* ////////////////////////////////////////////////////////////////////////////////////// + * extern + */ +__tb_extern_c_leave__ + +#endif diff --git a/core/src/xmake/io/pipe_close.c b/core/src/xmake/io/pipe_close.c index 6f50cbf67..062e7009d 100644 --- a/core/src/xmake/io/pipe_close.c +++ b/core/src/xmake/io/pipe_close.c @@ -41,11 +41,11 @@ tb_int_t xm_io_pipe_close(lua_State* lua) tb_assert_and_check_return_val(lua, 0); // check pipe? - if (!xm_lua_ispointer(lua, 1)) + if (!xm_pipe_file_is_valid(lua, 1)) return 0; // get the pipe file - tb_pipe_file_ref_t pipefile = (tb_pipe_file_ref_t)xm_lua_topointer(lua, 1); + tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1); tb_check_return_val(pipefile, 0); // exit pipe file diff --git a/core/src/xmake/io/pipe_read.c b/core/src/xmake/io/pipe_read.c index d75547714..cb3457fec 100644 --- a/core/src/xmake/io/pipe_read.c +++ b/core/src/xmake/io/pipe_read.c @@ -41,7 +41,7 @@ tb_int_t xm_io_pipe_read(lua_State* lua) tb_assert_and_check_return_val(lua, 0); // check pipe file - if (!xm_lua_ispointer(lua, 1)) + if (!xm_pipe_file_is_valid(lua, 1)) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid pipe file!"); @@ -49,7 +49,7 @@ tb_int_t xm_io_pipe_read(lua_State* lua) } // get pipe file - tb_pipe_file_ref_t pipefile = (tb_pipe_file_ref_t)xm_lua_topointer(lua, 1); + tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1); tb_check_return_val(pipefile, 0); // get data diff --git a/core/src/xmake/io/pipe_wait.c b/core/src/xmake/io/pipe_wait.c index 7de310425..f39220d41 100644 --- a/core/src/xmake/io/pipe_wait.c +++ b/core/src/xmake/io/pipe_wait.c @@ -41,11 +41,11 @@ tb_int_t xm_io_pipe_wait(lua_State* lua) tb_assert_and_check_return_val(lua, 0); // check pipe? - if (!xm_lua_ispointer(lua, 1)) + if (!xm_pipe_file_is_valid(lua, 1)) return 0; // get pipe file - tb_pipe_file_ref_t pipefile = (tb_pipe_file_ref_t)xm_lua_topointer(lua, 1); + tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1); tb_check_return_val(pipefile, 0); // get events diff --git a/core/src/xmake/io/pipe_write.c b/core/src/xmake/io/pipe_write.c index 2ea0c69fe..140894428 100644 --- a/core/src/xmake/io/pipe_write.c +++ b/core/src/xmake/io/pipe_write.c @@ -41,7 +41,7 @@ tb_int_t xm_io_pipe_write(lua_State* lua) tb_assert_and_check_return_val(lua, 0); // check pipe - if (!xm_lua_ispointer(lua, 1)) + if (!xm_pipe_file_is_valid(lua, 1)) { lua_pushinteger(lua, -1); lua_pushliteral(lua, "invalid pipe file!"); @@ -49,7 +49,7 @@ tb_int_t xm_io_pipe_write(lua_State* lua) } // get pipe file - tb_pipe_file_ref_t pipefile = (tb_pipe_file_ref_t)xm_lua_topointer(lua, 1); + tb_pipe_file_ref_t pipefile = xm_pipe_file_get(lua, 1); tb_check_return_val(pipefile, 0); // get data and size diff --git a/core/src/xmake/io/poller.c b/core/src/xmake/io/poller.c index 77c35e639..7700c6858 100644 --- a/core/src/xmake/io/poller.c +++ b/core/src/xmake/io/poller.c @@ -29,37 +29,17 @@ * includes */ #include "poller.h" - -/* ////////////////////////////////////////////////////////////////////////////////////// - * macros - */ - -// the singleton type of poller -#define XM_IO_POLLER (TB_SINGLETON_TYPE_USER + 4) - -/* ////////////////////////////////////////////////////////////////////////////////////// - * private implementation - */ -static tb_handle_t xm_io_poller_instance_init(tb_cpointer_t* ppriv) -{ - // init poller - tb_poller_ref_t poller = tb_poller_init(tb_null); - tb_assert_and_check_return_val(poller, tb_null); - - // attach poller to the current thread - tb_poller_attach(poller); - return (tb_handle_t)poller; -} -static tb_void_t xm_io_poller_instance_exit(tb_handle_t poller, tb_cpointer_t priv) -{ - if (poller) tb_poller_exit((tb_poller_ref_t)poller); -} +#include "../engine.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ -tb_poller_ref_t xm_io_poller() +tb_poller_ref_t xm_io_poller(lua_State* lua) { - return (tb_poller_ref_t)tb_singleton_instance(XM_IO_POLLER, xm_io_poller_instance_init, xm_io_poller_instance_exit, tb_null, tb_null); + tb_poller_ref_t poller = tb_null; + xm_engine_ref_t engine = xm_engine_get(lua); + if (engine) poller = xm_engine_poller(engine); + tb_assert(poller); + return poller; } diff --git a/core/src/xmake/io/poller.h b/core/src/xmake/io/poller.h index 83252afd5..887fc25ba 100644 --- a/core/src/xmake/io/poller.h +++ b/core/src/xmake/io/poller.h @@ -27,6 +27,18 @@ #include "prefix.h" /* ////////////////////////////////////////////////////////////////////////////////////// + * types + */ + +// the poller state in wait events +typedef struct __xm_poller_state_t +{ + lua_State* lua; + tb_int_t events_count; + +}xm_poller_state_t; + +/* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ @@ -34,7 +46,7 @@ * * @return the io poller */ -tb_poller_ref_t xm_io_poller(tb_noarg_t); +tb_poller_ref_t xm_io_poller(lua_State* lua); #endif diff --git a/core/src/xmake/io/poller_insert.c b/core/src/xmake/io/poller_insert.c index b8890842a..e78c3c18f 100644 --- a/core/src/xmake/io/poller_insert.c +++ b/core/src/xmake/io/poller_insert.c @@ -64,7 +64,7 @@ tb_int_t xm_io_poller_insert(lua_State* lua) tb_poller_object_t object; object.type = otype; object.ref.ptr = cdata; - lua_pushboolean(lua, tb_poller_insert(xm_io_poller(), &object, events, cdata_str)); + lua_pushboolean(lua, tb_poller_insert(xm_io_poller(lua), &object, events, cdata_str)); return 1; } diff --git a/core/src/xmake/io/poller_modify.c b/core/src/xmake/io/poller_modify.c index e16f715d4..5ed858030 100644 --- a/core/src/xmake/io/poller_modify.c +++ b/core/src/xmake/io/poller_modify.c @@ -64,7 +64,7 @@ tb_int_t xm_io_poller_modify(lua_State* lua) tb_poller_object_t object; object.type = otype; object.ref.ptr = cdata; - lua_pushboolean(lua, tb_poller_modify(xm_io_poller(), &object, events, cdata_str)); + lua_pushboolean(lua, tb_poller_modify(xm_io_poller(lua), &object, events, cdata_str)); return 1; } diff --git a/core/src/xmake/io/poller_remove.c b/core/src/xmake/io/poller_remove.c index a0c67b9bc..3cad1aa0a 100644 --- a/core/src/xmake/io/poller_remove.c +++ b/core/src/xmake/io/poller_remove.c @@ -60,7 +60,7 @@ tb_int_t xm_io_poller_remove(lua_State* lua) tb_poller_object_t object; object.type = otype; object.ref.ptr = cdata; - lua_pushboolean(lua, tb_poller_remove(xm_io_poller(), &object)); + lua_pushboolean(lua, tb_poller_remove(xm_io_poller(lua), &object)); return 1; } diff --git a/core/src/xmake/io/poller_spank.c b/core/src/xmake/io/poller_spank.c index e7d0bfcaf..ac7207763 100644 --- a/core/src/xmake/io/poller_spank.c +++ b/core/src/xmake/io/poller_spank.c @@ -42,7 +42,7 @@ tb_int_t xm_io_poller_spank(lua_State* lua) tb_assert_and_check_return_val(lua, 0); // spank the poller, break the tb_poller_wait() and return all events - tb_poller_spak(xm_io_poller()); + tb_poller_spak(xm_io_poller(lua)); return 0; } diff --git a/core/src/xmake/io/poller_support.c b/core/src/xmake/io/poller_support.c index b26810a43..36ae52b34 100644 --- a/core/src/xmake/io/poller_support.c +++ b/core/src/xmake/io/poller_support.c @@ -45,7 +45,7 @@ tb_int_t xm_io_poller_support(lua_State* lua) tb_size_t events = (tb_size_t)luaL_checknumber(lua, 1); // support events for poller - lua_pushboolean(lua, tb_poller_support(xm_io_poller(), events)); + lua_pushboolean(lua, tb_poller_support(xm_io_poller(lua), events)); return 1; } diff --git a/core/src/xmake/io/poller_wait.c b/core/src/xmake/io/poller_wait.c index 01021d943..341893f74 100644 --- a/core/src/xmake/io/poller_wait.c +++ b/core/src/xmake/io/poller_wait.c @@ -32,46 +32,40 @@ #include "poller.h" /* ////////////////////////////////////////////////////////////////////////////////////// - * globals - */ - -// we need only one global lua state/poller in main thread, so it is thread-safe. -static lua_State* g_lua = tb_null; -static tb_int_t g_events_count = 0; - -/* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t xm_io_poller_event(tb_poller_ref_t poller, tb_poller_object_ref_t object, tb_long_t events, tb_cpointer_t priv) { // check - tb_assert_and_check_return(g_lua); + xm_poller_state_t* state = (xm_poller_state_t*)tb_poller_priv(poller); + tb_assert_and_check_return(state && state->lua); // save object and events - lua_newtable(g_lua); - lua_pushinteger(g_lua, (tb_int_t)object->type); - lua_rawseti(g_lua, -2, 1); - if (priv) lua_pushstring(g_lua, (tb_char_t const*)priv); - else lua_pushlightuserdata(g_lua, object->ref.ptr); - lua_rawseti(g_lua, -2, 2); + lua_State* lua = state->lua; + lua_newtable(lua); + lua_pushinteger(lua, (tb_int_t)object->type); + lua_rawseti(lua, -2, 1); + if (priv) lua_pushstring(lua, (tb_char_t const*)priv); + else lua_pushlightuserdata(lua, object->ref.ptr); + lua_rawseti(lua, -2, 2); if (object->type == TB_POLLER_OBJECT_FWATCHER) { - lua_newtable(g_lua); + lua_newtable(lua); tb_fwatcher_event_t* event = (tb_fwatcher_event_t*)events; if (event) { - lua_pushstring(g_lua, "path"); - lua_pushstring(g_lua, event->filepath); - lua_settable(g_lua, -3); + lua_pushstring(lua, "path"); + lua_pushstring(lua, event->filepath); + lua_settable(lua, -3); - lua_pushstring(g_lua, "type"); - lua_pushinteger(g_lua, event->event); - lua_settable(g_lua, -3); + lua_pushstring(lua, "type"); + lua_pushinteger(lua, event->event); + lua_settable(lua, -3); } } - else lua_pushinteger(g_lua, (tb_int_t)events); - lua_rawseti(g_lua, -2, 3); - lua_rawseti(g_lua, -2, ++g_events_count); + else lua_pushinteger(lua, (tb_int_t)events); + lua_rawseti(lua, -2, 3); + lua_rawseti(lua, -2, ++state->events_count); } /* ////////////////////////////////////////////////////////////////////////////////////// @@ -82,18 +76,19 @@ static tb_void_t xm_io_poller_event(tb_poller_ref_t poller, tb_poller_object_ref tb_int_t xm_io_poller_wait(lua_State* lua) { // check - tb_assert_and_check_return_val(lua, 0); + tb_poller_ref_t poller = xm_io_poller(lua); + tb_assert_and_check_return_val(poller && lua, 0); // get timeout tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 1); - // pass lua and count to the events callback - g_lua = lua; - g_events_count = 0; + // reset events count + xm_poller_state_t* state = (xm_poller_state_t*)tb_poller_priv(poller); + state->events_count = 0; // wait it lua_newtable(lua); - tb_long_t count = tb_poller_wait(xm_io_poller(), xm_io_poller_event, timeout); + tb_long_t count = tb_poller_wait(poller, xm_io_poller_event, timeout); if (count > 0) { lua_pushinteger(lua, (tb_int_t)count); diff --git a/core/src/xmake/io/prefix.h b/core/src/xmake/io/prefix.h index 7d8a8405b..ec2cc7216 100644 --- a/core/src/xmake/io/prefix.h +++ b/core/src/xmake/io/prefix.h @@ -94,6 +94,21 @@ typedef struct __xm_io_file_t } xm_io_file_t; +// check pipe file +static __tb_inline__ tb_bool_t xm_pipe_file_is_valid(lua_State* lua, tb_int_t index) +{ + return xm_lua_ispointer(lua, index) || xm_lua_isinteger(lua, index); +} + +// get the pipe file from arguments +static __tb_inline__ tb_pipe_file_ref_t xm_pipe_file_get(lua_State* lua, tb_int_t index) +{ + tb_pipe_file_ref_t pipe_file = tb_null; + if (xm_lua_isinteger(lua, index)) pipe_file = (tb_pipe_file_ref_t)(tb_size_t)(tb_long_t)lua_tointeger(lua, index); + else if (xm_lua_ispointer(lua, index)) pipe_file = (tb_pipe_file_ref_t)xm_lua_topointer(lua, index); + return pipe_file; +} + #endif diff --git a/core/src/xmake/io/socket_close.c b/core/src/xmake/io/socket_close.c index fca95c186..a424a707f 100644 --- a/core/src/xmake/io/socket_close.c +++ b/core/src/xmake/io/socket_close.c @@ -50,8 +50,6 @@ tb_int_t xm_io_socket_close(lua_State* lua) // exit socket lua_pushboolean(lua, tb_socket_exit(sock)); - - // ok return 1; } diff --git a/core/src/xmake/thread/event_exit.c b/core/src/xmake/thread/event_exit.c new file mode 100644 index 000000000..54e977068 --- /dev/null +++ b/core/src/xmake/thread/event_exit.c @@ -0,0 +1,55 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_event_exit.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_event" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_event_exit(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_event_t* thread_event = xm_thread_event_get(lua, 1); + tb_assert_and_check_return_val(thread_event && thread_event->handle, 0); + + if (tb_atomic_fetch_and_sub(&thread_event->refn, 1) == 1) + { + if (thread_event->handle) + { + tb_event_exit(thread_event->handle); + thread_event->handle = tb_null; + } + tb_free(thread_event); + } + lua_pushboolean(lua, tb_true); + return 1; +} + diff --git a/core/src/xmake/thread/event_incref.c b/core/src/xmake/thread/event_incref.c new file mode 100644 index 000000000..ff8b658d9 --- /dev/null +++ b/core/src/xmake/thread/event_incref.c @@ -0,0 +1,46 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_event_incref.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_event" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_event_incref(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_event_t* thread_event = xm_thread_event_get(lua, 1); + tb_assert_and_check_return_val(thread_event && thread_event->handle, 0); + + lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_event->refn, 1) >= 1); + return 1; +} + diff --git a/core/src/xmake/thread/event_init.c b/core/src/xmake/thread/event_init.c new file mode 100644 index 000000000..942537718 --- /dev/null +++ b/core/src/xmake/thread/event_init.c @@ -0,0 +1,70 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file event_init.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_event" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_event_init(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + tb_bool_t ok = tb_false; + xm_thread_event_t* thread_event = tb_null; + do + { + thread_event = tb_malloc0_type(xm_thread_event_t); + tb_assert_and_check_break(thread_event); + + thread_event->refn = 1; + thread_event->handle = tb_event_init(); + tb_assert_and_check_break(thread_event->handle); + + xm_lua_pushpointer(lua, (tb_pointer_t)thread_event); + ok = tb_true; + + } while (0); + + if (!ok) + { + if (thread_event) + { + if (thread_event->handle) + { + tb_event_exit(thread_event->handle); + thread_event->handle = tb_null; + } + tb_free(thread_event); + } + lua_pushnil(lua); + } + return 1; +} diff --git a/core/src/xmake/thread/event_post.c b/core/src/xmake/thread/event_post.c new file mode 100644 index 000000000..0b8e5dabd --- /dev/null +++ b/core/src/xmake/thread/event_post.c @@ -0,0 +1,46 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_event_lock.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_event" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_event_post(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_event_t* thread_event = xm_thread_event_get(lua, 1); + tb_assert_and_check_return_val(thread_event && thread_event->handle, 0); + + lua_pushboolean(lua, tb_event_post(thread_event->handle)); + return 1; +} + diff --git a/core/src/xmake/thread/event_wait.c b/core/src/xmake/thread/event_wait.c new file mode 100644 index 000000000..0831036c6 --- /dev/null +++ b/core/src/xmake/thread/event_wait.c @@ -0,0 +1,47 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_event_unlock.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_event" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_event_wait(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_event_t* thread_event = xm_thread_event_get(lua, 1); + tb_assert_and_check_return_val(thread_event && thread_event->handle, 0); + + tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 2); + lua_pushinteger(lua, tb_event_wait(thread_event->handle, timeout)); + return 1; +} + diff --git a/core/src/xmake/thread/mutex_exit.c b/core/src/xmake/thread/mutex_exit.c new file mode 100644 index 000000000..39d69ab8a --- /dev/null +++ b/core/src/xmake/thread/mutex_exit.c @@ -0,0 +1,55 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_mutex_exit.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_mutex" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_mutex_exit(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_mutex_t* thread_mutex = xm_thread_mutex_get(lua, 1); + tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0); + + if (tb_atomic_fetch_and_sub(&thread_mutex->refn, 1) == 1) + { + if (thread_mutex->handle) + { + tb_mutex_exit(thread_mutex->handle); + thread_mutex->handle = tb_null; + } + tb_free(thread_mutex); + } + lua_pushboolean(lua, tb_true); + return 1; +} + diff --git a/core/src/xmake/thread/mutex_incref.c b/core/src/xmake/thread/mutex_incref.c new file mode 100644 index 000000000..34a234757 --- /dev/null +++ b/core/src/xmake/thread/mutex_incref.c @@ -0,0 +1,46 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_mutex_incref.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_mutex" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_mutex_incref(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_mutex_t* thread_mutex = xm_thread_mutex_get(lua, 1); + tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0); + + lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_mutex->refn, 1) >= 1); + return 1; +} + diff --git a/core/src/xmake/thread/mutex_init.c b/core/src/xmake/thread/mutex_init.c new file mode 100644 index 000000000..ff69e82ad --- /dev/null +++ b/core/src/xmake/thread/mutex_init.c @@ -0,0 +1,70 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file mutex_init.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_mutex" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_mutex_init(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + tb_bool_t ok = tb_false; + xm_thread_mutex_t* thread_mutex = tb_null; + do + { + thread_mutex = tb_malloc0_type(xm_thread_mutex_t); + tb_assert_and_check_break(thread_mutex); + + thread_mutex->refn = 1; + thread_mutex->handle = tb_mutex_init(); + tb_assert_and_check_break(thread_mutex->handle); + + xm_lua_pushpointer(lua, (tb_pointer_t)thread_mutex); + ok = tb_true; + + } while (0); + + if (!ok) + { + if (thread_mutex) + { + if (thread_mutex->handle) + { + tb_mutex_exit(thread_mutex->handle); + thread_mutex->handle = tb_null; + } + tb_free(thread_mutex); + } + lua_pushnil(lua); + } + return 1; +} diff --git a/core/src/xmake/thread/mutex_lock.c b/core/src/xmake/thread/mutex_lock.c new file mode 100644 index 000000000..380301da1 --- /dev/null +++ b/core/src/xmake/thread/mutex_lock.c @@ -0,0 +1,46 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_mutex_lock.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_mutex" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_mutex_lock(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_mutex_t* thread_mutex = xm_thread_mutex_get(lua, 1); + tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0); + + lua_pushboolean(lua, tb_mutex_enter(thread_mutex->handle)); + return 1; +} + diff --git a/core/src/xmake/thread/mutex_trylock.c b/core/src/xmake/thread/mutex_trylock.c new file mode 100644 index 000000000..7b83f3a90 --- /dev/null +++ b/core/src/xmake/thread/mutex_trylock.c @@ -0,0 +1,46 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_mutex_trylock.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_mutex" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_mutex_trylock(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_mutex_t* thread_mutex = xm_thread_mutex_get(lua, 1); + tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0); + + lua_pushboolean(lua, tb_mutex_enter_try(thread_mutex->handle)); + return 1; +} + diff --git a/core/src/xmake/thread/mutex_unlock.c b/core/src/xmake/thread/mutex_unlock.c new file mode 100644 index 000000000..beb0c9e0a --- /dev/null +++ b/core/src/xmake/thread/mutex_unlock.c @@ -0,0 +1,46 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_mutex_unlock.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_mutex" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_mutex_unlock(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_mutex_t* thread_mutex = xm_thread_mutex_get(lua, 1); + tb_assert_and_check_return_val(thread_mutex && thread_mutex->handle, 0); + + lua_pushboolean(lua, tb_mutex_leave(thread_mutex->handle)); + return 1; +} + diff --git a/core/src/xmake/thread/prefix.h b/core/src/xmake/thread/prefix.h new file mode 100644 index 000000000..2b841e6a7 --- /dev/null +++ b/core/src/xmake/thread/prefix.h @@ -0,0 +1,156 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file prefix.h + * + */ +#ifndef XM_THREAD_PREFIX_H +#define XM_THREAD_PREFIX_H + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "../prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * types + */ + +// the thread type +typedef struct __xm_thread_t +{ + tb_thread_ref_t handle; + tb_string_t callback; + tb_string_t callinfo; + +}xm_thread_t; + +// the thread value kind +typedef enum __xm_thread_value_kind_e +{ + XM_THREAD_VALUE_NIL = 0, + XM_THREAD_VALUE_BOOL = 1, + XM_THREAD_VALUE_INT = 2, + XM_THREAD_VALUE_NUM = 3, + XM_THREAD_VALUE_STR = 4 + +}xm_thread_value_kind_e; + +// the thread value type +typedef struct __xm_thread_value_t +{ + tb_uint32_t kind : 3; + tb_uint32_t size : 29; + union + { + tb_char_t* string; + tb_bool_t boolean; + lua_Integer integer; + lua_Number number; + } u; + +}xm_thread_value_t; + +// the thread event type +typedef struct __xm_thread_event_t +{ + tb_event_ref_t handle; + tb_atomic_t refn; + +}xm_thread_event_t; + +// the thread mutex type +typedef struct __xm_thread_mutex_t +{ + tb_mutex_ref_t handle; + tb_atomic_t refn; + +}xm_thread_mutex_t; + +// the thread semaphore type +typedef struct __xm_thread_semaphore_t +{ + tb_semaphore_ref_t handle; + tb_atomic_t refn; + +}xm_thread_semaphore_t; + +// the thread queue type +typedef struct __xm_thread_queue_t +{ + tb_queue_ref_t handle; + tb_atomic_t refn; + +}xm_thread_queue_t; + +// the thread sharedata type +typedef struct __xm_thread_sharedata_t +{ + xm_thread_value_t value; + tb_buffer_t buffer; + tb_atomic_t refn; + +}xm_thread_sharedata_t; + +// get the thread event from arguments +static __tb_inline__ xm_thread_event_t* xm_thread_event_get(lua_State* lua, tb_int_t index) +{ + xm_thread_event_t* thread_event = tb_null; + if (xm_lua_isinteger(lua, index)) thread_event = (xm_thread_event_t*)(tb_size_t)(tb_long_t)lua_tointeger(lua, index); + else if (xm_lua_ispointer(lua, index)) thread_event = (xm_thread_event_t*)xm_lua_topointer(lua, index); + return thread_event; +} + +// get the thread mutex from arguments +static __tb_inline__ xm_thread_mutex_t* xm_thread_mutex_get(lua_State* lua, tb_int_t index) +{ + xm_thread_mutex_t* thread_mutex = tb_null; + if (xm_lua_isinteger(lua, index)) thread_mutex = (xm_thread_mutex_t*)(tb_size_t)(tb_long_t)lua_tointeger(lua, index); + else if (xm_lua_ispointer(lua, index)) thread_mutex = (xm_thread_mutex_t*)xm_lua_topointer(lua, index); + return thread_mutex; +} + +// get the thread semaphore from arguments +static __tb_inline__ xm_thread_semaphore_t* xm_thread_semaphore_get(lua_State* lua, tb_int_t index) +{ + xm_thread_semaphore_t* thread_semaphore = tb_null; + if (xm_lua_isinteger(lua, index)) thread_semaphore = (xm_thread_semaphore_t*)(tb_size_t)(tb_long_t)lua_tointeger(lua, index); + else if (xm_lua_ispointer(lua, index)) thread_semaphore = (xm_thread_semaphore_t*)xm_lua_topointer(lua, index); + return thread_semaphore; +} + +// get the thread queue from arguments +static __tb_inline__ xm_thread_queue_t* xm_thread_queue_get(lua_State* lua, tb_int_t index) +{ + xm_thread_queue_t* thread_queue = tb_null; + if (xm_lua_isinteger(lua, index)) thread_queue = (xm_thread_queue_t*)(tb_size_t)(tb_long_t)lua_tointeger(lua, index); + else if (xm_lua_ispointer(lua, index)) thread_queue = (xm_thread_queue_t*)xm_lua_topointer(lua, index); + return thread_queue; +} + +// get the thread sharedata from arguments +static __tb_inline__ xm_thread_sharedata_t* xm_thread_sharedata_get(lua_State* lua, tb_int_t index) +{ + xm_thread_sharedata_t* thread_sharedata = tb_null; + if (xm_lua_isinteger(lua, index)) thread_sharedata = (xm_thread_sharedata_t*)(tb_size_t)(tb_long_t)lua_tointeger(lua, index); + else if (xm_lua_ispointer(lua, index)) thread_sharedata = (xm_thread_sharedata_t*)xm_lua_topointer(lua, index); + return thread_sharedata; +} + +#endif + + diff --git a/core/src/xmake/thread/queue_clear.c b/core/src/xmake/thread/queue_clear.c new file mode 100644 index 000000000..4888babe2 --- /dev/null +++ b/core/src/xmake/thread/queue_clear.c @@ -0,0 +1,47 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_queue_clear.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_queue" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_queue_clear(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_queue_t* thread_queue = xm_thread_queue_get(lua, 1); + tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0); + + tb_queue_clear(thread_queue->handle); + lua_pushboolean(lua, tb_true); + return 1; +} + diff --git a/core/src/xmake/thread/queue_exit.c b/core/src/xmake/thread/queue_exit.c new file mode 100644 index 000000000..8178ea22f --- /dev/null +++ b/core/src/xmake/thread/queue_exit.c @@ -0,0 +1,55 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_queue_exit.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_queue" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_queue_exit(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_queue_t* thread_queue = xm_thread_queue_get(lua, 1); + tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0); + + if (tb_atomic_fetch_and_sub(&thread_queue->refn, 1) == 1) + { + if (thread_queue->handle) + { + tb_queue_exit(thread_queue->handle); + thread_queue->handle = tb_null; + } + tb_free(thread_queue); + } + lua_pushboolean(lua, tb_true); + return 1; +} + diff --git a/core/src/xmake/thread/queue_incref.c b/core/src/xmake/thread/queue_incref.c new file mode 100644 index 000000000..4f06807c4 --- /dev/null +++ b/core/src/xmake/thread/queue_incref.c @@ -0,0 +1,46 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_queue_incref.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_queue" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_queue_incref(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_queue_t* thread_queue = xm_thread_queue_get(lua, 1); + tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0); + + lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_queue->refn, 1) >= 1); + return 1; +} + diff --git a/core/src/xmake/thread/queue_init.c b/core/src/xmake/thread/queue_init.c new file mode 100644 index 000000000..0c8af884d --- /dev/null +++ b/core/src/xmake/thread/queue_init.c @@ -0,0 +1,87 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file queue_init.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_queue" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * private implementation + */ +static tb_void_t xm_thread_value_free(tb_element_ref_t element, tb_pointer_t buff) +{ + xm_thread_value_t* item = (xm_thread_value_t*)buff; + if (item) + { + if (item->kind == XM_THREAD_VALUE_STR) + { + if (item->u.string) tb_free((tb_pointer_t)item->u.string); + item->u.string = tb_null; + } + item->size = 0; + } +} + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_queue_init(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + tb_bool_t ok = tb_false; + xm_thread_queue_t* thread_queue = tb_null; + do + { + thread_queue = tb_malloc0_type(xm_thread_queue_t); + tb_assert_and_check_break(thread_queue); + + thread_queue->refn = 1; + thread_queue->handle = tb_queue_init(0, tb_element_mem(sizeof(xm_thread_value_t), xm_thread_value_free, tb_null)); + tb_assert_and_check_break(thread_queue->handle); + + xm_lua_pushpointer(lua, (tb_pointer_t)thread_queue); + ok = tb_true; + + } while (0); + + if (!ok) + { + if (thread_queue) + { + if (thread_queue->handle) + { + tb_queue_exit(thread_queue->handle); + thread_queue->handle = tb_null; + } + tb_free(thread_queue); + } + lua_pushnil(lua); + } + return 1; +} diff --git a/core/src/xmake/thread/queue_pop.c b/core/src/xmake/thread/queue_pop.c new file mode 100644 index 000000000..c666a85dd --- /dev/null +++ b/core/src/xmake/thread/queue_pop.c @@ -0,0 +1,92 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_queue_pop.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_queue" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_queue_pop(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_queue_t* thread_queue = xm_thread_queue_get(lua, 1); + tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0); + + if (tb_queue_null(thread_queue->handle)) + { + lua_pushnil(lua); + lua_pushliteral(lua, "the thread queue is empty"); + return 2; + } + + xm_thread_value_t* item = (xm_thread_value_t*)tb_queue_get(thread_queue->handle); + tb_assert_and_check_return_val(item, 0); + + tb_bool_t ok = tb_false; + switch (item->kind) + { + case XM_THREAD_VALUE_STR: + if (item->size) + lua_pushlstring(lua, item->u.string, item->size); + else lua_pushliteral(lua, ""); + ok = tb_true; + break; + case XM_THREAD_VALUE_INT: + lua_pushinteger(lua, item->u.integer); + ok = tb_true; + break; + case XM_THREAD_VALUE_NUM: + lua_pushnumber(lua, item->u.number); + ok = tb_true; + break; + case XM_THREAD_VALUE_BOOL: + lua_pushboolean(lua, item->u.boolean); + ok = tb_true; + break; + case XM_THREAD_VALUE_NIL: + lua_pushnil(lua); + ok = tb_true; + break; + default: + break; + } + + if (!ok) + { + lua_pushnil(lua); + lua_pushliteral(lua, "invalid thread queue item"); + return 2; + } + + tb_queue_pop(thread_queue->handle); + return 1; +} + diff --git a/core/src/xmake/thread/queue_push.c b/core/src/xmake/thread/queue_push.c new file mode 100644 index 000000000..8125f2b9a --- /dev/null +++ b/core/src/xmake/thread/queue_push.c @@ -0,0 +1,96 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_queue_push.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_queue" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_queue_push(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_queue_t* thread_queue = xm_thread_queue_get(lua, 1); + tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0); + + if (tb_queue_full(thread_queue->handle)) + { + lua_pushboolean(lua, tb_false); + lua_pushliteral(lua, "the thread queue is full"); + return 2; + } + + xm_thread_value_t item; + if (lua_isstring(lua, 2)) + { + size_t data_size = 0; + tb_char_t const* data = luaL_checklstring(lua, 2, &data_size); + tb_assert_and_check_return_val(data, 0); + + item.kind = (tb_uint32_t)XM_THREAD_VALUE_STR; + item.size = (tb_uint32_t)data_size; + if (data_size) + { + item.u.string = tb_malloc_cstr(data_size); + tb_assert_and_check_return_val(item.u.string, 0); + tb_memcpy(item.u.string, data, data_size); + } + } + else if (xm_lua_isinteger(lua, 2)) + { + item.kind = (tb_uint32_t)XM_THREAD_VALUE_INT; + item.u.integer = lua_tointeger(lua, 2); + } + else if (lua_isnumber(lua, 2)) + { + item.kind = (tb_uint32_t)XM_THREAD_VALUE_NUM; + item.u.number = lua_tonumber(lua, 2); + } + else if (lua_isboolean(lua, 2)) + { + item.kind = (tb_uint32_t)XM_THREAD_VALUE_BOOL; + item.u.boolean = lua_toboolean(lua, 2); + } + else if (lua_isnil(lua, 2)) + { + item.kind = (tb_uint32_t)XM_THREAD_VALUE_NIL; + } + else + { + lua_pushboolean(lua, tb_false); + lua_pushliteral(lua, "unsupported thread queue item"); + return 2; + } + + tb_queue_put(thread_queue->handle, &item); + lua_pushboolean(lua, tb_true); + return 1; +} + diff --git a/core/src/xmake/thread/queue_size.c b/core/src/xmake/thread/queue_size.c new file mode 100644 index 000000000..559a1dceb --- /dev/null +++ b/core/src/xmake/thread/queue_size.c @@ -0,0 +1,46 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_queue_lock.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_queue" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_queue_size(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_queue_t* thread_queue = xm_thread_queue_get(lua, 1); + tb_assert_and_check_return_val(thread_queue && thread_queue->handle, 0); + + lua_pushinteger(lua, (tb_int_t)tb_queue_size(thread_queue->handle)); + return 1; +} + diff --git a/core/src/xmake/thread/semaphore_exit.c b/core/src/xmake/thread/semaphore_exit.c new file mode 100644 index 000000000..cffffa249 --- /dev/null +++ b/core/src/xmake/thread/semaphore_exit.c @@ -0,0 +1,55 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_semaphore_exit.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_semaphore" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_semaphore_exit(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_semaphore_t* thread_semaphore = xm_thread_semaphore_get(lua, 1); + tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0); + + if (tb_atomic_fetch_and_sub(&thread_semaphore->refn, 1) == 1) + { + if (thread_semaphore->handle) + { + tb_semaphore_exit(thread_semaphore->handle); + thread_semaphore->handle = tb_null; + } + tb_free(thread_semaphore); + } + lua_pushboolean(lua, tb_true); + return 1; +} + diff --git a/core/src/xmake/thread/semaphore_incref.c b/core/src/xmake/thread/semaphore_incref.c new file mode 100644 index 000000000..84c2118d3 --- /dev/null +++ b/core/src/xmake/thread/semaphore_incref.c @@ -0,0 +1,46 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_semaphore_incref.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_semaphore" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_semaphore_incref(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_semaphore_t* thread_semaphore = xm_thread_semaphore_get(lua, 1); + tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0); + + lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_semaphore->refn, 1) >= 1); + return 1; +} + diff --git a/core/src/xmake/thread/semaphore_init.c b/core/src/xmake/thread/semaphore_init.c new file mode 100644 index 000000000..976b48de9 --- /dev/null +++ b/core/src/xmake/thread/semaphore_init.c @@ -0,0 +1,72 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file semaphore_init.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_semaphore" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_semaphore_init(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + tb_bool_t ok = tb_false; + xm_thread_semaphore_t* thread_semaphore = tb_null; + do + { + tb_long_t value = (tb_long_t)luaL_checknumber(lua, 1); + + thread_semaphore = tb_malloc0_type(xm_thread_semaphore_t); + tb_assert_and_check_break(thread_semaphore); + + thread_semaphore->refn = 1; + thread_semaphore->handle = tb_semaphore_init(value); + tb_assert_and_check_break(thread_semaphore->handle); + + xm_lua_pushpointer(lua, (tb_pointer_t)thread_semaphore); + ok = tb_true; + + } while (0); + + if (!ok) + { + if (thread_semaphore) + { + if (thread_semaphore->handle) + { + tb_semaphore_exit(thread_semaphore->handle); + thread_semaphore->handle = tb_null; + } + tb_free(thread_semaphore); + } + lua_pushnil(lua); + } + return 1; +} diff --git a/core/src/xmake/thread/semaphore_post.c b/core/src/xmake/thread/semaphore_post.c new file mode 100644 index 000000000..9ca94bda5 --- /dev/null +++ b/core/src/xmake/thread/semaphore_post.c @@ -0,0 +1,47 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_semaphore_lock.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_semaphore" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_semaphore_post(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_semaphore_t* thread_semaphore = xm_thread_semaphore_get(lua, 1); + tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0); + + tb_long_t value = (tb_long_t)luaL_checknumber(lua, 2); + lua_pushboolean(lua, tb_semaphore_post(thread_semaphore->handle, value)); + return 1; +} + diff --git a/core/src/xmake/thread/semaphore_wait.c b/core/src/xmake/thread/semaphore_wait.c new file mode 100644 index 000000000..c8e4d1491 --- /dev/null +++ b/core/src/xmake/thread/semaphore_wait.c @@ -0,0 +1,47 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_semaphore_unlock.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_semaphore" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_semaphore_wait(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_semaphore_t* thread_semaphore = xm_thread_semaphore_get(lua, 1); + tb_assert_and_check_return_val(thread_semaphore && thread_semaphore->handle, 0); + + tb_long_t timeout = (tb_long_t)luaL_checknumber(lua, 2); + lua_pushinteger(lua, tb_semaphore_wait(thread_semaphore->handle, timeout)); + return 1; +} + diff --git a/core/src/xmake/thread/sharedata_clear.c b/core/src/xmake/thread/sharedata_clear.c new file mode 100644 index 000000000..0c8b4afcf --- /dev/null +++ b/core/src/xmake/thread/sharedata_clear.c @@ -0,0 +1,48 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_sharedata_clear.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_sharedata" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_sharedata_clear(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_sharedata_t* thread_sharedata = xm_thread_sharedata_get(lua, 1); + tb_assert_and_check_return_val(thread_sharedata, 0); + + thread_sharedata->value.kind = XM_THREAD_VALUE_NIL; + tb_buffer_clear(&thread_sharedata->buffer); + lua_pushboolean(lua, tb_true); + return 1; +} + diff --git a/core/src/xmake/thread/sharedata_exit.c b/core/src/xmake/thread/sharedata_exit.c new file mode 100644 index 000000000..ad4a9f33f --- /dev/null +++ b/core/src/xmake/thread/sharedata_exit.c @@ -0,0 +1,51 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_sharedata_exit.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_sharedata" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_sharedata_exit(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_sharedata_t* thread_sharedata = xm_thread_sharedata_get(lua, 1); + tb_assert_and_check_return_val(thread_sharedata, 0); + + if (tb_atomic_fetch_and_sub(&thread_sharedata->refn, 1) == 1) + { + tb_buffer_exit(&thread_sharedata->buffer); + tb_free(thread_sharedata); + } + lua_pushboolean(lua, tb_true); + return 1; +} + diff --git a/core/src/xmake/thread/sharedata_get.c b/core/src/xmake/thread/sharedata_get.c new file mode 100644 index 000000000..abd020d3b --- /dev/null +++ b/core/src/xmake/thread/sharedata_get.c @@ -0,0 +1,82 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_sharedata_get.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_sharedata" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_sharedata_get_(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_sharedata_t* thread_sharedata = xm_thread_sharedata_get(lua, 1); + tb_assert_and_check_return_val(thread_sharedata, 0); + + tb_bool_t ok = tb_false; + switch (thread_sharedata->value.kind) + { + case XM_THREAD_VALUE_STR: + if (tb_buffer_size(&thread_sharedata->buffer) > 0) + lua_pushlstring(lua, (tb_char_t*)tb_buffer_data(&thread_sharedata->buffer), tb_buffer_size(&thread_sharedata->buffer)); + else lua_pushliteral(lua, ""); + ok = tb_true; + break; + case XM_THREAD_VALUE_INT: + lua_pushinteger(lua, thread_sharedata->value.u.integer); + ok = tb_true; + break; + case XM_THREAD_VALUE_NUM: + lua_pushnumber(lua, thread_sharedata->value.u.number); + ok = tb_true; + break; + case XM_THREAD_VALUE_BOOL: + lua_pushboolean(lua, thread_sharedata->value.u.boolean); + ok = tb_true; + break; + case XM_THREAD_VALUE_NIL: + lua_pushnil(lua); + ok = tb_true; + break; + default: + break; + } + + if (!ok) + { + lua_pushnil(lua); + lua_pushliteral(lua, "invalid thread sharedata thread_sharedata"); + return 2; + } + + return 1; +} + + diff --git a/core/src/xmake/thread/sharedata_incref.c b/core/src/xmake/thread/sharedata_incref.c new file mode 100644 index 000000000..e0d32c600 --- /dev/null +++ b/core/src/xmake/thread/sharedata_incref.c @@ -0,0 +1,46 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_sharedata_incref.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_sharedata" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_sharedata_incref(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_sharedata_t* thread_sharedata = xm_thread_sharedata_get(lua, 1); + tb_assert_and_check_return_val(thread_sharedata, 0); + + lua_pushboolean(lua, tb_atomic_fetch_and_add(&thread_sharedata->refn, 1) >= 1); + return 1; +} + diff --git a/core/src/xmake/thread/sharedata_init.c b/core/src/xmake/thread/sharedata_init.c new file mode 100644 index 000000000..b38fc217a --- /dev/null +++ b/core/src/xmake/thread/sharedata_init.c @@ -0,0 +1,66 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file sharedata_init.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_sharedata" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_sharedata_init(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + tb_bool_t ok = tb_false; + xm_thread_sharedata_t* thread_sharedata = tb_null; + do + { + thread_sharedata = tb_malloc0_type(xm_thread_sharedata_t); + tb_assert_and_check_break(thread_sharedata); + + thread_sharedata->refn = 1; + thread_sharedata->value.kind = XM_THREAD_VALUE_NIL; + tb_buffer_init(&thread_sharedata->buffer); + + xm_lua_pushpointer(lua, (tb_pointer_t)thread_sharedata); + ok = tb_true; + + } while (0); + + if (!ok) + { + if (thread_sharedata) + { + tb_buffer_exit(&thread_sharedata->buffer); + tb_free(thread_sharedata); + } + lua_pushnil(lua); + } + return 1; +} diff --git a/core/src/xmake/thread/sharedata_set.c b/core/src/xmake/thread/sharedata_set.c new file mode 100644 index 000000000..08e661f20 --- /dev/null +++ b/core/src/xmake/thread/sharedata_set.c @@ -0,0 +1,84 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_sharedata_set.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread_sharedata" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_sharedata_set(lua_State* lua) +{ + tb_assert_and_check_return_val(lua, 0); + + xm_thread_sharedata_t* thread_sharedata = xm_thread_sharedata_get(lua, 1); + tb_assert_and_check_return_val(thread_sharedata, 0); + + if (lua_isstring(lua, 2)) + { + size_t data_size = 0; + tb_char_t const* data = luaL_checklstring(lua, 2, &data_size); + tb_assert_and_check_return_val(data, 0); + + thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_STR; + if (data_size) + tb_buffer_memncpy(&thread_sharedata->buffer, (tb_byte_t const*)data, data_size); + else tb_buffer_clear(&thread_sharedata->buffer); + } + else if (xm_lua_isinteger(lua, 2)) + { + thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_INT; + thread_sharedata->value.u.integer = lua_tointeger(lua, 2); + } + else if (lua_isnumber(lua, 2)) + { + thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_NUM; + thread_sharedata->value.u.number = lua_tonumber(lua, 2); + } + else if (lua_isboolean(lua, 2)) + { + thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_BOOL; + thread_sharedata->value.u.boolean = lua_toboolean(lua, 2); + } + else if (lua_isnil(lua, 2)) + { + thread_sharedata->value.kind = (tb_uint32_t)XM_THREAD_VALUE_NIL; + } + else + { + lua_pushboolean(lua, tb_false); + lua_pushliteral(lua, "unsupported thread sharedata item"); + return 2; + } + + lua_pushboolean(lua, tb_true); + return 1; +} + + diff --git a/core/src/xmake/thread/thread_exit.c b/core/src/xmake/thread/thread_exit.c new file mode 100644 index 000000000..9d2c8e908 --- /dev/null +++ b/core/src/xmake/thread/thread_exit.c @@ -0,0 +1,64 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_exit.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_exit(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // is pointer? + if (!xm_lua_ispointer(lua, 1)) + return 0; + + // get thread + xm_thread_t* thread = (xm_thread_t*)xm_lua_topointer(lua, 1); + tb_check_return_val(thread, 0); + + // exit thread + if (thread) + { + tb_string_exit(&thread->callback); + tb_string_exit(&thread->callinfo); + if (thread->handle) + { + tb_thread_exit(thread->handle); + thread->handle = tb_null; + } + tb_free(thread); + } + lua_pushboolean(lua, tb_true); + return 1; +} + diff --git a/core/src/xmake/thread/thread_init.c b/core/src/xmake/thread/thread_init.c new file mode 100644 index 000000000..6fc44267a --- /dev/null +++ b/core/src/xmake/thread/thread_init.c @@ -0,0 +1,146 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_init.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" +#include "../engine.h" +#include "../engine_pool.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * macros + */ +#define XM_THREAD_ENGINE_NAME "xmake" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * private implementation + */ + +static tb_int_t xm_thread_func(tb_cpointer_t priv) +{ + xm_thread_t* thread = (xm_thread_t*)priv; + tb_assert_and_check_return_val(thread, 0); + + xm_engine_ref_t engine = xm_engine_pool_alloc(xm_engine_pool()); + if (!engine) engine = xm_engine_init(XM_THREAD_ENGINE_NAME, tb_null); + if (engine) + { + lua_State* lua = xm_engine_lua(engine); + tb_assert(lua); + + // pass callback + tb_char_t const* callback_data = tb_string_cstr(&thread->callback); + tb_size_t callback_size = tb_string_size(&thread->callback); + if (callback_data && callback_size) + { + lua_pushlstring(lua, callback_data, callback_size); + lua_setglobal(lua, "_THREAD_CALLBACK"); + } + + // pass callinfo + tb_char_t const* callinfo_data = tb_string_cstr(&thread->callinfo); + tb_size_t callinfo_size = tb_string_size(&thread->callinfo); + if (callinfo_data && callinfo_size) + { + lua_pushlstring(lua, callinfo_data, callinfo_size); + lua_setglobal(lua, "_THREAD_CALLINFO"); + } + + // start engine + tb_char_t* argv[] = {XM_THREAD_ENGINE_NAME, tb_null}; + xm_engine_main(engine, 1, argv, tb_null); + if (!xm_engine_pool_free(xm_engine_pool(), engine)) + xm_engine_exit(engine); + } + return 0; +} + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_init(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + tb_bool_t ok = tb_false; + xm_thread_t* thread = tb_null; + do + { + // get thread name + tb_char_t const* name = luaL_checkstring(lua, 1); + + // get callback + size_t callback_size = 0; + tb_char_t const* callback_data = luaL_checklstring(lua, 2, &callback_size); + tb_assert_and_check_break(callback_data && callback_size); + + // get callinfo + size_t callinfo_size = 0; + tb_char_t const* callinfo_data = luaL_checklstring(lua, 3, &callinfo_size); + tb_assert_and_check_break(callinfo_data && callinfo_size); + + // get stack size + tb_size_t stacksize = (tb_size_t)luaL_checkinteger(lua, 4); + + // init thread + thread = tb_malloc0_type(xm_thread_t); + tb_assert_and_check_break(thread); + + tb_string_init(&thread->callback); + tb_string_cstrncpy(&thread->callback, callback_data, callback_size); + + tb_string_init(&thread->callinfo); + tb_string_cstrncpy(&thread->callinfo, callinfo_data, callinfo_size); + + // create and start thread + thread->handle = tb_thread_init(name, xm_thread_func, thread, stacksize); + tb_assert_and_check_break(thread->handle); + + xm_lua_pushpointer(lua, (tb_pointer_t)thread); + ok = tb_true; + + } while (0); + + if (!ok) + { + if (thread) + { + tb_string_exit(&thread->callback); + tb_string_exit(&thread->callinfo); + if (thread->handle) + { + tb_thread_exit(thread->handle); + thread->handle = tb_null; + } + tb_free(thread); + } + lua_pushnil(lua); + } + return 1; +} diff --git a/core/src/xmake/thread/thread_resume.c b/core/src/xmake/thread/thread_resume.c new file mode 100644 index 000000000..9843ac2d7 --- /dev/null +++ b/core/src/xmake/thread/thread_resume.c @@ -0,0 +1,53 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_resume.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_resume(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // is pointer? + if (!xm_lua_ispointer(lua, 1)) + return 0; + + // get thread + xm_thread_t* thread = (xm_thread_t*)xm_lua_topointer(lua, 1); + tb_check_return_val(thread && thread->handle, 0); + + // resume thread + lua_pushboolean(lua, tb_thread_resume(thread->handle)); + return 1; +} + diff --git a/core/src/xmake/thread/thread_suspend.c b/core/src/xmake/thread/thread_suspend.c new file mode 100644 index 000000000..e21509413 --- /dev/null +++ b/core/src/xmake/thread/thread_suspend.c @@ -0,0 +1,53 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_suspend.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_suspend(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // is pointer? + if (!xm_lua_ispointer(lua, 1)) + return 0; + + // get thread + xm_thread_t* thread = (xm_thread_t*)xm_lua_topointer(lua, 1); + tb_check_return_val(thread && thread->handle, 0); + + // suspend thread + lua_pushboolean(lua, tb_thread_suspend(thread->handle)); + return 1; +} + diff --git a/core/src/xmake/thread/thread_wait.c b/core/src/xmake/thread/thread_wait.c new file mode 100644 index 000000000..f2d7199ec --- /dev/null +++ b/core/src/xmake/thread/thread_wait.c @@ -0,0 +1,57 @@ +/*!A cross-platform build utility based on Lua + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (C) 2015-present, Xmake Open Source Community. + * + * @author ruki + * @file thread_wait.c + * + */ + +/* ////////////////////////////////////////////////////////////////////////////////////// + * trace + */ +#define TB_TRACE_MODULE_NAME "thread" +#define TB_TRACE_MODULE_DEBUG (0) + +/* ////////////////////////////////////////////////////////////////////////////////////// + * includes + */ +#include "prefix.h" + +/* ////////////////////////////////////////////////////////////////////////////////////// + * implementation + */ +tb_int_t xm_thread_wait(lua_State* lua) +{ + // check + tb_assert_and_check_return_val(lua, 0); + + // is pointer? + if (!xm_lua_ispointer(lua, 1)) + return 0; + + // get thread + xm_thread_t* thread = (xm_thread_t*)xm_lua_topointer(lua, 1); + tb_check_return_val(thread->handle, 0); + + // get timeout + tb_size_t timeout = (tb_size_t)luaL_checkinteger(lua, 2); + + // wait thread + tb_int_t retval; + lua_pushinteger(lua, (tb_int_t)tb_thread_wait(thread->handle, timeout, &retval)); + return 1; +} + diff --git a/core/src/xmake/xmake.sh b/core/src/xmake/xmake.sh index 6c45b6fa0..731d1d783 100755 --- a/core/src/xmake/xmake.sh +++ b/core/src/xmake/xmake.sh @@ -72,6 +72,7 @@ target "xmake" add_files "string/*.c" add_files "tty/*.c" add_files "utils/*.c" + add_files "thread/*.c" if is_plat "mingw"; then add_files "winos/*.c" fi diff --git a/tests/modules/thread/coroutine.lua b/tests/modules/thread/coroutine.lua new file mode 100644 index 000000000..28aa8971e --- /dev/null +++ b/tests/modules/thread/coroutine.lua @@ -0,0 +1,32 @@ +import("core.base.thread") +import("core.base.scheduler") + +function thread_loop() + import("core.base.thread") + print("%s: starting ..", thread.running()) + local dt = os.mclock() + for i = 1, 10 do + print("%s: %d", thread.running(), i) + os.sleep(1000) + end + dt = os.mclock() - dt + print("%s: end, dt: %d ms", thread.running(), dt) +end + +function coroutine_loop() + print("%s: starting ..", scheduler.co_running()) + local dt = os.mclock() + for i = 1, 10 do + print("%s: %d", scheduler.co_running(), i) + os.sleep(1000) + end + dt = os.mclock() - dt + print("%s: end, dt: %d ms", scheduler.co_running(), dt) +end + +function main() + scheduler.co_start_named("coroutine", coroutine_loop) + local t = thread.start_named("thread", thread_loop) + t:wait(-1) +end + diff --git a/tests/modules/thread/event.lua b/tests/modules/thread/event.lua new file mode 100644 index 000000000..fde1511ee --- /dev/null +++ b/tests/modules/thread/event.lua @@ -0,0 +1,25 @@ +import("core.base.thread") + +function callback(event) + import("core.base.thread") + print("%s: starting ..", thread.running()) + while true do + print("%s: waiting ..", thread.running()) + if event:wait(-1) > 0 then + print("%s: triggered", thread.running()) + end + end +end + +function main() + local event = thread.event() + local t = thread.start_named("keyboard", callback, event) + while true do + local ch = io.read() + if ch then + event:post() + end + end + t:wait(-1) +end + diff --git a/tests/modules/thread/mutex.lua b/tests/modules/thread/mutex.lua new file mode 100644 index 000000000..e969c0747 --- /dev/null +++ b/tests/modules/thread/mutex.lua @@ -0,0 +1,24 @@ +import("core.base.thread") + +function callback(mutex) + import("core.base.thread") + print("%s: starting ..", thread.running()) + local dt = os.mclock() + for i = 1, 10 do + mutex:lock() + print("%s: %d", thread.running(), i) + mutex:unlock() + os.sleep(1000) + end + dt = os.mclock() - dt + print("%s: end, dt: %d ms", thread.running(), dt) +end + +function main() + local mutex = thread.mutex() + local t0 = thread.start_named("thread_0", callback, mutex) + local t1 = thread.start_named("thread_1", callback, mutex) + t0:wait(-1) + t1:wait(-1) +end + diff --git a/tests/modules/thread/queue.lua b/tests/modules/thread/queue.lua new file mode 100644 index 000000000..ebf298ec2 --- /dev/null +++ b/tests/modules/thread/queue.lua @@ -0,0 +1,28 @@ +import("core.base.thread") + +function callback(event, queue) + print("starting ..") + while true do + print("waiting ..") + if event:wait(-1) > 0 then + while not queue:empty() do + print(" -> %s", queue:pop()) + end + end + end +end + +function main() + local event = thread.event() + local queue = thread.queue() + local t = thread.start_named("", callback, event, queue) + while true do + local ch = io.read() + if ch then + queue:push(ch) + event:post() + end + end + t:wait(-1) +end + diff --git a/tests/modules/thread/semaphore.lua b/tests/modules/thread/semaphore.lua new file mode 100644 index 000000000..b05774e1d --- /dev/null +++ b/tests/modules/thread/semaphore.lua @@ -0,0 +1,25 @@ +import("core.base.thread") + +function callback(semaphore) + import("core.base.thread") + print("%s: starting ..", thread.running()) + while true do + print("%s: waiting ..", thread.running()) + if semaphore:wait(-1) > 0 then + print("%s: triggered", thread.running()) + end + end +end + +function main() + local semaphore = thread.semaphore("", 1) + local t = thread.start_named("keyboard", callback, semaphore) + while true do + local ch = io.read() + if ch then + semaphore:post(2) + end + end + t:wait(-1) +end + diff --git a/tests/modules/thread/sharedata.lua b/tests/modules/thread/sharedata.lua new file mode 100644 index 000000000..cce265ae1 --- /dev/null +++ b/tests/modules/thread/sharedata.lua @@ -0,0 +1,26 @@ +import("core.base.thread") + +function callback(event, sharedata) + print("starting ..") + while true do + print("waiting ..") + if event:wait(-1) > 0 then + print(" -> %s", sharedata:get()) + end + end +end + +function main() + local event = thread.event() + local sharedata = thread.sharedata() + local t = thread.start_named("", callback, event, sharedata) + while true do + local ch = io.read() + if ch then + sharedata:set(ch) + event:post() + end + end + t:wait(-1) +end + diff --git a/tests/modules/thread/sleep.lua b/tests/modules/thread/sleep.lua new file mode 100644 index 000000000..2e21aa3d2 --- /dev/null +++ b/tests/modules/thread/sleep.lua @@ -0,0 +1,21 @@ +import("core.base.thread") + +function callback(id) + import("core.base.thread") + print("%s: %d starting ..", thread.running(), id) + local dt = os.mclock() + for i = 1, 10 do + print("%s: %d", thread.running(), i) + os.sleep(1000) + end + dt = os.mclock() - dt + print("%s: %d end, dt: %d ms", thread.running(), id, dt) +end + +function main() + local t0 = thread.start_named("thread_0", callback, 0) + local t1 = thread.start_named("thread_1", callback, 1) + t0:wait(-1) + t1:wait(-1) +end + diff --git a/xmake/core/_xmake_main.lua b/xmake/core/_xmake_main.lua index 282106806..a2bbe8e00 100644 --- a/xmake/core/_xmake_main.lua +++ b/xmake/core/_xmake_main.lua @@ -36,6 +36,8 @@ xmake._PROJECT_FILE = "xmake.lua" xmake._WORKING_DIR = os.curdir() xmake._FEATURES = _FEATURES xmake._LUAJIT = _LUAJIT +xmake._THREAD_CALLBACK = _THREAD_CALLBACK +xmake._THREAD_CALLINFO = _THREAD_CALLINFO -- In order to be compatible with updates from lower versions of engine core -- @see https://github.com/xmake-io/xmake/issues/1694#issuecomment-925507210 diff --git a/xmake/core/base/compat/env.lua b/xmake/core/base/compat/env.lua index b7956866e..722c5f97c 100644 --- a/xmake/core/base/compat/env.lua +++ b/xmake/core/base/compat/env.lua @@ -53,7 +53,7 @@ else -- >= Lua 5.2 elseif f < 1 then error("thread environments unsupported in Lua 5.2", 3) --[*] end - f = debug.getinfo(f+2, 'f').func + f = debug.getinfo(f + 2, 'f').func elseif type(f) ~= 'function' then error(("bad argument #1 to '%s' (number expected, got %s)"):format(type(name, f)), 2) end diff --git a/xmake/core/base/pipe.lua b/xmake/core/base/pipe.lua index 48d36df9e..4b122ed9e 100644 --- a/xmake/core/base/pipe.lua +++ b/xmake/core/base/pipe.lua @@ -285,6 +285,11 @@ function _instance:__gc() end end +-- new a pipe +function pipe.new(cdata, name) + return _instance.new(cdata, name) +end + -- open a named pipe file -- -- 1. named pipe (server-side): diff --git a/xmake/core/base/serialize.lua b/xmake/core/base/serialize.lua index b45d5587f..274687f49 100644 --- a/xmake/core/base/serialize.lua +++ b/xmake/core/base/serialize.lua @@ -25,12 +25,26 @@ local stub = serialize._stub or {} serialize._stub = stub serialize._dump = serialize._dump or string._dump or string.dump serialize._BCTAG = xmake._LUAJIT and "\27LJ" or "\27Lua" +stub.isstub = setmetatable({}, { __tostring = function() return "stub indentifier" end }) +stub.__index = stub -- load modules local math = require("base/math") local table = require("base/table") local hashset = require("base/hashset") +function stub:__call(root, fenv) + return self.resolver(root, fenv, table.unpack(self.params, 1, self.params.n)) +end + +function stub:__tostring() + local fparams = {} + for i = 1, self.params.n do + fparams[i] = serialize._make(self.params[i], {}) + end + return string.format("%s(%s)", self.name, table.concat(fparams, ", ")) +end + -- reserved keywords in lua function serialize._keywords() local keywords = serialize._KEYWORDS @@ -167,7 +181,6 @@ function serialize._makefunction(func, opt) end function serialize._resolvefunction(root, fenv, bytecode) - -- check if type(bytecode) ~= "string" then return nil, string.format("invalid bytecode (string expected, got %s)", type(bytecode)) end @@ -337,22 +350,6 @@ function serialize.save(obj, opt) return (#dump < #result) and dump or result end --- init stub metatable -stub.isstub = setmetatable({}, { __tostring = function() return "stub indentifier" end }) -stub.__index = stub - -function stub:__call(root, fenv) - return self.resolver(root, fenv, table.unpack(self.params, 1, self.params.n)) -end - -function stub:__tostring() - local fparams = {} - for i = 1, self.params.n do - fparams[i] = serialize._make(self.params[i], {}) - end - return string.format("%s(%s)", self.name, table.concat(fparams, ", ")) -end - -- called by functions in deserialize environment -- create a function (called stub) to finish deserialization function serialize._createstub(name, resolver, env, ...) @@ -406,23 +403,13 @@ end -- create a env for deserialze load() call function serialize._createenv() - - -- init env local env = { nan = math.nan, inf = math.huge } - - -- resolve reference function env.ref(...) - -- load ref return serialize._createstub("ref", serialize._resolveref, env, ...) end - - -- load function function env.func(...) - -- load func return serialize._createstub("func", serialize._resolvefunction, env, ...) end - - -- return new env return env end @@ -440,7 +427,6 @@ function serialize._load(str) local env = serialize._createenv() local script, errors = load(str, binary and "=(b)" or "=(t)", binary and "b" or "t", env) if script then - -- load obj local ok, obj = pcall(script) if ok then result = obj @@ -449,7 +435,6 @@ function serialize._load(str) result, errors = serialize._resolvestub(result, result, fenv, "<root>") end else - -- error errors = tostring(obj) end end @@ -477,8 +462,6 @@ end -- @return obj, errors -- function serialize.load(str) - - -- check assert(str) -- load string diff --git a/xmake/core/base/task.lua b/xmake/core/base/task.lua index df865b92d..29cca38f2 100644 --- a/xmake/core/base/task.lua +++ b/xmake/core/base/task.lua @@ -344,28 +344,21 @@ function task._load(filepath) if not ok then return nil, errors end - - -- ok? return tasks end -- get task apis function task.apis() - - return - { - values = - { + return { + values = { -- task.set_xxx "task.set_category" -- main, action, plugin, task (default) - } - , dictionary = - { + }, + dictionary = { -- task.set_xxx "task.set_menu" - } - , script = - { + }, + script = { -- task.on_xxx "task.on_run" } @@ -490,8 +483,6 @@ end -- run given task function task:run(...) - - -- check local on_run = self:get("run") if not on_run then return false, string.format("task(\"%s\"): no run script, please call on_run() first!", self:fullname()) diff --git a/xmake/core/base/thread.lua b/xmake/core/base/thread.lua new file mode 100644 index 000000000..a53e7bc82 --- /dev/null +++ b/xmake/core/base/thread.lua @@ -0,0 +1,925 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file thread.lua +-- + +-- define module +local thread = thread or {} +local _thread = _thread or {} +local _mutex = _mutex or {} +local _event = _event or {} +local _semaphore = _semaphore or {} +local _queue = _queue or {} +local _sharedata = _sharedata or {} + +-- load modules +local io = require("base/io") +local libc = require("base/libc") +local pipe = require("base/pipe") +local bytes = require("base/bytes") +local table = require("base/table") +local string = require("base/string") +local scheduler = require("base/scheduler") +local sandbox = require("sandbox/sandbox") + +-- the thread status +thread.STATUS_READY = 1 +thread.STATUS_RUNNING = 2 +thread.STATUS_SUSPENDED = 3 +thread.STATUS_DEAD = 4 + +-- new a thread +function _thread.new(callback, opt) + opt = opt or {} + local instance = table.inherit(_thread) + instance._NAME = opt.name or "anonymous" + instance._ARGV = opt.argv + instance._CALLBACK = callback + instance._STACKSIZE = opt.stacksize or 0 + instance._STATUS = thread.STATUS_READY + setmetatable(instance, _thread) + return instance +end + +-- get thread name +function _thread:name() + return self._NAME +end + +-- get cdata of thread +function _thread:cdata() + return self._HANLDE +end + +-- get thread status +function _thread:status() + return self._STATUS +end + +-- is ready? +function _thread:is_ready() + return self:status() == thread.STATUS_READY +end + +-- is running? +function _thread:is_running() + return self:status() == thread.STATUS_RUNNING +end + +-- is suspended? +function _thread:is_suspended() + return self:status() == thread.STATUS_SUSPENDED +end + +-- is dead? +function _thread:is_dead() + return self:status() == thread.STATUS_DEAD +end + +-- start thread +function _thread:start() + if not self:is_ready() then + return nil, string.format("%s: cannot start non-ready thread!", self) + end + assert(not self:cdata()) + + -- translate arguments (mutex, ...) + local argv = {} + for _, arg in ipairs(self._ARGV) do + if type(arg) == "table" then + -- is mutex? we can only pass cdata address + if arg._MUTEX and arg.cdata then + thread.mutex_incref(arg:cdata()) + arg = {mutex = true, name = arg:name(), caddr = libc.dataptr(arg:cdata())} + -- is event? we can only pass cdata address + elseif arg._EVENT and arg.cdata then + thread.event_incref(arg:cdata()) + arg = {event = true, name = arg:name(), caddr = libc.dataptr(arg:cdata())} + -- is semaphore? we can only pass cdata address + elseif arg._SEMAPHORE and arg.cdata then + thread.semaphore_incref(arg:cdata()) + arg = {semaphore = true, name = arg:name(), caddr = libc.dataptr(arg:cdata())} + -- is queue? we can only pass cdata address + elseif arg._QUEUE and arg.cdata then + thread.queue_incref(arg:cdata()) + arg = {queue = true, name = arg:name(), caddr = libc.dataptr(arg:cdata())} + -- is sharedata? we can only pass cdata address + elseif arg._SHAREDATA and arg.cdata then + thread.sharedata_incref(arg:cdata()) + arg = {sharedata = true, name = arg:name(), caddr = libc.dataptr(arg:cdata())} + end + end + table.insert(argv, arg) + end + + -- init callback info + local callback = string._dump(self._CALLBACK) + local callinfo = {name = self:name(), argv = argv} + + -- we need a pipe pair to wait and listen thread exit event + local rpipe, wpipe = pipe.openpair("BA") -- rpipe (block) + self._RPIPE = rpipe + callinfo.wpipe = libc.dataptr(wpipe:cdata()) + -- we need to suppress gc to free it, because it has been transfer to thread in another lua state instance + wpipe._PIPE = nil + + -- serialize and pass callback and arguments to this thread + -- we do not use string.serialize to serialize callback, because it's slower (deserialize) + -- and we cannot strip function debug info, we need to reserve _ENV, and other upvalue names + callinfo = string.serialize(callinfo, {strip = true, indent = false}) + + -- init and start thread + local handle, errors = thread.thread_init(self:name(), callback, callinfo, self._STACKSIZE) + if not handle then + return nil, errors or string.format("%s: failed to create thread!", self) + end + + self._HANLDE = handle + self._STATUS = thread.STATUS_RUNNING + return true +end + +-- suspend thread +function _thread:suspend() + if not self:is_running() then + return nil, string.format("%s: cannot suspend non-running thread!", self) + end + assert(self:cdata()) + + local ok, errors = thread.thread_suspend(self:cdata()) + if not ok then + return nil, errors or string.format("%s: failed to suspend thread!", self) + end + + self._STATUS = thread.STATUS_SUSPENDED + return true +end + +-- resume thread +function _thread:resume() + if not self:is_suspended() then + return nil, string.format("%s: cannot suspend non-suspended thread!", self) + end + assert(self:cdata()) + + local ok, errors = thread.thread_resume(self:cdata()) + if not ok then + return nil, errors or string.format("%s: failed to resume thread!", self) + end + + self._STATUS = thread.STATUS_RUNNING + return true +end + +-- wait thread +function _thread:wait(timeout) + if self:is_dead() then + return 1 + elseif self:is_ready() then + return -1, string.format("%s: cannot wait ready thread!", self) + end + assert(self:cdata()) + + local ok, errors + local rpipe = self._RPIPE + if rpipe and scheduler:co_running() then + ok, errors = rpipe:wait(pipe.EV_READ, timeout) + else + ok, errors = thread.thread_wait(self:cdata(), timeout) + end + if ok < 0 then + return -1, errors or string.format("%s: failed to resume thread!", self) + end + + if ok > 0 then + self._STATUS = thread.STATUS_DEAD + end + return ok +end + +-- tostring(thread) +function _thread:__tostring() + local status_strs = self._STATUS_STRS + if not status_strs then + status_strs = { + [thread.STATUS_READY] = "ready", + [thread.STATUS_RUNNING] = "running", + [thread.STATUS_SUSPENDED] = "suspended", + [thread.STATUS_DEAD] = "dead" + } + self._STATUS_STRS = status_strs + end + return string.format("<thread: %s/%s>", self:name(), status_strs[self:status()]) +end + +-- gc(thread) +function _thread:__gc() + if self:cdata() and self:is_dead() and thread.thread_exit(self:cdata()) then + self._HANLDE = nil + end +end + +-- new an mutex +function _mutex.new(name, cdata) + local mutex = table.inherit(_mutex) + mutex._NAME = name + mutex._MUTEX = cdata + mutex._LOCKED_NUM = 0 + setmetatable(mutex, _mutex) + return mutex +end + +-- get the mutex name +function _mutex:name() + return self._NAME +end + +-- get the cdata +function _mutex:cdata() + return self._MUTEX +end + +-- is locked? +function _mutex:islocked() + return self._LOCKED_NUM > 0 +end + +-- lock mutex +-- +-- @return ok, errors +-- +function _mutex:lock() + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + if self._LOCKED_NUM > 0 or thread.mutex_lock(self:cdata()) then + self._LOCKED_NUM = self._LOCKED_NUM + 1 + return true + else + return false, string.format("%s: lock failed!", self) + end +end + +-- try to lock mutex +-- +-- @param opt the argument option, {shared = true} +-- +-- @return ok, errors +-- +function _mutex:trylock(opt) + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + if self._LOCKED_NUM > 0 or thread.mutex_trylock(self:cdata(), opt) then + self._LOCKED_NUM = self._LOCKED_NUM + 1 + return true + else + return false, string.format("%s: trylock failed!", self) + end +end + +-- unlock mutex +function _mutex:unlock(opt) + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + if self._LOCKED_NUM > 1 or (self._LOCKED_NUM > 0 and thread.mutex_unlock(self:cdata())) then + if self._LOCKED_NUM > 0 then + self._LOCKED_NUM = self._LOCKED_NUM - 1 + else + self._LOCKED_NUM = 0 + end + return true + else + return false, string.format("%s: unlock failed!", self) + end +end + +-- close mutex +function _mutex:close() + + -- ensure opened + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + -- close it + ok = thread.mutex_exit(self:cdata()) + if ok then + self._MUTEX = nil + self._LOCKED_NUM = 0 + end + return ok +end + +-- ensure the file is opened +function _mutex:_ensure_opened() + if not self:cdata() then + return false, string.format("%s: has been closed!", self) + end + return true +end + +-- tostring(mutex) +function _mutex:__tostring() + return "<mutex: " .. (self:name() or tostring(self:cdata())) .. ">" +end + +-- gc(mutex) +function _mutex:__gc() + if self:cdata() and thread.mutex_exit(self:cdata()) then + self._MUTEX = nil + self._LOCKED_NUM = 0 + end +end + +-- new an event +function _event.new(name, cdata) + local event = table.inherit(_event) + event._NAME = name + event._EVENT = cdata + setmetatable(event, _event) + return event +end + +-- get the event name +function _event:name() + return self._NAME +end + +-- get the cdata +function _event:cdata() + return self._EVENT +end + +-- post event +-- +-- @return ok, errors +-- +function _event:post() + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + if not thread.event_post(self:cdata()) then + return false, string.format("%s: post failed!", self) + end + return true +end + +-- wait event +function _event:wait(timeout) + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + local ok, errors = thread.event_wait(self:cdata(), timeout) + if ok < 0 then + return false, string.format("%s: wait failed, errors: %s!", self, errors or "unknown") + end + return ok +end + +-- close event +function _event:close() + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + ok = thread.event_exit(self:cdata()) + if ok then + self._EVENT = nil + end + return ok +end + +-- ensure the file is opened +function _event:_ensure_opened() + if not self:cdata() then + return false, string.format("%s: has been closed!", self) + end + return true +end + +-- tostring(event) +function _event:__tostring() + return "<event: " .. (self:name() or tostring(self:cdata())) .. ">" +end + +-- gc(event) +function _event:__gc() + if self:cdata() and thread.event_exit(self:cdata()) then + self._EVENT = nil + end +end + +-- new an semaphore +function _semaphore.new(name, cdata) + local semaphore = table.inherit(_semaphore) + semaphore._NAME = name + semaphore._SEMAPHORE = cdata + setmetatable(semaphore, _semaphore) + return semaphore +end + +-- get the semaphore name +function _semaphore:name() + return self._NAME +end + +-- get the cdata +function _semaphore:cdata() + return self._SEMAPHORE +end + +-- post semaphore +-- +-- @param value the semaphore value +-- +-- @return ok, errors +-- +function _semaphore:post(value) + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + if not thread.semaphore_post(self:cdata(), value) then + return false, string.format("%s: post failed!", self) + end + return true +end + +-- wait semaphore +function _semaphore:wait(timeout) + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + local ok, errors = thread.semaphore_wait(self:cdata(), timeout) + if ok < 0 then + return false, string.format("%s: wait failed, errors: %s!", self, errors or "unknown") + end + return ok +end + +-- close semaphore +function _semaphore:close() + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + ok = thread.semaphore_exit(self:cdata()) + if ok then + self._SEMAPHORE = nil + end + return ok +end + +-- ensure the file is opened +function _semaphore:_ensure_opened() + if not self:cdata() then + return false, string.format("%s: has been closed!", self) + end + return true +end + +-- tostring(semaphore) +function _semaphore:__tostring() + return "<semaphore: " .. (self:name() or tostring(self:cdata())) .. ">" +end + +-- gc(semaphore) +function _semaphore:__gc() + if self:cdata() and thread.semaphore_exit(self:cdata()) then + self._SEMAPHORE = nil + end +end + +-- new an queue +function _queue.new(name, cdata) + local queue = table.inherit(_queue) + queue._NAME = name + queue._QUEUE = cdata + setmetatable(queue, _queue) + return queue +end + +-- get the queue name +function _queue:name() + return self._NAME +end + +-- get the cdata +function _queue:cdata() + return self._QUEUE +end + +-- get queue size +function _queue:size() + local ok, errors = self:_ensure_opened() + if not ok then + return nil, errors + end + + return thread.queue_size(self:cdata()) +end + +-- is empty queue? +function _queue:empty() + local ok, errors = self:_ensure_opened() + if not ok then + return nil, errors + end + + return thread.queue_size(self:cdata()) == 0 +end + +-- clear queue +function _queue:clear() + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + local ok, errors = thread.queue_clear(self:cdata()) + if not ok then + return false, string.format("%s: clear failed, errors: %s!", self, errors or "unknown") + end + return ok +end + +-- push queue item +function _queue:push(value) + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + if type(value) == "table" then + value = string.serialize(value, {strip = true, indent = false}) + if value == nil then + return false, string.format("%s: cannot serialize value: %s", self, value) + end + value = "__table_" .. value + end + + local ok, errors = thread.queue_push(self:cdata(), value) + if not ok then + return false, string.format("%s: push item failed, errors: %s!", self, errors or "unknown") + end + return ok +end + +-- pop queue item +function _queue:pop() + local ok, errors = self:_ensure_opened() + if not ok then + return nil, errors or "unknown" + end + + local value, errors = thread.queue_pop(self:cdata()) + if value == nil and errors then + return nil, string.format("%s: push item failed, errors: %s!", self, errors or "unknown") + end + + if type(value) == "string" and value:startswith("__table_") then + value = value:sub(9) + value, errors = string.deserialize(value) + if not value then + return nil, string.format("invalid queue item, %s!", errors or "unknown") + end + end + return value +end + +-- close queue +function _queue:close() + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + ok = thread.queue_exit(self:cdata()) + if ok then + self._QUEUE = nil + end + return ok +end + +-- ensure the file is opened +function _queue:_ensure_opened() + if not self:cdata() then + return false, string.format("%s: has been closed!", self) + end + return true +end + +-- tostring(queue) +function _queue:__tostring() + return "<queue: " .. (self:name() or tostring(self:cdata())) .. ">" +end + +-- gc(queue) +function _queue:__gc() + if self:cdata() and thread.queue_exit(self:cdata()) then + self._QUEUE = nil + end +end + +-- new an sharedata +function _sharedata.new(name, cdata) + local sharedata = table.inherit(_sharedata) + sharedata._NAME = name + sharedata._SHAREDATA = cdata + setmetatable(sharedata, _sharedata) + return sharedata +end + +-- get the sharedata name +function _sharedata:name() + return self._NAME +end + +-- get the cdata +function _sharedata:cdata() + return self._SHAREDATA +end + +-- clear sharedata +function _sharedata:clear() + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + local ok, errors = thread.sharedata_clear(self:cdata()) + if not ok then + return false, string.format("%s: clear failed, errors: %s!", self, errors or "unknown") + end + return ok +end + +-- set sharedata +function _sharedata:set(value) + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + if type(value) == "table" then + value = string.serialize(value, {strip = true, indent = false}) + if value == nil then + return false, string.format("%s: cannot serialize value: %s", self, value) + end + value = "__table_" .. value + end + + local ok, errors = thread.sharedata_set(self:cdata(), value) + if not ok then + return false, string.format("%s: set sharedata failed, errors: %s!", self, errors or "unknown") + end + return ok +end + +-- get sharedata +function _sharedata:get() + local ok, errors = self:_ensure_opened() + if not ok then + return nil, errors or "unknown" + end + + local value, errors = thread.sharedata_get(self:cdata()) + if value == nil and errors then + return nil, string.format("%s: get sharedata failed, errors: %s!", self, errors or "unknown") + end + + if type(value) == "string" and value:startswith("__table_") then + value = value:sub(9) + value, errors = string.deserialize(value) + if not value then + return nil, string.format("invalid sharedata, %s!", errors or "unknown") + end + end + return value +end + +-- close sharedata +function _sharedata:close() + local ok, errors = self:_ensure_opened() + if not ok then + return false, errors + end + + ok = thread.sharedata_exit(self:cdata()) + if ok then + self._SHAREDATA = nil + end + return ok +end + +-- ensure the file is opened +function _sharedata:_ensure_opened() + if not self:cdata() then + return false, string.format("%s: has been closed!", self) + end + return true +end + +-- tostring(sharedata) +function _sharedata:__tostring() + return "<sharedata: " .. (self:name() or tostring(self:cdata())) .. ">" +end + +-- gc(sharedata) +function _sharedata:__gc() + if self:cdata() and thread.sharedata_exit(self:cdata()) then + self._SHAREDATA = nil + end +end + +-- new a thread +-- +-- @param callback the thread callback +-- @param opt the thread options, e.g. {name = "", argv = {}, stacksize = 8192} +-- +-- @return the thread instance +-- +function thread.new(callback, opt) + if callback == nil then + return nil, "invalid thread, callback is nil" + end + return _thread.new(callback, opt) +end + +-- get the running thread name +function thread.running() + return thread._RUNNING +end + +-- run thread +function thread._run_thread(callback_str, callinfo_str) + + -- load callback info + local callinfo + local argv + local threadname + local wpipe + if callinfo_str then + local result, errors = string.deserialize(callinfo_str) + if not result then + return false, string.format("invalid thread callinfo, %s!", errors or "unknown") + end + callinfo = result + if callinfo then + argv = callinfo.argv + threadname = callinfo.name + wpipe = pipe.new(libc.ptraddr(callinfo.wpipe)) + end + end + + -- load callback + local callback + local fenvs = {} + if callback_str then + local script, errors = load(callback_str, "=(thread)", "b", fenvs) + if not script then + return false, string.format("cannot load thread(%s) callback, %s!", threadname or "unknown", errors or "unknown") + end + for i = 1, math.huge do + local upname, upvalue = debug.getupvalue(script, i) + if upname == nil or upname == "" then + break + end + if upvalue == nil then + return false, string.format("we cannot access upvalue(%s) in thread(%s) callback!", upname, threadname or "unknown") + end + end + callback = script + end + if not callback then + return false, "no thread callback" + end + + -- bind sandbox + local sandbox_inst, errors = sandbox.new(callback) + if not sandbox_inst then + return false, errors + end + + -- save the running thread name + thread._RUNNING = threadname + + -- translate arguments (mutex, ...) + if argv then + local newargv = {} + for _, arg in ipairs(argv) do + if type(arg) == "table" and arg.mutex and arg.caddr then + arg = _mutex.new(arg.name, libc.ptraddr(arg.caddr)) + elseif type(arg) == "table" and arg.event and arg.caddr then + arg = _event.new(arg.name, libc.ptraddr(arg.caddr)) + elseif type(arg) == "table" and arg.semaphore and arg.caddr then + arg = _semaphore.new(arg.name, libc.ptraddr(arg.caddr)) + elseif type(arg) == "table" and arg.queue and arg.caddr then + arg = _queue.new(arg.name, libc.ptraddr(arg.caddr)) + elseif type(arg) == "table" and arg.sharedata and arg.caddr then + arg = _sharedata.new(arg.name, libc.ptraddr(arg.caddr)) + end + table.insert(newargv, arg) + end + argv = newargv + end + + -- do callback + local ok, errors = sandbox.load(sandbox_inst:script(), table.unpack(argv or {})) + + -- thread is finished, we need to notify the waited thread + if wpipe then + local ok, errors = wpipe:write("exited") + if ok == nil then + return false, errors + end + end + return ok, errors +end + +-- open a mutex +function thread.mutex(name) + local mutex = thread.mutex_init() + if mutex then + return _mutex.new(name, mutex) + else + return nil, string.format("cannot open mutex: %s", os.strerror()) + end +end + +-- open a event +function thread.event(name) + local event = thread.event_init() + if event then + return _event.new(name, event) + else + return nil, string.format("cannot open event: %s", os.strerror()) + end +end + +-- open a semaphore +function thread.semaphore(name, value) + local semaphore = thread.semaphore_init(value or 0) + if semaphore then + return _semaphore.new(name, semaphore) + else + return nil, string.format("cannot open semaphore: %s", os.strerror()) + end +end + +-- open a queue +function thread.queue(name) + local queue = thread.queue_init() + if queue then + return _queue.new(name, queue) + else + return nil, string.format("cannot open queue: %s", os.strerror()) + end +end + +-- open a sharedata +function thread.sharedata(name) + local sharedata = thread.sharedata_init() + if sharedata then + return _sharedata.new(name, sharedata) + else + return nil, string.format("cannot open sharedata: %s", os.strerror()) + end +end + +-- return module +return thread + diff --git a/xmake/core/main.lua b/xmake/core/main.lua index 87e94c824..3f0a4484f 100644 --- a/xmake/core/main.lua +++ b/xmake/core/main.lua @@ -41,6 +41,7 @@ local project = require("project/project") local localcache = require("cache/localcache") local profiler = require("base/profiler") local debugger = require("base/debugger") +local thread = require("base/thread") -- init the option menu local menu = @@ -258,6 +259,22 @@ function main._limit_root() return not option.get("root") and os.getenv("XMAKE_ROOT") ~= 'y' and os.host() ~= 'haiku' end +-- run task +function main._run_task(taskname) + local taskinst = task.task(taskname) or project.task(taskname) + if not taskinst then + return false, string.format("do unknown task(%s)!", taskname) + end + + scheduler:co_start_named("xmake " .. taskname, function () + local ok, errors = taskinst:run() + if not ok then + os.raise(errors) + end + end) + return true +end + -- the main entry function function main.entry() @@ -314,22 +331,21 @@ Or you can add `--root` option or XMAKE_ROOT=y to allow run as root temporarily. localcache.save("history") end - -- get task instance - local taskname = option.taskname() or "build" - local taskinst = task.task(taskname) or project.task(taskname) - if not taskinst then - return main._exit(false, string.format("do unknown task(%s)!", taskname)) - end - - -- run task + -- enable scheduler scheduler:enable(true) - scheduler:co_start_named("xmake " .. taskname, function () - local ok, errors = taskinst:run() - if not ok then - os.raise(errors) - end - end) + -- run task or thread + local thread_callback = xmake._THREAD_CALLBACK + if thread_callback then + ok, errors = thread._run_thread(thread_callback, xmake._THREAD_CALLINFO) + else + ok, errors = main._run_task(option.taskname() or "build") + end + if not ok then + return main._exit(ok, errors) + end + + -- start runloop ok, errors = scheduler:runloop() if not ok then return main._exit(ok, errors) diff --git a/xmake/core/sandbox/modules/coroutine.lua b/xmake/core/sandbox/modules/coroutine.lua index 60d67be96..b1af6581f 100644 --- a/xmake/core/sandbox/modules/coroutine.lua +++ b/xmake/core/sandbox/modules/coroutine.lua @@ -34,8 +34,6 @@ sandbox_coroutine.running = coroutine.running -- resume coroutine function sandbox_coroutine.resume(co, ...) - - -- resume it local ok, results = coroutine.resume(co, ...) if not ok then @@ -54,8 +52,6 @@ function sandbox_coroutine.resume(co, ...) -- raise it raise(errors) end - - -- ok return results end diff --git a/xmake/core/sandbox/modules/import/core/base/thread.lua b/xmake/core/sandbox/modules/import/core/base/thread.lua new file mode 100644 index 000000000..21e068964 --- /dev/null +++ b/xmake/core/sandbox/modules/import/core/base/thread.lua @@ -0,0 +1,394 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, Xmake Open Source Community. +-- +-- @author ruki +-- @file thread.lua +-- + +-- load modules +local utils = require("base/utils") +local string = require("base/string") +local thread = require("base/thread") +local raise = require("sandbox/modules/raise") + +-- define module +local sandbox_core_base_thread = sandbox_core_base_thread or {} +local sandbox_core_base_thread_instance = sandbox_core_base_thread_instance or {} +local sandbox_core_base_thread_mutex = sandbox_core_base_thread_mutex or {} +local sandbox_core_base_thread_event = sandbox_core_base_thread_event or {} +local sandbox_core_base_thread_semaphore = sandbox_core_base_thread_semaphore or {} +local sandbox_core_base_thread_queue = sandbox_core_base_thread_queue or {} +local sandbox_core_base_thread_sharedata = sandbox_core_base_thread_sharedata or {} + +-- export the thread status +sandbox_core_base_thread.STATUS_READY = thread.STATUS_READY +sandbox_core_base_thread.STATUS_RUNNING = thread.STATUS_RUNNING +sandbox_core_base_thread.STATUS_SUSPENDED = thread.STATUS_SUSPENDED +sandbox_core_base_thread.STATUS_DEAD = thread.STATUS_DEAD + +-- wrap thread +function _thread_wrap(instance) + + -- hook thread interfaces + local hooked = {} + for name, func in pairs(sandbox_core_base_thread_instance) do + if not name:startswith("_") and type(func) == "function" then + hooked["_" .. name] = instance["_" .. name] or instance[name] + hooked[name] = func + end + end + for name, func in pairs(hooked) do + instance[name] = func + end + return instance +end + +-- start thread +function sandbox_core_base_thread_instance.start(instance) + local ok, errors = instance:_start() + if not ok then + raise(errors) + end + return instance +end + +-- suspend thread +function sandbox_core_base_thread_instance.suspend(instance) + local ok, errors = instance:_suspend() + if not ok then + raise(errors) + end +end + +-- resume thread +function sandbox_core_base_thread_instance.resume(instance) + local ok, errors = instance:_resume() + if not ok then + raise(errors) + end +end + +-- wait thread +function sandbox_core_base_thread_instance.wait(instance, timeout) + local ok, errors = instance:_wait(timeout) + if ok < 0 then + raise(errors) + end +end + +-- lock mutex +function sandbox_core_base_thread_mutex.lock(mutex) + local ok, errors = mutex:_lock() + if not ok then + raise(errors) + end +end + +-- unlock mutex +function sandbox_core_base_thread_mutex.unlock(mutex) + local ok, errors = mutex:_unlock() + if not ok then + raise(errors) + end +end + +-- close mutex +function sandbox_core_base_thread_mutex.close(mutex) + local ok, errors = mutex:_close() + if not ok then + raise(errors) + end +end + +-- post event +function sandbox_core_base_thread_event.post(event) + local ok, errors = event:_post() + if not ok then + raise(errors) + end +end + +-- wait event +function sandbox_core_base_thread_event.wait(event, timeout) + local ok, errors = event:_wait(timeout) + if ok < 0 then + raise(errors) + end + return ok +end + +-- close event +function sandbox_core_base_thread_event.close(event) + local ok, errors = event:_close() + if not ok then + raise(errors) + end +end + +-- post semaphore +function sandbox_core_base_thread_semaphore.post(semaphore, value) + local ok, errors = semaphore:_post(value) + if not ok then + raise(errors) + end +end + +-- wait semaphore +function sandbox_core_base_thread_semaphore.wait(semaphore, timeout) + local ok, errors = semaphore:_wait(timeout) + if ok < 0 then + raise(errors) + end + return ok +end + +-- close semaphore +function sandbox_core_base_thread_semaphore.close(semaphore) + local ok, errors = semaphore:_close() + if not ok then + raise(errors) + end +end + +-- get queue size +function sandbox_core_base_thread_queue.size(queue) + local size, errors = queue:_size() + if not size then + raise(errors) + end + return size +end + +-- is empty queue? +function sandbox_core_base_thread_queue.empty(queue) + local ok, errors = queue:_empty() + if ok == nil then + raise(errors) + end + return ok +end + +-- clear queue +function sandbox_core_base_thread_queue.clear(queue) + local ok, errors = queue:_clear() + if not ok then + raise(errors) + end + return ok +end + +-- push queue item +function sandbox_core_base_thread_queue.push(queue, value) + local ok, errors = queue:_push(value) + if not ok then + raise(errors) + end + return ok +end + +-- pop queue item +function sandbox_core_base_thread_queue.pop(queue) + local value, errors = queue:_pop() + if value == nil and errors then + raise(errors) + end + return value +end + +-- close queue +function sandbox_core_base_thread_queue.close(queue) + local ok, errors = queue:_close() + if not ok then + raise(errors) + end +end + +-- clear sharedata +function sandbox_core_base_thread_sharedata.clear(sharedata) + local ok, errors = sharedata:_clear() + if not ok then + raise(errors) + end + return ok +end + +-- set sharedata +function sandbox_core_base_thread_sharedata.set(sharedata, value) + local ok, errors = sharedata:_set(value) + if not ok then + raise(errors) + end + return ok +end + +-- get sharedata +function sandbox_core_base_thread_sharedata.get(sharedata) + local value, errors = sharedata:_get() + if value == nil and errors then + raise(errors) + end + return value +end + +-- close sharedata +function sandbox_core_base_thread_sharedata.close(sharedata) + local ok, errors = sharedata:_close() + if not ok then + raise(errors) + end +end + +-- new thread +function sandbox_core_base_thread.new(callback, opt) + local instance, errors = thread.new(callback, opt) + if not instance then + raise(errors) + end + return _thread_wrap(instance) +end + +-- start a thread +function sandbox_core_base_thread.start(callback, ...) + return sandbox_core_base_thread.start_withopt(callback, {argv = table.pack(...)}) +end + +-- start a named thread +function sandbox_core_base_thread.start_named(name, callback, ...) + return sandbox_core_base_thread.start_withopt(callback, {name = name, argv = table.pack(...)}) +end + +-- start a thread with options +function sandbox_core_base_thread.start_withopt(callback, opt) + return sandbox_core_base_thread.new(callback, opt):start() +end + +-- get the running thread +function sandbox_core_base_thread.running() + local instance, errors = thread.running() + if not instance then + raise(errors) + end + return instance +end + +-- open a mutex +function sandbox_core_base_thread.mutex(name) + local mutex, errors = thread.mutex(name) + if not mutex then + raise(errors) + end + + -- hook filemutex interfaces + local hooked = {} + for name, func in pairs(sandbox_core_base_thread_mutex) do + if not name:startswith("_") and type(func) == "function" then + hooked["_" .. name] = mutex["_" .. name] or mutex[name] + hooked[name] = func + end + end + for name, func in pairs(hooked) do + mutex[name] = func + end + return mutex +end + +-- open a event +function sandbox_core_base_thread.event(name) + local event, errors = thread.event(name) + if not event then + raise(errors) + end + + -- hook fileevent interfaces + local hooked = {} + for name, func in pairs(sandbox_core_base_thread_event) do + if not name:startswith("_") and type(func) == "function" then + hooked["_" .. name] = event["_" .. name] or event[name] + hooked[name] = func + end + end + for name, func in pairs(hooked) do + event[name] = func + end + return event +end + +-- open a semaphore +function sandbox_core_base_thread.semaphore(name, value) + local semaphore, errors = thread.semaphore(name, value) + if not semaphore then + raise(errors) + end + + -- hook filesemaphore interfaces + local hooked = {} + for name, func in pairs(sandbox_core_base_thread_semaphore) do + if not name:startswith("_") and type(func) == "function" then + hooked["_" .. name] = semaphore["_" .. name] or semaphore[name] + hooked[name] = func + end + end + for name, func in pairs(hooked) do + semaphore[name] = func + end + return semaphore +end + +-- open a queue +function sandbox_core_base_thread.queue(name) + local queue, errors = thread.queue(name) + if not queue then + raise(errors) + end + + -- hook filequeue interfaces + local hooked = {} + for name, func in pairs(sandbox_core_base_thread_queue) do + if not name:startswith("_") and type(func) == "function" then + hooked["_" .. name] = queue["_" .. name] or queue[name] + hooked[name] = func + end + end + for name, func in pairs(hooked) do + queue[name] = func + end + return queue +end + +-- open a sharedata +function sandbox_core_base_thread.sharedata(name) + local sharedata, errors = thread.sharedata(name) + if not sharedata then + raise(errors) + end + + -- hook filesharedata interfaces + local hooked = {} + for name, func in pairs(sandbox_core_base_thread_sharedata) do + if not name:startswith("_") and type(func) == "function" then + hooked["_" .. name] = sharedata["_" .. name] or sharedata[name] + hooked[name] = func + end + end + for name, func in pairs(hooked) do + sharedata[name] = func + end + return sharedata +end + +-- return module +return sandbox_core_base_thread + diff --git a/xmake/core/sandbox/modules/import/core/sandbox/module.lua b/xmake/core/sandbox/modules/import/core/sandbox/module.lua index 7168cbffe..3a50e862b 100644 --- a/xmake/core/sandbox/modules/import/core/sandbox/module.lua +++ b/xmake/core/sandbox/modules/import/core/sandbox/module.lua @@ -619,14 +619,8 @@ end -- @note the polymiorphism is not supported for import.inherit mode now. -- function core_sandbox_module.inherit(name, opt) - - -- init opt opt = opt or {} - - -- mark as inherit opt.inherit = true - - -- import and inherit it return core_sandbox_module.import(name, opt) end |
