lua-users home
lua-l archive

Re: helper threads layer

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


On Thursday 09 March 2006 1:16 pm, Vijay Aswadhati wrote:
> This may be the beginning of something new and exciting!!
i hope so! either because it's accepted, or because somebody does something 
much better after seeing this as a proof of concept.
> A few concrete examples would be of great help. I am particularly
> interested in how one would go about creating a singleton timer
this is precisely what i did as a testbed for the library. here's the full C 
code:
#include <sys/time.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include "lua.h"
#include "lauxlib.h"
#include "helper.h"
typedef struct timer_udata {
	struct timeval tv;
	int ret;
} timer_udata;
static int timer_prepare (lua_State *L, void **udata) {
	lua_Number t = luaL_checknumber (L, 1);
	timer_udata *td = (timer_udata *)malloc (sizeof (timer_udata));
	if (!td)
		luaL_error (L, "can't alloc udata");
	
	td->tv.tv_sec = (int) t;
	td->tv.tv_usec = (t - td->tv.tv_sec) * 1000000;
	
	*udata = td;
	
	return 0;
}
static int timer_work (void *udata) {
	timer_udata *td = (timer_udata *)udata;
	fd_set fd_a, fd_b, fd_c;
	FD_ZERO (&fd_a);
	FD_ZERO (&fd_b);
	FD_ZERO (&fd_c);
	
	printf ("before select\n");
	td->ret = select (0, &fd_a, &fd_b, &fd_c, &td->tv);
	printf ("after select\n");
	
	return 0;
}
static int timer_finish (lua_State *L, void *udata) {
	timer_udata *td = (timer_udata *)udata;
	
	if (td->ret < 0)
		luaL_error (L, strerror (td->ret));
	
	free (td);
	
	return 0;
}
static task_ops timer_ops = {
	timer_prepare,
	timer_work,
	timer_finish
};
int luaopen_timer (lua_State *L);
int luaopen_timer (lua_State *L) {
	helper_init ();
	add_helperfunc (L, &timer_ops);
	return 1;
}
as you can see, timer_prepare() gets the Lua parameters (a single number), 
allocates a private structure and fills it with a timeval (with sec and usec 
fields). timer_work() runs in the background, so it can't touch the Lua 
space; it gets the timeval struct and does a select() to wait some time. 
timer_finish() verifies the return value of the select(), and frees the 
udata. if there was any final result (like on a read funcion), it would be 
pushed in the Lua stack.
note that since it defines just a single function, it's returned in the stack 
by luaopen_timer(), instead of building a package.
this is how i tested it from Lua:
require "helper"
timer = require "timer"
q1=helper.newqueue()
q2=helper.newqueue()
print ("queues:", q1, q2)
th=helper.newthread (q1, q2)
print ("thread:", th)
tsk=timer(10)
print ("task:", tsk)
q1:addtask (tsk)
t2=q2:wait()
print ("t2:", t2)
helper.finish (t2)
print ("end")
----------------------------
th is the helper thread. it uses q1 and q2 as input and output queues, 
respectively. as soon as it's created, it tries to get a task from q1; but 
since it's empty, it's blocked.
the timer() function doesn't do the 'work' immediately, it just creates and 
returns a 'task' (a lightuserdata). it also calls the timer_prepare() 
function.
when the task is added to q1, the thread gets it and executes the timer_work() 
function. the Lua code continues to run in the 'main' thread.
the q2:wait() function blocks until there's a task in q2. when timer_work() 
ends, the task is pushed to q2 and the Lua code unblocks. t2 gets the task, 
it should be equal to tsk (that's why i used lightuserdata). the 
helper.finish() call gets any result (none in this example)
> instance using this package and how the main dispatch loop would
> look like in the "C" or "C++" world.
my idea is that the main dispatch loop would be Lua code, not C.
i haven't written one yet, but this would be the general idea:
wrap all functions that return a task, like this:
local _read = read
function read (file)
 return helper.finish (yield (_read (file)))
end
and in the dispatcher:
while true do
 local tsk_done = out_q:wait()
 local co = coros [tsk_done]
 local tsk_blk = coroutine.resume (co, tsk_done)
 coros [tsk_blk] = co
 in_q:addtask (tsk_blk)
end
> On a frivolous note, I would probably name this package as
> 'concurrency' instead of 'helper'.
i'm notoriously bad at picking names for my code... any explanation why you 
think 'concurrency' is better than 'helper' ?
-- 
Javier

Attachment: pgpfImGulIblf.pgp
Description: PGP signature


AltStyle によって変換されたページ (->オリジナル) /