From 14a60e7ea085792d7784b3bd4fe3d5c64c4086dc Mon Sep 17 00:00:00 2001
From: Thijs Schreijer History
copas.gettime()
, which transparently maps to either LuaSockets or
LuaSystems implementation, ensuring independence of the availability of either one of those.copas.exit()
, copas.exiting()
, and
+ copas.waitforexit()
.Getting started examples
end
-copas.addserver(server_socket, copas.handler(connection_handler,
- ssl_params), "my_TCP_server")
+copas.addthread(function()
+ copas.addserver(server_socket, copas.handler(connection_handler,
+ ssl_params), "my_TCP_server")
+ copas.waitforexit()
+ copas.removeserver(server_socket)
+end)
copas()
@@ -180,6 +184,29 @@ Copas dispatcher main functions
truthy.
copas.exit()
Sets a flag that the application is intending to exit. After calling
+ this function copas.exiting()
will be returning true
, and
+ all threads blocked on copas.waitforexit()
will be released.
Copas itself will call this function when copas.finished()
returns
+ true
.
bool = copas.exiting()
Returns a flag indicating whether the application is supposed to exit.
+ Returns false
until after copas.exit()
has been called,
+ after which it will start returning true
.
Clients should check whether they are to cease their operation and exit. They
+ can do this by checking this flag, or by registering a task waiting on
+ copas.waitforexit()
. Clients should cancel pending work and close sockets
+ when an exit is announced, otherwise Copas will not exit.
+
bool = copas.finished()
Checks whether anything remains to be done.
@@ -304,6 +331,15 @@copas.waitforexit()
This will block the calling coroutine until the copas.exit()
function
+ is called. Clients should check whether they are to cease their operation and exit. They
+ can do this by waiting on this call, or by checking the copas.exiting()
flag.
+ Clients should cancel pending work and close sockets when an exit is announced, otherwise
+ Copas will not exit.
skt = copas.wrap(skt [, sslparams] )
Wraps a LuaSocket socket and returns a Copas socket that implements LuaSocket's API diff --git a/src/copas.lua b/src/copas.lua index 19a195c..77699d3 100644 --- a/src/copas.lua +++ b/src/copas.lua @@ -1666,6 +1666,38 @@ function copas.finished() return #_reading == 0 and #_writing == 0 and _resumable:done() and _sleeping:done(copas.gettimeouts()) end + +local resetexit do + local exit_semaphore, exiting + + function resetexit() + exit_semaphore = copas.semaphore.new(1, 0, math.huge) + exiting = false + end + + -- Signals tasks to exit. But only if they check for it. By calling `copas.exiting` + -- they can check if they should exit. Or by calling `copas.waitforexit` they can + -- wait until the exit signal is given. + function copas.exit() + if exiting then return end + exiting = true + exit_semaphore:destroy() + end + + -- returns whether Copas is in the process of exiting. Exit can be started by + -- calling `copas.exit()`. + function copas.exiting() + return exiting + end + + -- Pauses the current coroutine until Copas is exiting. To be used as an exit + -- signal for tasks that need to clean up before exiting. + function copas.waitforexit() + exit_semaphore:take(1) + end +end + + local _getstats do local _getstats_instrumented, _getstats_plain @@ -1756,8 +1788,17 @@ function copas.loop(initializer, timeout) timeout = initializer or timeout end + resetexit() copas.running = true - while not copas.finished() do copas.step(timeout) end + while true do + copas.step(timeout) + if copas.finished() then + if copas.exiting() then + break + end + copas.exit() + end + end copas.running = false end diff --git a/tests/exittest.lua b/tests/exittest.lua index 5d4ad67..c8850be 100644 --- a/tests/exittest.lua +++ b/tests/exittest.lua @@ -72,3 +72,46 @@ copas.loop() assert(testran == 6, "Test 6 was not executed!") print("6) success") +print("7) Testing exiting releasing the exitsemaphore (implicit, no call to copas.exit)") +copas.addthread(function() + print("","7 running...") + copas.addthread(function() + copas.waitforexit() + testran = 7 + end) +end) +copas.loop() +assert(testran == 7, "Test 7 was not executed!") +print("7) success") + +print("8) Testing schduling new tasks while exiting (explicit exit by calling copas.exit)") +testran = 0 +copas.addthread(function() + print("","8 running...") + copas.addthread(function() + while true do + copas.pause(0.1) + testran = testran + 1 + print("count...") + if testran == 3 then -- testran == 3 + print("initiating exit...") + copas.exit() + break + end + end + end) + copas.addthread(function() + copas.waitforexit() + print("exit signal received...") + testran = testran + 1 -- testran == 4 + copas.addthread(function() + print("running new task from exit handler...") + copas.pause(1) + testran = testran + 1 -- testran == 5 + print("new task from exit handler done!") + end) + end) +end) +copas.loop() +assert(testran == 5, "Test 8 was not executed!") +print("8) success")