diff options
Diffstat (limited to 'indra/newview/scripts/lua/WaitQueue.lua')
-rw-r--r-- | indra/newview/scripts/lua/WaitQueue.lua | 31 |
1 files changed, 14 insertions, 17 deletions
diff --git a/indra/newview/scripts/lua/WaitQueue.lua b/indra/newview/scripts/lua/WaitQueue.lua index 00766ccae7..a34dbef4d7 100644 --- a/indra/newview/scripts/lua/WaitQueue.lua +++ b/indra/newview/scripts/lua/WaitQueue.lua @@ -2,8 +2,12 @@ -- the Dequeue() operation blocks the calling coroutine until some other -- coroutine Enqueue()s a new value. +local fiber = require('fiber') local Queue = require('Queue') +-- local debug = print_debug +local function debug(...) end + local WaitQueue = Queue:new() function WaitQueue:new() @@ -32,26 +36,20 @@ function WaitQueue:_wake_waiters() -- cases. With multiple consumers, if more than one is trying to -- Dequeue() from an empty WaitQueue, we'll have multiple waiters. -- Unlike OS threads, with cooperative concurrency it doesn't make sense - -- to "notify all": we need resume only one of the waiting Dequeue() - -- callers. But since resuming that caller might entail either Enqueue() - -- or Dequeue() calls, recheck every time around to see if we must resume - -- another waiting coroutine. - while not self:IsEmpty() and #self._waiters > 0 do + -- to "notify all": we need wake only one of the waiting Dequeue() + -- callers. + if ((not self:IsEmpty()) or self._closed) and next(self._waiters) then -- Pop the oldest waiting coroutine instead of the most recent, for -- more-or-less round robin fairness. But skip any coroutines that -- have gone dead in the meantime. local waiter = table.remove(self._waiters, 1) - while waiter and coroutine.status(waiter) ~= "suspended" do + while waiter and fiber.status(waiter) == "dead" do waiter = table.remove(self._waiters, 1) end -- do we still have at least one waiting coroutine? if waiter then -- don't pass the head item: let the resumed coroutine retrieve it - local ok, message = coroutine.resume(waiter) - -- if resuming that waiter encountered an error, don't swallow it - if not ok then - error(message) - end + fiber.wake(waiter) end end end @@ -62,18 +60,17 @@ function WaitQueue:Dequeue() -- the queue while there are still items left, and we want the -- consumer(s) to retrieve those last few items. if self._closed then + debug('WaitQueue:Dequeue(): closed') return nil end - local coro = coroutine.running() - if coro == nil then - error("WaitQueue:Dequeue() trying to suspend main coroutine") - end + debug('WaitQueue:Dequeue(): waiting') -- add the running coroutine to the list of waiters - table.insert(self._waiters, coro) + table.insert(self._waiters, fiber.running()) -- then let somebody else run - coroutine.yield() + fiber.wait() end -- here we're sure this queue isn't empty + debug('WaitQueue:Dequeue() calling Queue.Dequeue()') return Queue.Dequeue(self) end |