[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Strange experiences with coroutines while using Copas
- From: Chris Pressey <cpressey@...>
- Date: Sun, 21 Aug 2005 21:43:56 -0700
On Sun, 21 Aug 2005 21:53:44 -0500
Javier Guerra <javier@guerrag.com> wrote:
> On Sunday 21 August 2005 1:56 pm, Chris Pressey wrote:
> > > i don't think so. i've sometimes tried some weird 'coroutines
> > > within coroutines' yielded at several levels with mostly expected
> > > results. for example, in Xavante the main dispatcher is a
> > > coroutine-based iterator.
> >
> > Perhaps I'm confused; I thought the dispatcher in Xavante *was*
> > Copas?
>
> we're missing some good definitions to help the dialogue:
>
> Copas is wha i'd call a "scheduler". [...]
Yes, that's (more or less) what I'd call it too, but it calls itself a
"dispatcher" :) Anyway, I understand what you mean, now.
And I think you were right about there being a deeper problem than
coroutines. Attached is a test case with which I can reliably trigger
weird behaviour in Copas. It's not perfectly minimal, but it should be
pretty straightforward.
eclient.lua opens up a connection with a server, sends it a length on a
line by itself, followed by that many asterisks. It takes two
command-line arguments; the first is how many asterisks to send, the
second is how big of chunks to send them in.
eserver.lua accepts connections from clients, reads the length, then
reads exactly that many bytes and closes the connection.
ecopas.lua is the same as eserver.lua, but implemented using Copas.
Usually, eserver.lua and ecopas.lua behave the same. However, for some
configurations of eclient.lua, ecopas.lua consistently fails with
"ERROR: closed", and for others, it fails only sporadically.
An example of where ecopas.lua consistently fails for me is
lua eclient.lua 80000 80
and one where it sporadically fails for me is
lua eclient.lua 80000 770
I have yet to make eserver.lua fail due to any combination of arguments
to eclient.lua, which supports the theory that the problem is in Copas.
I'm running with the packages I listed in my first post, under FreeBSD
4.11. I've only modified the packages as far as I had to to get them to
build and run (mainly adjusting paths for the benefit of Compat-5.1r4.)
I'd be really interested to know if my test scripts look sane to others,
whether anyone can reproduce these problems in other setups, and whether
or not this indicates a bug in Copas.
Thanks!
-Chris
--dofile("./paths.lua")
--
-- Create a client socket, connect to a server, and send
-- it a bunch of asterisks. How many asterisks, and in
-- batches of how many, are given by the first two
-- command-line parameters, respectively.
--
local socket = require("socket")
local total_length = tonumber(arg[1])
local length = total_length
local total_sent = 0
local chunk_length = tonumber(arg[2] or math.ceil(total_length / 100))
if chunk_length > total_length then
chunk_length = total_length
end
local chunk = string.rep("*", chunk_length)
local skt = assert(socket.connect("127.0.0.1", 7000))
skt:send(tostring(length) .. "\n")
while length > 0 do
if chunk_length > length then
chunk_length = length
chunk = string.rep("*", chunk_length)
end
local sent, err = assert(skt:send(chunk))
if not sent then
error(err)
end
if sent ~= chunk_length then
print(string.format(
"WARNING: chunk_length=%d but sent=%d",
chunk_length, sent
))
end
length = length - sent
total_sent = total_sent + sent
print("total sent", total_sent, "/", total_length)
end
print("sent all ok!")
--dofile("./paths.lua")
--
-- Open a server socket and accept requests. In each request,
-- read a single line which contains the length of the request,
-- then read exactly that many bytes and close the connection.
--
local socket = require("socket")
local listen_skt = socket.bind("127.0.0.1", 7000)
repeat
local skt = listen_skt:accept()
local total_length = tonumber(skt:receive("*l"))
print("Total length:", total_length)
local length = total_length
local total_recv = 0
while length > 0 do
local chunk_size = 8192
if chunk_size > length then
chunk_size = length
end
local chunk, err = skt:receive(chunk_size)
if not chunk then
print("ERROR:", err)
if err ~= "timeout" then
return
end
end
local recv = string.len(chunk)
length = length - recv
total_recv = total_recv + recv
print("total recv'ed", total_recv, "/", total_length)
end
print("recv'ed all ok!")
until false
--dofile("./paths.lua")
--
-- Start a Copas server and accept requests. In each request,
-- read a single line which contains the length of the request,
-- then read exactly that many bytes and close the connection.
--
local copas = require("copas")
local socket = require("socket")
local listen_skt = socket.bind("127.0.0.1", 7000)
copas.addserver(listen_skt, function(skt)
skt = copas.wrap(skt)
local total_length = tonumber(skt:receive("*l"))
print("Total length:", total_length)
local length = total_length
local total_recv = 0
while length > 0 do
local chunk_size = 8192
if chunk_size > length then
chunk_size = length
end
local chunk, err = skt:receive(chunk_size)
if not chunk then
print("ERROR:", err)
if err ~= "timeout" then
return
end
end
local recv = string.len(chunk)
length = length - recv
total_recv = total_recv + recv
print("total recv'ed", total_recv, "/", total_length)
end
print("recv'ed all ok!")
end)
copas.loop()