lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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()