summaryrefslogtreecommitdiff
path: root/xmake/core/base
diff options
context:
space:
mode:
authorruki <[email protected]>2025-08-27 23:27:52 +0800
committerruki <[email protected]>2025-08-28 11:35:54 +0800
commit46dd9ecf582e7d30d5ce7eb18f248506f85bbe21 (patch)
treecc8481903ed576f0d2b38db7f89f55db25706050 /xmake/core/base
parent6809e2d887d3f3f298b4e324a7580c55ac47562d (diff)
add mutex to thread
Diffstat (limited to 'xmake/core/base')
-rw-r--r--xmake/core/base/thread.lua183
1 files changed, 163 insertions, 20 deletions
diff --git a/xmake/core/base/thread.lua b/xmake/core/base/thread.lua
index bdf1c0380..413bdb422 100644
--- a/xmake/core/base/thread.lua
+++ b/xmake/core/base/thread.lua
@@ -19,8 +19,9 @@
--
-- define module
-local thread = thread or {}
-local _instance = _instance or {}
+local thread = thread or {}
+local _thread = _thread or {}
+local _mutex = _mutex or {}
-- load modules
local io = require("base/io")
@@ -37,55 +38,55 @@ thread.STATUS_SUSPENDED = 3
thread.STATUS_DEAD = 4
-- new a thread
-function _instance.new(callback, opt)
+function _thread.new(callback, opt)
opt = opt or {}
- local instance = table.inherit(_instance)
+ 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, _instance)
+ setmetatable(instance, _thread)
return instance
end
-- get thread name
-function _instance:name()
+function _thread:name()
return self._NAME
end
-- get cdata of thread
-function _instance:cdata()
+function _thread:cdata()
return self._HANLDE
end
-- get thread status
-function _instance:status()
+function _thread:status()
return self._STATUS
end
-- is ready?
-function _instance:is_ready()
+function _thread:is_ready()
return self:status() == thread.STATUS_READY
end
-- is running?
-function _instance:is_running()
+function _thread:is_running()
return self:status() == thread.STATUS_RUNNING
end
-- is suspended?
-function _instance:is_suspended()
+function _thread:is_suspended()
return self:status() == thread.STATUS_SUSPENDED
end
-- is dead?
-function _instance:is_dead()
+function _thread:is_dead()
return self:status() == thread.STATUS_DEAD
end
-- start thread
-function _instance:start()
+function _thread:start()
if not self:is_ready() then
return nil, string.format("%s: cannot start non-ready thread!", self)
end
@@ -110,7 +111,7 @@ function _instance:start()
end
-- suspend thread
-function _instance:suspend()
+function _thread:suspend()
if not self:is_running() then
return nil, string.format("%s: cannot suspend non-running thread!", self)
end
@@ -126,7 +127,7 @@ function _instance:suspend()
end
-- resume thread
-function _instance:resume()
+function _thread:resume()
if not self:is_suspended() then
return nil, string.format("%s: cannot suspend non-suspended thread!", self)
end
@@ -142,7 +143,7 @@ function _instance:resume()
end
-- wait thread
-function _instance:wait(timeout)
+function _thread:wait(timeout)
if self:is_dead() then
return 1
elseif self:is_ready() then
@@ -162,7 +163,7 @@ function _instance:wait(timeout)
end
-- tostring(thread)
-function _instance:__tostring()
+function _thread:__tostring()
local status_strs = self._STATUS_STRS
if not status_strs then
status_strs = {
@@ -177,12 +178,144 @@ function _instance:__tostring()
end
-- gc(thread)
-function _instance:__gc()
- if self:cdata() and self:is_dead() and io.thread_exit(self:cdata()) then
+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, lock)
+ local mutex = table.inherit(_mutex)
+ mutex._NAME = name
+ mutex._LOCK = lock
+ 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._LOCK
+end
+
+-- is locked?
+function _mutex:islocked()
+ return self._LOCKED_NUM > 0
+end
+
+-- lock file
+--
+-- @param opt the argument option, {shared = true}
+--
+-- @return ok, errors
+--
+function _mutex:lock(opt)
+
+ -- ensure opened
+ local ok, errors = self:_ensure_opened()
+ if not ok then
+ return false, errors
+ end
+
+ -- lock it
+ if self._LOCKED_NUM > 0 or thread.mutex_lock(self:cdata(), opt) then
+ self._LOCKED_NUM = self._LOCKED_NUM + 1
+ return true
+ else
+ return false, string.format("%s: lock failed!", self)
+ end
+end
+
+-- try to lock file
+--
+-- @param opt the argument option, {shared = true}
+--
+-- @return ok, errors
+--
+function _mutex:trylock(opt)
+
+ -- ensure opened
+ local ok, errors = self:_ensure_opened()
+ if not ok then
+ return false, errors
+ end
+
+ -- try lock it
+ 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 file
+function _mutex:unlock(opt)
+
+ -- ensure opened
+ local ok, errors = self:_ensure_opened()
+ if not ok then
+ return false, errors
+ end
+
+ -- unlock it
+ 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._LOCK = 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._LOCK = nil
+ self._LOCKED_NUM = 0
+ end
+end
+
-- new a thread
--
-- @param callback the thread callback
@@ -194,7 +327,7 @@ function thread.new(callback, opt)
if callback == nil then
return nil, "invalid thread, callback is nil"
end
- return _instance.new(callback, opt)
+ return _thread.new(callback, opt)
end
-- get the running thread name
@@ -259,6 +392,16 @@ function thread._run_thread(callback_str, callinfo_str)
return sandbox.load(sandbox_inst:script(), table.unpack(argv or {}))
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
+
-- return module
return thread