diff --git a/sync.lua b/sync.lua index 46ff941..07a661b 100644 --- a/sync.lua +++ b/sync.lua @@ -1,5 +1,5 @@ local sync = { - _VERSION = '0.11.1', + _VERSION = '0.12.0', } sync.cond = require 'sync.cond' diff --git a/sync/cond.lua b/sync/cond.lua index 5c3120b..9eb058d 100644 --- a/sync/cond.lua +++ b/sync/cond.lua @@ -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 diff --git a/sync/pool.lua b/sync/pool.lua index d50874b..08950ab 100644 --- a/sync/pool.lua +++ b/sync/pool.lua @@ -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 diff --git a/test/01-cond.test.lua b/test/01-cond.test.lua index 5dcb21a..6855982 100644 --- a/test/01-cond.test.lua +++ b/test/01-cond.test.lua @@ -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() \ No newline at end of file diff --git a/test/05-pool.test.lua b/test/05-pool.test.lua index 74528f8..4adbf17 100644 --- a/test/05-pool.test.lua +++ b/test/05-pool.test.lua @@ -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') @@ -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()