* Completed mostly working version

Mon, 11 Jun 2007 01:08:59 +0000

author
Thomas Harning Jr <harningt@gmail.com>
date
Mon, 11 Jun 2007 01:08:59 +0000
changeset 2
01b3a96ae760
parent 1
31c782cfe7fe
child 3
5999243fab1d

* Completed mostly working version
* Moved to a mode where addevent calls a callback rather than
it being instantiated within.
* If the callback returns -1, then no event is ever setup
* Otherwise the integer value is used to setup the event
* This allows for using coroutine.wrap rather than a cooked-up wrapper
* Tests work, although there are a few remaining issues:
* Need to figure a good way of preserving the event object,
not sure if current method is good enough, since the socket
is the only anchor, and it is only held inside the coro..
circular reference, something that Lua 'handles' well.
* Doing more than the maximum sockets the process is allows
causes strangeness to occur in libevent.. somehow
it is getting around to epoll_add which is causing valgrind
to barf.

luaevent/luaevent.lua file | annotate | diff | comparison | revisions
luaevent/src/luaevent.c file | annotate | diff | comparison | revisions
luaevent/test/test.lua file | annotate | diff | comparison | revisions
luaevent/test/testClient.lua file | annotate | diff | comparison | revisions
--- a/luaevent/luaevent.lua	Sun Jun 10 16:52:55 2007 +0000
+++ b/luaevent/luaevent.lua	Mon Jun 11 01:08:59 2007 +0000
@@ -9,18 +9,10 @@
 local EV_WRITE = luaevent.core.EV_WRITE
 local fair = false
 
--- Weak keys.. the keys are the client sockets
-local clientTable = {} or setmetatable({}, {'__mode', 'k'})
+local hookedObjectMt = false
 
-local function getWrapper()
-	local running = coroutine.running()
-	return function(...)
-		print(coroutine.running(), running)
-		print(debug.traceback())
-		if coroutine.running() == running then return end
-		return select(2, coroutine.resume(running, ...))
-	end
-end
+-- Weak keys.. the keys are the client sockets
+local clientTable = setmetatable({}, {'__mode', 'k'})
 
 function send(sock, data, start, stop)
 	local s, err
@@ -35,7 +27,6 @@
 			coroutine.yield(EV_WRITE)
 		end
 		if s or err ~= "timeout" then return s, err, sent end
-		if not clientTable[sock] then clientTable[sock] = luaevent.core.addevent(sock, EV_WRITE, getWrapper()) end
 		coroutine.yield(EV_WRITE)
 	until false
 end
@@ -45,7 +36,6 @@
 	repeat
 		s, err, part = sock:receive(pattern, part)
 		if s or err ~= "timeout" then return s, err, part end
-		if not clientTable[sock] then clientTable[sock] = luaevent.core.addevent(sock, EV_READ, getWrapper()) end
 		coroutine.yield(EV_READ)
 	until false
 end
@@ -58,7 +48,6 @@
 	s, err, part = client:receive(pattern)
 	if s or ( (type(pattern)=="number") and part~="" and part ~=nil ) or 
 		err ~= "timeout" then return s, err, part end
-		if not clientTable[sock] then clientTable[sock] = luaevent.core.addevent(sock, EV_READ, getWrapper()) end
 		coroutine.yield(EV_READ)
 	until false
 end
@@ -66,7 +55,6 @@
 	sock:settimeout(0)
 	local ret, err = sock:connect(...)
 	if ret or err ~= "timeout" then return ret, err end
-	if not clientTable[sock] then clientTable[sock] = luaevent.core.addevent(sock, EV_WRITE, getWrapper()) end
 	coroutine.yield(EV_WRITE)
 	ret, err = sock:connect(...)
 	if err == "already connected" then
@@ -81,28 +69,44 @@
 	-- Figure out what to do ......
 	return handler(sock)
 end
-local function handleClient(co, client, handler)
-	local ok, res, event = coroutine.resume(co, client, handler)
-end
+
 local function serverCoroutine(sock, callback)
-	local listenItem = luaevent.core.addevent(sock, EV_READ, getWrapper())
 	repeat
 		local event = coroutine.yield(EV_READ)
 		-- Get new socket
 		local client = sock:accept()
 		if client then
+			--cl[#cl + 1] = client
 			client:settimeout(0)
-			local co = coroutine.create(clientCoroutine)
-			handleClient(co, client, callback)
+			local coFunc = coroutine.wrap(clientCoroutine)
+			clientTable[client] = luaevent.core.addevent(client, coFunc, client, callback)
 		end
 	until false
 end
+
+local oldAddEvent = luaevent.core.addevent
+luaevent.core.addevent = function(...)
+	local item = oldAddEvent(...)
+	print("SETUP ITEM FOR: ", debug.getmetatable(item).getfd(item))
+	if not hookedObjectMt then
+		hookedObjectMt = true
+		local mt = debug.getmetatable(item)
+		local oldGC = mt.__gc
+		mt.__gc = function(...)
+			print("RELEASING ITEM FOR: ", mt.getfd(...))
+			return oldGC(...)
+		end
+	end
+	return item
+end
+
 function addserver(sock, callback)
-	local coro = coroutine.create(serverCoroutine)
-	assert(coroutine.resume(coro, sock, callback))
+	local coFunc = coroutine.wrap(serverCoroutine)
+	clientTable[sock] = luaevent.core.addevent(sock, coFunc, sock, callback)
 end
-function addthread(func, ...)
-	return coroutine.resume(coroutine.create(func), ...)
+function addthread(sock, func, ...)
+	local coFunc = coroutine.wrap(func)
+	clientTable[sock] = luaevent.core.addevent(sock, coFunc, ...)
 end
 local _skt_mt = {__index = {
 	connect = function(self, ...)
--- a/luaevent/src/luaevent.c	Sun Jun 10 16:52:55 2007 +0000
+++ b/luaevent/src/luaevent.c	Mon Jun 11 01:08:59 2007 +0000
@@ -74,6 +74,12 @@
 	return 0;
 }
 
+static int luaevent_cb_getfd(lua_State* L) {
+	le_callback* arg = luaL_checkudata(L, 1, EVENT_CALLBACK_ARG_MT);
+	lua_pushinteger(L, arg->ev.ev_fd);
+	return 1;
+}
+
 int getSocketFd(lua_State* L, int idx) {
 	int fd;
 	luaL_checktype(L, idx, LUA_TUSERDATA);
@@ -90,23 +96,35 @@
 /* Expected to be called at the beginning of the coro that uses it.. 
 Value must be kept until coro is complete....
 */
-/* sock, event, callback */
+/* sock, callback */
 static int luaevent_addevent(lua_State* L) {
-	int fd, event, callbackRef;
+	int fd, callbackRef;
+	int top, ret;
 	le_callback* arg;
 	fd = getSocketFd(L, 1);
-	event = luaL_checkinteger(L, 2);
-	luaL_checktype(L, 3, LUA_TFUNCTION);
-	lua_pushvalue(L, 3);
+	luaL_checktype(L, 2, LUA_TFUNCTION);
+	top = lua_gettop(L);
+	/* Preserve the callback function */
+	lua_pushvalue(L, 2);
 	callbackRef = luaL_ref(L, LUA_REGISTRYINDEX);
+	
+	/* Call the callback with all arguments after it to get the loop primed.. */
+	lua_call(L, top - 2, 1);
+	ret = lua_tointeger(L, -1);
+	lua_pop(L, 1);
+	if(ret == -1) { /* Done, no need to setup event */
+		luaL_unref(L, LUA_REGISTRYINDEX, callbackRef);
+		return 0;
+	}
 	arg = lua_newuserdata(L, sizeof(*arg));
 	luaL_getmetatable(L, EVENT_CALLBACK_ARG_MT);
 	lua_setmetatable(L, -2);
 	
 	arg->L = L;
 	arg->callbackRef = callbackRef;
+	
 	/* Setup event... */
-	event_set(&arg->ev, fd, event | EV_PERSIST, luaevent_callback, arg);
+	event_set(&arg->ev, fd, ret | EV_PERSIST, luaevent_callback, arg);
 	event_base_set(getEventBase(L), &arg->ev);
 	event_add(&arg->ev, NULL);
 	return 1;
@@ -157,6 +175,8 @@
 	luaL_newmetatable(L, EVENT_CALLBACK_ARG_MT);
 	lua_pushcfunction(L, luaevent_cb_gc);
 	lua_setfield(L, -2, "__gc");
+	lua_pushcfunction(L, luaevent_cb_getfd);
+	lua_setfield(L, -2, "getfd");
 	lua_pop(L, 1);
 
 	setEventBase(L, event_init());
--- a/luaevent/test/test.lua	Sun Jun 10 16:52:55 2007 +0000
+++ b/luaevent/test/test.lua	Mon Jun 11 01:08:59 2007 +0000
@@ -6,29 +6,18 @@
 require"luaevent"
 require"socket"
 local function echoHandler(skt)
-  while true do
-  print(skt)
-    local data,ret = luaevent.receive(skt, 10)
-    print("GOT: ", data, ret)
-    if data == "quit" or ret == 'closed' then
-      break
-    end
-    luaevent.send(skt, data)
-  end
-  print("DONE")
+	while true do
+		local data,ret = luaevent.receive(skt, 10)
+		if data == "quit" or ret == 'closed' then
+			break
+		end
+		--collectgarbage()
+		luaevent.send(skt, data)
+	end
 end
-local function setupHook(thread)
-	if not thread then debug.sethook(function(event) print("TRACE >: ", debug.getinfo(2, 'n').name) end, 'c')
-	else debug.sethook(thread, function(event) print("TRACE ", thread,">: ", debug.getinfo(2, 'n').name) end, 'c') end
-end
+
 local server = assert(socket.bind("localhost", 20000))
 server:settimeout(0)
-setupHook()
-local coro = coroutine.create
-coroutine.create = function(...)
-	local ret = coro(...)
-	setupHook(ret)
-	return ret
-end
+
 luaevent.addserver(server, echoHandler)
-luaevent.loop()
+luaevent.loop()
\ No newline at end of file
--- a/luaevent/test/testClient.lua	Sun Jun 10 16:52:55 2007 +0000
+++ b/luaevent/test/testClient.lua	Mon Jun 11 01:08:59 2007 +0000
@@ -1,15 +1,22 @@
 require"luaevent"
 require"socket"
-
-local function func()
-	print("ACTIVATED")
-	local sock = socket.tcp()
-	--sock:
-	sock = luaevent.wrap(sock)
-	print(assert(sock:connect("localhost", 20000)))
-	for i = 1, 100000 do assert(sock:send("Greet me  ")) assert(sock:receive(10)) collectgarbage() end
+local function setupHook(thread)
+	if not thread then debug.sethook(function(event) print("TRACE >: ", debug.getinfo(2, 'n').name) end, 'c')
+	else debug.sethook(thread, function(event) print("TRACE ", thread,">: ", debug.getinfo(2, 'n').name) end, 'c') end
 end
 
-luaevent.addthread(func)
-
-luaevent.loop()
\ No newline at end of file
+local function func(sock)
+	sock = luaevent.wrap(sock)
+	assert(sock:connect("localhost", 20000))
+	for i = 1, 10 do
+		for z = 1, 100 do
+			assert(sock:send("Greet me  "))
+		end
+		assert(sock:receive(10 * 100))
+	end
+end
+for i = 1, 1020 do
+	local sock = assert(socket.tcp())
+	luaevent.addthread(sock, func, sock)
+end
+luaevent.loop()

mercurial