aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorame <[email protected]>2025-06-20 20:34:18 -0500
committerame <[email protected]>2025-06-20 20:34:18 -0500
commit76495ea9809c256ebc216e7aa2954c4e0592fd1d (patch)
tree4f6b08a23632659199ebcb16b198ecf0ede1f5d7
parente058a29d70dd299b7fc2a84cae5824fd03fbef84 (diff)
thread.mutex
-rw-r--r--library/lullaby/thread.lua22
-rw-r--r--src/thread.c59
-rw-r--r--src/thread.h2
-rw-r--r--src/util.h2
-rw-r--r--tests/mutex.lua23
5 files changed, 107 insertions, 1 deletions
diff --git a/library/lullaby/thread.lua b/library/lullaby/thread.lua
index 1b0e89d..d4efe2d 100644
--- a/library/lullaby/thread.lua
+++ b/library/lullaby/thread.lua
@@ -64,4 +64,26 @@ function thread.unlock(tid) end
---@deprecated
function thread.testcopy() end
+---@class mutex-table
+local mutex = {}
+
+---locks the mutex
+---@param T mutex-table
+---@return nil
+function mutex.lock(T) end
+
+---unlocks the mutex
+---@param T mutex-table
+---@return nil
+function mutex.unlock(T) end
+
+---frees the mutex, automatically called by __gc
+---@param T mutex-table
+---@return nil
+function mutex.free(T) end
+
+---returns a mutex object, useful for solving race conditions in multi-threaded environments
+---@return mutex-table
+function thread.mutex() end
+
return thread
diff --git a/src/thread.c b/src/thread.c
index a5eb892..6d4540d 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -85,6 +85,65 @@ int l_tunlock(lua_State* L){
return 0;
}
+int _mutex_lock(lua_State* L){
+ lua_pushstring(L, "_");
+ lua_gettable(L, 1);
+ pthread_mutex_t *lock = lua_touserdata(L, -1);
+
+ pthread_mutex_lock(lock);
+
+ return 0;
+}
+
+int _mutex_unlock(lua_State* L){
+ lua_pushstring(L, "_");
+ lua_gettable(L, 1);
+ pthread_mutex_t *lock = lua_touserdata(L, -1);
+
+ pthread_mutex_unlock(lock);
+
+ return 0;
+}
+
+int _mutex_free(lua_State* L){
+ lua_pushstring(L, "_");
+ lua_gettable(L, 1);
+ pthread_mutex_t *lock = lua_touserdata(L, -1);
+
+ if(lock != NULL){
+ pthread_mutex_destroy(&*lock);
+ free(lock);
+
+ luaI_tsetlud(L, 1, "_", NULL);
+ }
+
+ return 0;
+}
+
+int l_mutex(lua_State* L){
+ pthread_mutex_t *lock = malloc(sizeof * lock);
+
+ if(pthread_mutex_init(&*lock, NULL) != 0)
+ luaI_error(L, -1, "mutex init failed");
+
+ lua_newtable(L);
+ int idx = lua_gettop(L);
+ luaI_tsetlud(L, idx, "_", lock);
+ luaI_tsetcf(L, idx, "lock", _mutex_lock);
+ luaI_tsetcf(L, idx, "unlock", _mutex_unlock);
+ luaI_tsetcf(L, idx, "free", _mutex_free);
+
+ lua_newtable(L);
+ int midx = lua_gettop(L);
+ luaI_tsetcf(L, midx, "__gc", _mutex_free);
+
+ lua_pushvalue(L, midx);
+ lua_setmetatable(L, idx);
+ lua_pushvalue(L, idx);
+
+ return 1;
+}
+
int l_res(lua_State* L){
int return_count = lua_gettop(L) - 1;
lua_pushstring(L, "_");
diff --git a/src/thread.h b/src/thread.h
index be9cadd..0b3a27d 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -6,6 +6,7 @@ int l_tlock(lua_State*);
int l_tunlock(lua_State*);
int l_buffer(lua_State*);
int l_testcopy(lua_State*);
+int l_mutex(lua_State*);
void lib_thread_clean();
@@ -17,6 +18,7 @@ static const luaL_Reg thread_function_list [] = {
{"unlock",l_tunlock},
{"buffer",l_buffer},
{"testcopy",l_testcopy},
+ {"mutex", l_mutex},
{NULL,NULL}
};
diff --git a/src/util.h b/src/util.h
index 62cf80d..99f127c 100644
--- a/src/util.h
+++ b/src/util.h
@@ -38,4 +38,4 @@ void _p_fatal(const char*, int, const char*, const char*);
void p_error(const char*);
char* strnstr(const char*, const char*, size_t);
-#endif //__UTIL_H \ No newline at end of file
+#endif //__UTIL_H
diff --git a/tests/mutex.lua b/tests/mutex.lua
new file mode 100644
index 0000000..2e5ce4b
--- /dev/null
+++ b/tests/mutex.lua
@@ -0,0 +1,23 @@
+local llby = require"lullaby"
+
+
+local mutex = llby.thread.mutex()
+
+llby.io.print_meta = 1
+llby.io.pprint(mutex)
+
+local th = llby.thread.async(function(res)
+ mutex:lock()
+ os.execute("sleep 5")
+ print("thread")
+ mutex:unlock()
+end)
+
+os.execute("sleep 1")
+mutex:lock()
+print("main")
+mutex:unlock()
+mutex:free()
+--
+th:await()
+