diff options
| author | ruki <[email protected]> | 2025-08-27 23:27:52 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2025-08-28 11:35:54 +0800 |
| commit | 46dd9ecf582e7d30d5ce7eb18f248506f85bbe21 (patch) | |
| tree | cc8481903ed576f0d2b38db7f89f55db25706050 /xmake/core/base/thread.lua | |
| parent | 6809e2d887d3f3f298b4e324a7580c55ac47562d (diff) | |
add mutex to thread
Diffstat (limited to 'xmake/core/base/thread.lua')
| -rw-r--r-- | xmake/core/base/thread.lua | 183 |
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 |
