Skip to content

Commit

Permalink
Merge pull request #9 from moonlibs/fix-timeout-0
Browse files Browse the repository at this point in the history
fix: sync/cond and sync/pool do not yield with timeout=0
  • Loading branch information
ochaton authored Mar 3, 2024
2 parents 00722df + 4daa701 commit eb439bd
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 7 deletions.
2 changes: 1 addition & 1 deletion sync.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
local sync = {
_VERSION = '0.11.1',
_VERSION = '0.12.0',
}

sync.cond = require 'sync.cond'
Expand Down
3 changes: 3 additions & 0 deletions sync/cond.lua
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ function cond:recv(timeout)
if not self.lock then
self.lock = fiber.cond()
end
if timeout == 0 then
return nil, "Timed out"
end
self.lock:wait(timeout or self.timeout)
self.lock = nil
if self.sent then
Expand Down
15 changes: 10 additions & 5 deletions sync/pool.lua
Original file line number Diff line number Diff line change
Expand Up @@ -362,11 +362,16 @@ function pool:send(func, args, opts)

self.wg:start()

while not self.terminate_cb:recv(0) and fiber.time() < deadline do
fiber.testcancel()
if self.chan:put(task, math.min(1, deadline - fiber.time())) then
task.published_at = fiber.time()
break
if fiber.time() <= deadline then
while not self.terminate_cb:recv(0) do
fiber.testcancel()
if self.chan:put(task, math.min(1, math.max(0, deadline - fiber.time()))) then
task.published_at = fiber.time()
break
end
if fiber.time() >= deadline then
break
end
end
end

Expand Down
20 changes: 20 additions & 0 deletions test/01-cond.test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,24 @@ test:deadline(function()

end, 3, 'recv -> send works')

test:deadline(function()
local cond = sync.cond()
local value = math.random()

test:noyield(function()
local no_val, err = cond:recv(0)
test:is(no_val, nil, 'empty cond returns no value')
test:is(err, 'Timed out', 'error message is timed out')
end)

cond:send(value)

test:noyield(function()
local recv, err = cond:recv(0)
test:is(recv, value, 'value received')
test:is(err, nil, 'no error returned')
end)

end, 1, 'recv noyields when timeout=0')

test:done_testing()
35 changes: 34 additions & 1 deletion test/05-pool.test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ test:deadline(function()
print("pool:send returned")

local ft2 = fiber.time()
test:ok(ft2 > ft1, "send yields fiber")
test:is(ft2, ft1, "send does not yield fiber when worker is available")
test:ok(not t1_done, 'task still wasnt processed')

test:ok(not pool:wait(0), 'pool has accepted given task')
Expand Down Expand Up @@ -353,4 +353,37 @@ test:deadline(function()
test:is(waited, 0, "task:wait on cancelled task must return instantly")
end, 1, "task autocancelled when wait_timeout is too low")

test:deadline(function()
local pool = sync.pool.new('pool', 1)

local executed
local task, err

test:noyield(function()
task, err = pool:send(function() executed = true end, {},
{ async = true, wait_timeout = 0 })
test:is(err, nil, "pool with one worker raises no error on send{wait_timeout=0}")
end)

---@cast task sync.pool.task
task:wait()
test:is(executed, true, "task was successfully executed")

-- pool still has free slot
test:noyield(function ()
task, err = pool:send(function() fiber.yield() executed = true end, {},
{ async = true, wait_timeout = 0 })

test:is(err, nil, "pool with one worker raises no error on send{wait_timeout=0}")

task, err = pool:send(function() executed = true end, {},
{ async = true, wait_timeout = 0 })

test:is(err, pool.errors.TASK_WAS_NOT_SCHEDULED, "second task was not scheduled")
end)

pool:terminate()
pool:wait()
end, 1, "pool:send allows put with timeout=0")

test:done_testing()

0 comments on commit eb439bd

Please sign in to comment.