summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2025-09-02 10:16:24 +0800
committerGitHub <[email protected]>2025-09-02 10:16:24 +0800
commit148501afafa5e9e05da7a54bc804880d6c415849 (patch)
treef5cbcee2b05d4b836478a45698c8a42b43ea38b7
parent90b7015682c5523dfa252ebfbab6ed16b3e4b16a (diff)
parent37a499eeb5fd84be4ac83d639211e18e55dccd32 (diff)
Merge pull request #6324 from xmake-io/thread
Add native thread support
m---------core/src/tbox/tbox0
-rw-r--r--core/src/xmake/engine.c161
-rw-r--r--core/src/xmake/engine.h26
-rw-r--r--core/src/xmake/engine_pool.c107
-rw-r--r--core/src/xmake/engine_pool.h82
-rw-r--r--core/src/xmake/io/pipe_close.c4
-rw-r--r--core/src/xmake/io/pipe_read.c4
-rw-r--r--core/src/xmake/io/pipe_wait.c4
-rw-r--r--core/src/xmake/io/pipe_write.c4
-rw-r--r--core/src/xmake/io/poller.c34
-rw-r--r--core/src/xmake/io/poller.h14
-rw-r--r--core/src/xmake/io/poller_insert.c2
-rw-r--r--core/src/xmake/io/poller_modify.c2
-rw-r--r--core/src/xmake/io/poller_remove.c2
-rw-r--r--core/src/xmake/io/poller_spank.c2
-rw-r--r--core/src/xmake/io/poller_support.c2
-rw-r--r--core/src/xmake/io/poller_wait.c55
-rw-r--r--core/src/xmake/io/prefix.h15
-rw-r--r--core/src/xmake/io/socket_close.c2
-rw-r--r--core/src/xmake/thread/event_exit.c55
-rw-r--r--core/src/xmake/thread/event_incref.c46
-rw-r--r--core/src/xmake/thread/event_init.c70
-rw-r--r--core/src/xmake/thread/event_post.c46
-rw-r--r--core/src/xmake/thread/event_wait.c47
-rw-r--r--core/src/xmake/thread/mutex_exit.c55
-rw-r--r--core/src/xmake/thread/mutex_incref.c46
-rw-r--r--core/src/xmake/thread/mutex_init.c70
-rw-r--r--core/src/xmake/thread/mutex_lock.c46
-rw-r--r--core/src/xmake/thread/mutex_trylock.c46
-rw-r--r--core/src/xmake/thread/mutex_unlock.c46
-rw-r--r--core/src/xmake/thread/prefix.h156
-rw-r--r--core/src/xmake/thread/queue_clear.c47
-rw-r--r--core/src/xmake/thread/queue_exit.c55
-rw-r--r--core/src/xmake/thread/queue_incref.c46
-rw-r--r--core/src/xmake/thread/queue_init.c87
-rw-r--r--core/src/xmake/thread/queue_pop.c92
-rw-r--r--core/src/xmake/thread/queue_push.c96
-rw-r--r--core/src/xmake/thread/queue_size.c46
-rw-r--r--core/src/xmake/thread/semaphore_exit.c55
-rw-r--r--core/src/xmake/thread/semaphore_incref.c46
-rw-r--r--core/src/xmake/thread/semaphore_init.c72
-rw-r--r--core/src/xmake/thread/semaphore_post.c47
-rw-r--r--core/src/xmake/thread/semaphore_wait.c47
-rw-r--r--core/src/xmake/thread/sharedata_clear.c48
-rw-r--r--core/src/xmake/thread/sharedata_exit.c51
-rw-r--r--core/src/xmake/thread/sharedata_get.c82
-rw-r--r--core/src/xmake/thread/sharedata_incref.c46
-rw-r--r--core/src/xmake/thread/sharedata_init.c66
-rw-r--r--core/src/xmake/thread/sharedata_set.c84
-rw-r--r--core/src/xmake/thread/thread_exit.c64
-rw-r--r--core/src/xmake/thread/thread_init.c146
-rw-r--r--core/src/xmake/thread/thread_resume.c53
-rw-r--r--core/src/xmake/thread/thread_suspend.c53
-rw-r--r--core/src/xmake/thread/thread_wait.c57
-rwxr-xr-xcore/src/xmake/xmake.sh1
-rw-r--r--tests/modules/thread/coroutine.lua32
-rw-r--r--tests/modules/thread/event.lua25
-rw-r--r--tests/modules/thread/mutex.lua24
-rw-r--r--tests/modules/thread/queue.lua28
-rw-r--r--tests/modules/thread/semaphore.lua25
-rw-r--r--tests/modules/thread/sharedata.lua26
-rw-r--r--tests/modules/thread/sleep.lua21
-rw-r--r--xmake/core/_xmake_main.lua2
-rw-r--r--xmake/core/base/compat/env.lua2
-rw-r--r--xmake/core/base/pipe.lua5
-rw-r--r--xmake/core/base/serialize.lua45
-rw-r--r--xmake/core/base/task.lua21
-rw-r--r--xmake/core/base/thread.lua925
-rw-r--r--xmake/core/main.lua44
-rw-r--r--xmake/core/sandbox/modules/coroutine.lua4
-rw-r--r--xmake/core/sandbox/modules/import/core/base/thread.lua394
-rw-r--r--xmake/core/sandbox/modules/import/core/sandbox/module.lua6
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