From 9b8bce6465d2c7de84782f9e12f529a020a16444 Mon Sep 17 00:00:00 2001 From: Diego Nehab Date: Wed, 3 Jul 2002 19:06:53 +0000 Subject: [PATCH] select implementation. --- src/select.c | 248 ++++++++++++++++++++------------------------------- 1 file changed, 95 insertions(+), 153 deletions(-) diff --git a/src/select.c b/src/select.c index 1f83b7a..9a24dbb 100644 --- a/src/select.c +++ b/src/select.c @@ -1,39 +1,43 @@ +#include +#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 slct_addclass(lua_State *L, cchar *lsclass) +void select_addclass(lua_State *L, cchar *lsclass) { - lua_pushstring(L, "selectable sockets"); + 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, 2); + lua_pop(L, 1); } -/*-------------------------------------------------------------------------*\ -* Gets a pointer to a socket structure from a userdata -* Input -* pos: userdata stack index -* Returns -* pointer to structure, or NULL if invalid type -\*-------------------------------------------------------------------------*/ -static p_sock ls_toselectable(lua_State *L) +void select_open(lua_State *L) { - lua_getregistry(L); - lua_pushstring(L, "sock(selectable)"); - lua_gettable(L, -2); - lua_pushstring(L, lua_type(L, -3)); - lua_gettable(L, -2); - if (lua_isnil(L, -1)) { - lua_pop(L, 3); - return NULL; - } else { - lua_pop(L, 3); - return (p_sock) lua_touserdata(L, -1); - } + /* 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); } /*-------------------------------------------------------------------------*\ @@ -47,148 +51,86 @@ static p_sock ls_toselectable(lua_State *L) * {output}: table with sockets ready for output * err: "timeout" or nil \*-------------------------------------------------------------------------*/ -int global_select(lua_State *L) +static int select_lua_select(lua_State *L) { - int ms = lua_isnil(L, 3) ? -1 : (int) (luaL_opt_number(L, 3, -1) * 1000); - fd_set rfds, *prfds = NULL, wfds, *pwfds = NULL; - struct timeval tv, *ptv = NULL; - unsigned max = 0; - int byfds, readable, writable; - int toread = 1, towrite = 2; - lua_newtable(L); byfds = lua_gettop(L); /* sockets indexed by descriptor */ - lua_newtable(L); readable = lua_gettop(L); - lua_newtable(L); writable = lua_gettop(L); - /* collect sockets to be tested into FD_SET structures and fill byfds */ - if (lua_istable(L, toread)) - prfds = tab2rfds(L, toread, &rfds, &max, byfds, readable, &ms); - else if (!lua_isnil(L, toread)) - luaL_argerror(L, toread, "expected table or nil"); - if (lua_istable(L, towrite)) - pwfds = tab2wfds(L, towrite, &wfds, &max, byfds); - else if (!lua_isnil(L, towrite)) - luaL_argerror(L, towrite, "expected table or nil"); - /* fill timeval structure */ - if (ms >= 0) { - tv.tv_sec = ms / 1000; - tv.tv_usec = (ms % 1000) * 1000; - ptv = &tv; - } else ptv = NULL; /* ptv == NULL when we don't have timeout */ - /* see if we can read, write or if we timedout */ - if (select(max+1, prfds, pwfds, NULL, ptv) <= 0 && ms >= 0) { - ls_pusherror(L, LS_TIMEOUT); - return 3; - } - /* collect readable and writable sockets into result tables */ - fds2tab(L, prfds, max+1, byfds, readable); - fds2tab(L, pwfds, max+1, byfds, writable); - lua_pushnil(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; } -/*=========================================================================*\ -* Select auxiliar functions -\*=========================================================================*/ -/*-------------------------------------------------------------------------*\ -* Converts a FD_SET structure into a socket table set -* Input -* fds: pointer to FD_SET structure -* max: 1 plus the largest descriptor value in FD_SET -* byfds: table indexed by descriptor number, with corresponding socket tables -* can: table to receive corresponding socket table set -\*-------------------------------------------------------------------------*/ -static void fds2tab(lua_State *L, fd_set *fds, int max, int byfds, int can) +static int local_getfd(lua_State *L) { - int s; - if (!fds) return; - for (s = 0; s < max; s++) { - if (FD_ISSET(s, fds)) { - lua_pushnumber(L, lua_getn(L, can) + 1); - lua_pushnumber(L, s); - lua_gettable(L, byfds); - lua_settable(L, can); - } + 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; } -/*-------------------------------------------------------------------------*\ -* Converts a socket table set ito a FD_SET structure -* Input -* towrite: socket table set -* Output -* wfds: pointer to FD_SET structure to be filled -* max: largest descriptor value found in wfds -* byfds: table indexed by descriptor number, with corresponding socket tables -\*-------------------------------------------------------------------------*/ -static fd_set *tab2wfds(lua_State *L, int towrite, fd_set *wfds, - int *max, int byfds) +static int local_pending(lua_State *L) { - int empty = 1; - FD_ZERO(wfds); - lua_pushnil(L); - while (lua_next(L, towrite)) { - p_sock sock = ls_toselectable(L); - if (sock) { /* skip strange fields */ - NET_FD s = sock->fd; - if (s != NET_INVALIDFD) { /* skip closed sockets */ - lua_pushnumber(L, s); - lua_pushvalue(L, -2); - lua_settable(L, byfds); - if (s > *max) *max = s; - FD_SET(s, wfds); - empty = 0; - } - } - /* get rid of value and expose index */ - lua_pop(L, 1); + 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); } - if (empty) return NULL; - else return wfds; + return 1; } -/*-------------------------------------------------------------------------*\ -* Converts a socket table set ito a FD_SET structure -* Input -* toread: socket table set -* Output -* rfds: pointer to FD_SET structure to be filled -* max: largest descriptor value found in rfds -* byfds: table indexed by descriptor number, with corresponding socket tables -* readable: table to receive socket table if socket is obviously readable -* ms: will be zeroed if a readable socket is detected -\*-------------------------------------------------------------------------*/ -static fd_set *tab2rfds(lua_State *L, int toread, fd_set *rfds, - int *max, int byfds, int readable, int *ms) +static int local_select(lua_State *L) { - int empty = 1; - FD_ZERO(rfds); - lua_pushnil(L); - while (lua_next(L, toread)) { - p_sock sock = ls_toselectable(L); - if (sock) { /* skip strange fields */ - NET_FD s = sock->fd; - if (s != NET_INVALID) { /* skip closed sockets */ - /* a socket can have unread data in our internal buffer. we - pass them straight to the readable set, and test only to - find out which of the other sockets can be written to or - read from immediately. */ - if (sock->vt->readable(sock)) { - *ms = 0; - lua_pushnumber(L, lua_getn(L, readable) + 1); - lua_pushvalue(L, -2); - lua_settable(L, readable); - } else { - lua_pushnumber(L, s); - lua_pushvalue(L, -2); - lua_settable(L, byfds); - if (s > *max) *max = s; - FD_SET(s, rfds); - empty = 0; - } - } - } - /* get rid of value and exposed index */ - lua_pop(L, 1); + 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)); } - if (empty) return NULL; - else return rfds; + 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; }