Skip to content

Commit

Permalink
Merge pull request lunarmodules#25 from Tieske/exit
Browse files Browse the repository at this point in the history
Exit loop when all is done
  • Loading branch information
Tieske committed Mar 5, 2015
2 parents be58265 + 10f0485 commit a76c8a9
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 18 deletions.
9 changes: 8 additions & 1 deletion doc/us/reference.html
Expand Up @@ -84,12 +84,19 @@ <h2>Reference</h2>
registered handlers as long as it uses the Copas socket functions.
</dd>

<dt><strong><code>copas.finished()</code></strong></dt>
<dd>Checks whether anything remains to be done.<br />
Returns <code>false</code> when the sockets lists for reading and writing
are empty and there is no other (sleeping) task to execute.
</dd>

<dt><strong><code>copas.loop(timeout)</code></strong></dt>
<dd>Starts the Copas infinite loop accepting client connections for the
<dd>Starts the Copas loop accepting client connections for the
registered servers and handling those connections with the corresponding
handlers. Every time a server accepts a connection, Copas calls the
associated handler passing the client socket returned by
<code>socket.accept()</code>. The <code>timeout</code> parameter is optional.
The loop returns when <code>copas.finished() == true</code>.
</dd>

<dt><strong><code>copas.removeserver(skt)</code></strong></dt>
Expand Down
51 changes: 34 additions & 17 deletions src/copas/copas.lua
Expand Up @@ -397,7 +397,7 @@ local function _doTick (co, skt, ...)
new_q:push (res, co)
else
if not ok then pcall (_errhandlers [co] or _deferror, res, co, skt) end
if skt and copas.autoclose then skt:close() end
if skt and copas.autoclose then skt:close() end --TODO: should UDP socket be closed???? will close server!, should then also be removed from the _servers and _reading list!
_errhandlers [co] = nil
end
end
Expand Down Expand Up @@ -570,19 +570,26 @@ local function _select (timeout)

if duration(now, last_cleansing) > WATCH_DOG_TIMEOUT then
last_cleansing = now
for k,v in pairs(_reading_log) do
if not r_evs[k] and duration(now, v) > WATCH_DOG_TIMEOUT then
_reading_log[k] = nil
r_evs[#r_evs + 1] = k
r_evs[k] = #r_evs

-- Check all sockets selected for reading, and check how long they have been waiting
-- for data already, without select returning them as readable
for skt,time in pairs(_reading_log) do
if not r_evs[skt] and duration(now, time) > WATCH_DOG_TIMEOUT then
-- This one timedout while waiting to become readable, so move
-- it in the readable list and try and read anyway, despite not
-- having been returned by select
_reading_log[skt] = nil
r_evs[#r_evs + 1] = skt
r_evs[skt] = #r_evs
end
end

for k,v in pairs(_writing_log) do
if not w_evs[k] and duration(now, v) > WATCH_DOG_TIMEOUT then
_writing_log[k] = nil
w_evs[#w_evs + 1] = k
w_evs[k] = #w_evs
-- Do the same for writing
for skt,time in pairs(_writing_log) do
if not w_evs[skt] and duration(now, time) > WATCH_DOG_TIMEOUT then
_writing_log[skt] = nil
w_evs[#w_evs + 1] = skt
w_evs[skt] = #w_evs
end
end
end
Expand All @@ -608,13 +615,16 @@ function copas.step(timeout)
local nextwait = _sleeping:getnext()
if nextwait then
timeout = timeout and math.min(nextwait, timeout) or nextwait
else
if copas.finished() then
return false
end
end

local err = _select (timeout)
if err == "timeout" then return false end

if err then
error(err)
if err == "timeout" then return false end
return nil, err
end

for tsk in tasks() do
Expand All @@ -625,14 +635,21 @@ function copas.step(timeout)
return true
end

-------------------------------------------------------------------------------
-- Check whether there is something to do.
-- returns false if there are no sockets for read/write nor tasks scheduled
-- (which means Copas is in an empty spin)
-------------------------------------------------------------------------------
function copas.finished()
return not (next(_reading) or next(_writing) or _sleeping:getnext())
end

-------------------------------------------------------------------------------
-- Dispatcher endless loop.
-- Listen to client requests and handles them forever
-------------------------------------------------------------------------------
function copas.loop(timeout)
while true do
copas.step(timeout)
end
while not copas.finished() do copas.step(timeout) end
end

return copas
35 changes: 35 additions & 0 deletions tests/testexit.lua
@@ -0,0 +1,35 @@
-- tests whether the main loop automatically exits when all work is done

local copas = require("copas")
local socket = require("socket")

copas.addthread(function()
local n = 1
while n<=5 do
copas.sleep(0)
print(n)
n=n+1
end
end)

print("Test 1 count to 5... then exit")
copas.loop()
print("Test 1 done")

local server, err = socket.bind("*", 20000)

copas.addserver(server, function(skt)
print(copas.receive(skt))
copas.removeserver(server)
end)

copas.addthread(function()
copas.sleep(1)
local skt, err = socket.connect("localhost", 20000)
print(copas.send(skt, "Hello world!\n"))
end)

print("Test 2 send and receive some... then exit")
copas.loop()
print("Test 2 done")

0 comments on commit a76c8a9

Please sign in to comment.