summaryrefslogtreecommitdiff
path: root/indra/newview/scripts/lua/WaitQueue.lua
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/scripts/lua/WaitQueue.lua')
-rw-r--r--indra/newview/scripts/lua/WaitQueue.lua31
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