luasocket/src/select.c
2002-07-03 19:06:53 +00:00

137 lines
4.3 KiB
C

#include <lua.h>
#include "lspriv.h"
#include "lsselect.h"
#include "lsfd.h"
/* auxiliar functions */
static int local_select(lua_State *L);
static int local_getfd(lua_State *L);
static int local_pending(lua_State *L);
static int local_FD_SET(lua_State *L);
static int local_FD_ISSET(lua_State *L);
static int select_lua_select(lua_State *L);
/*-------------------------------------------------------------------------*\
* Marks type as selectable
* Input
* name: type name
\*-------------------------------------------------------------------------*/
void select_addclass(lua_State *L, cchar *lsclass)
{
lua_pushstring(L, "luasocket(select)");
lua_gettable(L, LUA_REGISTRYINDEX);
lua_pushstring(L, lsclass);
lua_pushnumber(L, 1);
lua_settable(L, -3);
lua_pop(L, 1);
}
void select_open(lua_State *L)
{
/* push select auxiliar lua function and register
* select_lua_select with it as an upvalue */
#include "lsselect.loh"
lua_pushcclosure(L, select_lua_select, 1);
lua_setglobal(L, "select");
/* create luasocket(select) table */
lua_pushstring(L, "luasocket(select)");
lua_newtable(L);
lua_settable(L, LUA_REGISTRYINDEX);
}
/*-------------------------------------------------------------------------*\
* Waits for a set of sockets until a condition is met or timeout.
* Lua Input: {input}, {output} [, timeout]
* {input}: table of sockets to be tested for input
* {output}: table of sockets to be tested for output
* timeout: maximum amount of time to wait for condition, in seconds
* Lua Returns: {input}, {output}, err
* {input}: table with sockets ready for input
* {output}: table with sockets ready for output
* err: "timeout" or nil
\*-------------------------------------------------------------------------*/
static int select_lua_select(lua_State *L)
{
fd_set read, write;
FD_ZERO(&read);
FD_ZERO(&write);
/* push select lua auxiliar function */
lua_pushvalue(L, lua_upvalueindex(1)); lua_insert(L, 1);
/* make sure we have enough arguments (nil is the default) */
lua_settop(L, 4);
/* pass FD_SET and manipulation functions */
lua_newuserdatabox(L, &read);
lua_newuserdatabox(L, &write);
lua_pushcfunction(L, local_FD_SET);
lua_pushcfunction(L, local_FD_ISSET);
/* pass getfd function with selectable table as upvalue */
lua_pushstring(L, "luasocket(select)"); lua_gettable(L, LUA_REGISTRYINDEX);
lua_pushcclosure(L, local_getfd, 1);
/* pass pending function */
lua_pushstring(L, "luasocket(select)"); lua_gettable(L, LUA_REGISTRYINDEX);
lua_pushcclosure(L, local_pending, 1);
/* pass select auxiliar C function */
lua_pushcfunction(L, local_select);
/* call select auxiliar lua function */
lua_call(L, 10, 3);
return 3;
}
static int local_getfd(lua_State *L)
{
priv_pushclass(L, 1);
lua_gettable(L, lua_upvalueindex(1));
if (!lua_isnil(L, -1)) {
p_fd sock = (p_fd) lua_touserdata(L, 1);
lua_pushnumber(L, sock->fd);
}
return 1;
}
static int local_pending(lua_State *L)
{
priv_pushclass(L, 1);
lua_gettable(L, lua_upvalueindex(1));
if (!lua_isnil(L, -1)) {
p_fd sock = (p_fd) lua_touserdata(L, 1);
if (sock->fd_pending(L, sock)) lua_pushnumber(L, 1);
else lua_pushnil(L);
}
return 1;
}
static int local_select(lua_State *L)
{
int max_fd = (int) lua_tonumber(L, 1);
fd_set *read_set = (fd_set *) lua_touserdata(L, 2);
fd_set *write_set = (fd_set *) lua_touserdata(L, 3);
int deadline = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000);
struct timeval tv;
if (deadline >= 0) {
tv.tv_sec = deadline / 1000;
tv.tv_usec = (deadline % 1000) * 1000;
lua_pushnumber(L, select(max_fd, read_set, write_set, NULL, &tv));
} else {
lua_pushnumber(L, select(max_fd, read_set, write_set, NULL, NULL));
}
return 1;
}
static int local_FD_SET(lua_State *L)
{
COMPAT_FD fd = (COMPAT_FD) lua_tonumber(L, 1);
fd_set *set = (fd_set *) lua_touserdata(L, 2);
if (fd >= 0) FD_SET(fd, set);
return 0;
}
static int local_FD_ISSET(lua_State *L)
{
COMPAT_FD fd = (COMPAT_FD) lua_tonumber(L, 1);
fd_set *set = (fd_set *) lua_touserdata(L, 2);
if (fd >= 0 && FD_ISSET(fd, set)) lua_pushnumber(L, 1);
else lua_pushnil(L);
return 1;
}