Skip to content

Commit

Permalink
feat(pause) replace sleep with pause and pauseforever (#148)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tieske authored Oct 14, 2022
1 parent ef5805d commit 9d6fffa
Show file tree
Hide file tree
Showing 24 changed files with 93 additions and 63 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ test: certs
$(LUA) $(DELIM) $(PKGPATH) tests/largetransfer.lua
$(LUA) $(DELIM) $(PKGPATH) tests/lock.lua
$(LUA) $(DELIM) $(PKGPATH) tests/loop_starter.lua
$(LUA) $(DELIM) $(PKGPATH) tests/pause.lua
$(LUA) $(DELIM) $(PKGPATH) tests/queue.lua
$(LUA) $(DELIM) $(PKGPATH) tests/removeserver.lua
$(LUA) $(DELIM) $(PKGPATH) tests/removethread.lua
$(LUA) $(DELIM) $(PKGPATH) tests/request.lua 'http://www.google.com'
$(LUA) $(DELIM) $(PKGPATH) tests/request.lua 'https://www.google.nl' true
$(LUA) $(DELIM) $(PKGPATH) tests/semaphore.lua
$(LUA) $(DELIM) $(PKGPATH) tests/sleep.lua
$(LUA) $(DELIM) $(PKGPATH) tests/starve.lua
$(LUA) $(DELIM) $(PKGPATH) tests/tcptimeout.lua
$(LUA) $(DELIM) $(PKGPATH) tests/timer.lua
Expand Down
2 changes: 2 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ <h2><a name="history"></a>History</h2>
<li>Fix: an error in the timer callback would kill the timer.</li>
<li>Added: <code>copas.geterrorhandler</code> to retrieve the active errorhandler.</li>
<li>Added: option <code>errorhandler</code> for timer objects.</li>
<li>Added: <code>copas.pause</code> and <code>copas.pauseforever</code> to replace <code>copas.sleep</code>. The latter
method can accidentally sleep-forever if time arithmetic returns a negative result.</li>
<li>Change: renamed <code>copas.setErrorHandler</code> to <code>copas.seterrorhandler</code>.</li>
<li>Change: renamed <code>copas.useSocketTimeoutErrors</code> to <code>copas.usesockettimeouterrors</code>.</li>
</ul></dd>
Expand Down
2 changes: 1 addition & 1 deletion docs/manual.html
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ <h2><a name="synchronization"></a>Synchronization primitives</h2>
end

print("doing something on my own")
copas.sleep() -- allow to yield, while inside the lock
copas.pause() -- allow to yield, while inside the lock
print("after " .. ok .. " seconds waiting")

lock:release()
Expand Down
17 changes: 13 additions & 4 deletions docs/reference.html
Original file line number Diff line number Diff line change
Expand Up @@ -298,14 +298,23 @@ <h3>Non-blocking data exchange and timer/sleep functions</h3>
exchange data with other services.</p>

<dl class="reference">
<dt><strong><code>copas.pause([delay])</code></strong></dt>
<dd>Pauses the current co-routine. Parameter <code>delay</code> (in seconds) is optional
and defaults to 0. If <code>delay &lt= 0</code> then it will pause for 0 seconds.
</dd>

<dt><strong><code>copas.pauseforever()</code></strong></dt>
<dd>Pauses the current co-routine until explicitly woken by a call to
<code>copas.wakeup()</code>.
</dd>

<dt><strong><code>copas.sleep([sleeptime])</code></strong></dt>
<dd>Pauses the current co-routine. Parameter <code>sleeptime</code> (in seconds) is optional
and defaults to 0. If <code>sleeptime &lt 0</code>
then it will sleep until explicitly woken by a call to <code>copas.wakeup()</code>.
<dd><i>Deprecated:</i> use <code>copas.pause</code> and <code>copas.pauseforever</code>
instead.
</dd>

<dt><strong><code>copas.wakeup(co)</code></strong></dt>
<dd><code>co</code> is the coroutine to wakeup, see <code>copas.sleep()</code>.
<dd><code>co</code> is the coroutine to wakeup, see <code>copas.pauseforever()</code>.
</dd>

<dt><strong><code>sock:close()</code></strong></dt>
Expand Down
33 changes: 26 additions & 7 deletions src/copas.lua
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ function copas.receive(client, pattern, part)

-- guarantees that high throughput doesn't take other threads to starvation
if (math.random(100) > 90) then
copas.sleep(0)
copas.pause()
end

if s then
Expand Down Expand Up @@ -541,7 +541,7 @@ function copas.receivefrom(client, size)

-- garantees that high throughput doesn't take other threads to starvation
if (math.random(100) > 90) then
copas.sleep(0)
copas.pause()
end

if s then
Expand Down Expand Up @@ -578,7 +578,7 @@ function copas.receivepartial(client, pattern, part)

-- guarantees that high throughput doesn't take other threads to starvation
if (math.random(100) > 90) then
copas.sleep(0)
copas.pause()
end

if s or (type(part) == "string" and #part > orig_size) then
Expand Down Expand Up @@ -626,7 +626,7 @@ function copas.send(client, data, from, to)

-- guarantees that high throughput doesn't take other threads to starvation
if (math.random(100) > 90) then
copas.sleep(0)
copas.pause()
end

if s then
Expand Down Expand Up @@ -1198,7 +1198,7 @@ function copas.addnamedthread(name, handler, ...)
-- create a coroutine that skips the first argument, which is always the socket
-- passed by the scheduler, but `nil` in case of a task/thread
local thread = coroutine_create(function(_, ...)
copas.sleep(0)
copas.pause()
return handler(...)
end)
if name then
Expand Down Expand Up @@ -1230,10 +1230,29 @@ end

-- yields the current coroutine and wakes it after 'sleeptime' seconds.
-- If sleeptime < 0 then it sleeps until explicitly woken up using 'wakeup'
-- TODO: deprecated, remove in next major
function copas.sleep(sleeptime)
coroutine_yield((sleeptime or 0), _sleeping)
end


-- yields the current coroutine and wakes it after 'sleeptime' seconds.
-- if sleeptime < 0 then it sleeps 0 seconds.
function copas.pause(sleeptime)
if sleeptime and sleeptime > 0 then
coroutine_yield(sleeptime, _sleeping)
else
coroutine_yield(0, _sleeping)
end
end


-- yields the current coroutine until explicitly woken up using 'wakeup'
function copas.pauseforever()
coroutine_yield(-1, _sleeping)
end


-- Wakes up a sleeping coroutine 'co'.
function copas.wakeup(co)
_sleeping:wakeup(co)
Expand All @@ -1258,7 +1277,7 @@ do

time_out_thread = copas.addnamedthread("copas_core_timer", function()
while true do
copas.sleep(TIMEOUT_PRECISION)
copas.pause(TIMEOUT_PRECISION)
timerwheel:step()
end
end)
Expand Down Expand Up @@ -1358,7 +1377,7 @@ local _sleeping_task = {} do
local co = _sleeping:pop(now)
while co do
-- we're pushing them to _resumable, since that list will be replaced before
-- executing. This prevents tasks running twice in a row with sleep(0) for example.
-- executing. This prevents tasks running twice in a row with pause(0) for example.
-- So here we won't execute, but at _resumable step which is next
_resumable:push(co)
co = _sleeping:pop(now)
Expand Down
2 changes: 1 addition & 1 deletion src/copas/lock.lua
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ function lock:get(timeout)
copas.timeout(timeout, timeout_handler)

start_time = gettime()
copas.sleep(-1)
copas.pauseforever()

local err = self.errors[co]
self.errors[co] = nil
Expand Down
2 changes: 1 addition & 1 deletion src/copas/semaphore.lua
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ function semaphore:take(requested, timeout)
}
self.q_tail = self.q_tail + 1

copas.sleep(-1) -- block until woken
copas.pauseforever() -- block until woken
if self.to_flags[co] then
-- a timeout happened
self.to_flags[co] = nil
Expand Down
4 changes: 2 additions & 2 deletions src/copas/timer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ do
if self.errorhandler then
copas.seterrorhandler(self.errorhandler)
end
copas.sleep(initial_delay)
copas.pause(initial_delay)
while true do
if not self.cancelled then
if not self.recurring then
Expand All @@ -52,7 +52,7 @@ do
return
end

copas.sleep(self.delay)
copas.pause(self.delay)
end
end

Expand Down
4 changes: 2 additions & 2 deletions tests/close.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ copas.loop(function()
copas.addserver(server, copas.handler(function(conn_skt)
-- client connected, we're not doing anything, let the client
-- wait in the read/write queues
copas.sleep(2)
copas.pause(2)
-- now we're closing the connecting_socket
close_time = socket.gettime()
print("closing client socket now, client receive and send operation should immediately error out now")
client_socket:close()

copas.sleep(10)
copas.pause(10)
conn_skt:close()
copas.removeserver(server)
print "timeout, test failed"
Expand Down
6 changes: 3 additions & 3 deletions tests/errhandlers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ if _VERSION ~= "Lua 5.1" then
end
f()
end)
copas.sleep(1)
copas.pause(1)
end)

print = old_print --luacheck: ignore
Expand All @@ -83,7 +83,7 @@ tests.yielding_from_user_code_fails = function()
end

copas.loop(function()
copas.sleep(1)
copas.pause(1)
coroutine.yield() -- directly yield to Copas
end)

Expand Down Expand Up @@ -137,7 +137,7 @@ tests.timerwheel_callbacks_call_the_default_error_handler = function()
copas.setErrorHandler(function() call_count = call_count - 10 end, true)
copas.loop(function()
copas.timeout(0.01, function(co) error("hi there!") end)
copas.sleep(1)
copas.pause(1)
end)

assert(call_count == -10, "expected callcount -10, got: " .. tostring(call_count))
Expand Down
4 changes: 2 additions & 2 deletions tests/exit.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ local done = false

copas.addthread(function()
for i = 1, 5 do
copas.sleep(0)
copas.pause()
print(i)
end

Expand Down Expand Up @@ -43,7 +43,7 @@ copas.addserver(server, function(skt)
end)

copas.addthread(function()
copas.sleep(1)
copas.pause(1)
local skt = socket.connect("localhost", 20000)
print("Sending "..message.."\\n")
local bytes = copas.send(skt, message.."\n")
Expand Down
16 changes: 8 additions & 8 deletions tests/exittest.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ print("1) success")

print("2) Testing exiting when a task finishes within the loop")
copas.addthread(function()
copas.sleep(0.1) -- wait until loop is running
copas.sleep(0.1) -- wait again to make sure its not the initial step in the loop
copas.pause(0.1) -- wait until loop is running
copas.pause(0.1) -- wait again to make sure its not the initial step in the loop
print("","2 running...")
testran = 2
end)
Expand All @@ -40,8 +40,8 @@ print("3) success")

print("4) Testing exiting when a task fails in the loop")
copas.addthread(function()
copas.sleep(0.1) -- wait until loop is running
copas.sleep(0.1) -- wait again to make sure its not the initial step in the loop
copas.pause(0.1) -- wait until loop is running
copas.pause(0.1) -- wait again to make sure its not the initial step in the loop
print("","4 running...")
testran = 4
error("error on purpose")
Expand All @@ -54,19 +54,19 @@ print("5) Testing exiting when a task permanently sleeps before the loop")
copas.addthread(function()
print("","5 running...")
testran = 5
copas.sleep(-1) -- sleep until explicitly woken up
copas.pauseforever() -- sleep until explicitly woken up
end)
copas.loop()
assert(testran == 5, "Test 5 was not executed!")
print("5) success")

print("6) Testing exiting when a task permanently sleeps in the loop")
copas.addthread(function()
copas.sleep(0.1) -- wait until loop is running
copas.sleep(0.1) -- wait again to make sure its not the initial step in the loop
copas.pause(0.1) -- wait until loop is running
copas.pause(0.1) -- wait again to make sure its not the initial step in the loop
print("","6 running...")
testran = 6
copas.sleep(-1) -- sleep until explicitly woken up
copas.pauseforever() -- sleep until explicitly woken up
end)
copas.loop()
assert(testran == 6, "Test 6 was not executed!")
Expand Down
16 changes: 8 additions & 8 deletions tests/http-timeout.lua
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ local function runtest()
os.exit(1)
end
-- we timeout on the request, so sleep here and exit
copas.sleep(timeout + 1) -- sleep 1 second more than the requester timeout, to force a timeout on the request
copas.pause(timeout + 1) -- sleep 1 second more than the requester timeout, to force a timeout on the request
print("Server reading port 49500: request-timeout complete")
return skt:close()
end
Expand Down Expand Up @@ -105,7 +105,7 @@ local function runtest()
os.exit(1)
end

copas.sleep(timeout + 1) -- sleep 1 second more than the requester timeout, to force a timeout on the response
copas.pause(timeout + 1) -- sleep 1 second more than the requester timeout, to force a timeout on the response
print("Server reading port 49500: response-timeout complete")
return skt:close()
end))
Expand All @@ -115,7 +115,7 @@ local function runtest()
copas.addnamedthread("test request", function()

print "Waiting a bit for server to start..."
copas.sleep(1) -- give server some time to start
copas.pause(1) -- give server some time to start

do
print("first test: succesfull round trip")
Expand Down Expand Up @@ -152,7 +152,7 @@ local function runtest()

-- cleanup; sleep 2 secs to wait for closing server socket
-- to ensure any error messages do not get intermixed with the next tests output
copas.sleep(2)
copas.pause(2)
print(("="):rep(80))
end

Expand Down Expand Up @@ -192,7 +192,7 @@ local function runtest()

-- cleanup; sleep 2 secs to wait for closing server socket
-- to ensure any error messages do not get intermixed with the next tests output
copas.sleep(2)
copas.pause(2)
print(("="):rep(80))
end

Expand Down Expand Up @@ -232,7 +232,7 @@ local function runtest()

-- cleanup; sleep 2 secs to wait for closing server socket
-- to ensure any error messages do not get intermixed with the next tests output
copas.sleep(2)
copas.pause(2)
print(("="):rep(80))
end

Expand Down Expand Up @@ -272,7 +272,7 @@ local function runtest()

-- cleanup; sleep 2 secs to wait for closing server socket
-- to ensure any error messages do not get intermixed with the next tests output
copas.sleep(2)
copas.pause(2)
print(("="):rep(80))
end

Expand Down Expand Up @@ -312,7 +312,7 @@ local function runtest()

-- cleanup; sleep 2 secs to wait for closing server socket
-- to ensure any error messages do not get intermixed with the next tests output
copas.sleep(2)
copas.pause(2)
print(("="):rep(80))
end

Expand Down
2 changes: 1 addition & 1 deletion tests/largetransfer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ local function runtest()
copas.addnamedthread("test timeout thread", function()
local i = 1
while done ~= 4 do
copas.sleep(1)
copas.pause(1)
print(i, "seconds:", socket.gettime()-start)
i = i + 1
if i > 60 then
Expand Down
Loading

0 comments on commit 9d6fffa

Please sign in to comment.