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 | |
| parent | 6809e2d887d3f3f298b4e324a7580c55ac47562d (diff) | |
add mutex to thread
Diffstat (limited to 'xmake')
| -rw-r--r-- | xmake/core/base/thread.lua | 183 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/base/thread.lua | 47 |
2 files changed, 210 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 diff --git a/xmake/core/sandbox/modules/import/core/base/thread.lua b/xmake/core/sandbox/modules/import/core/base/thread.lua index f56466ddf..3c4bfa6d5 100644 --- a/xmake/core/sandbox/modules/import/core/base/thread.lua +++ b/xmake/core/sandbox/modules/import/core/base/thread.lua @@ -27,6 +27,7 @@ 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 {} -- export the thread status sandbox_core_base_thread.STATUS_READY = thread.STATUS_READY @@ -84,6 +85,30 @@ function sandbox_core_base_thread_instance.wait(instance, timeout) 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 + -- new thread function sandbox_core_base_thread.new(callback, opt) local instance, errors = thread.new(callback, opt) @@ -117,6 +142,28 @@ function sandbox_core_base_thread.running() 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 + + -- return module return sandbox_core_base_thread |
