This repository has been archived on 2019-08-24. You can view files and clone it, but cannot push or open issues or pull requests.
asyncio/locks.lua

111 lines
2.6 KiB
Lua

--
-- asyncio synchronisation primitives.
--
--
-- Locks
--
-- Store lock metadata locally
local lock_states = {}
local lock_callbacks = {}
setmetatable(lock_states, {__mode = 'kv'})
setmetatable(lock_callbacks, {__mode = 'k'})
-- Create the functions
-- https://docs.python.org/3/library/asyncio-sync.html#lock
local lock = {}
function lock:acquire()
if not asyncio.running then
error('lock:acquire() called outside of a coroutine.')
elseif not lock_callbacks[self] then
lock_callbacks[self] = {}
end
if lock_states[self] then
asyncio.await(table.insert(lock_callbacks[self], asyncio.resume))
elseif #lock_callbacks[self] > 0 then
table.remove(lock_callbacks[self], 1)()
asyncio.await(table.insert(lock_callbacks[self], asyncio.resume))
end
lock_states[self] = coroutine.running()
end
function lock:release()
if not lock_states[self] then error('Lock is not acquired.', 2) end
lock_states[self] = nil
-- lock_callbacks[self] should never be nil.
assert(lock_callbacks[self])
-- Call the next function.
local func = table.remove(lock_callbacks[self], 1)
if func then func() end
end
function lock:locked()
return lock_states[self] and true or false
end
function asyncio.Lock()
return {
acquire = lock.acquire,
release = lock.release,
locked = lock.locked,
}
end
--
-- Events
--
local event_callbacks = {}
setmetatable(event_callbacks, {__mode = 'k'})
local event = {}
function event:wait()
if not asyncio.running then
error('event:wait() called outside of a coroutine.')
elseif event_callbacks[self] then
asyncio.await(table.insert(event_callbacks[self], asyncio.resume))
end
return true
end
-- Automatically defer execution when running event:set()
async function event:set()
local funcs = event_callbacks[self]
event_callbacks[self] = nil
if not funcs then return end
async for _, func in asyncio.ipairs(funcs) do
-- If event:set() is re-called, re-add any unhandled coroutines.
if event_callbacks[self] then
table.insert(event_callbacks[self], 1, func)
else
func()
end
end
end
function event:clear()
if not event_callbacks[self] then event_callbacks[self] = {} end
end
function event:is_set()
return not event_callbacks[self]
end
function asyncio.Event()
local res = {
wait = event.wait,
set = event.set,
clear = event.clear,
is_set = event.is_set,
}
event_callbacks[res] = {}
return res
end