diff src/select.c @ 0:4b915342e2a8

LuaSocket 2.0.2 + CMake build description.
author Eric Wing <ewing . public |-at-| gmail . com>
date Tue, 26 Aug 2008 18:40:01 -0700
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/select.c	Tue Aug 26 18:40:01 2008 -0700
@@ -0,0 +1,200 @@
+/*=========================================================================*\
+* Select implementation
+* LuaSocket toolkit
+*
+* RCS ID: $Id: select.c,v 1.22 2005/11/20 07:20:23 diego Exp $
+\*=========================================================================*/
+#include <string.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+
+#include "socket.h"
+#include "timeout.h"
+#include "select.h"
+
+/*=========================================================================*\
+* Internal function prototypes.
+\*=========================================================================*/
+static t_socket getfd(lua_State *L);
+static int dirty(lua_State *L);
+static t_socket collect_fd(lua_State *L, int tab, t_socket max_fd, 
+        int itab, fd_set *set);
+static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set);
+static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, 
+        int itab, int tab, int start);
+static void make_assoc(lua_State *L, int tab);
+static int global_select(lua_State *L);
+
+/* functions in library namespace */
+static luaL_reg func[] = {
+    {"select", global_select},
+    {NULL,     NULL}
+};
+
+/*=========================================================================*\
+* Exported functions
+\*=========================================================================*/
+/*-------------------------------------------------------------------------*\
+* Initializes module
+\*-------------------------------------------------------------------------*/
+int select_open(lua_State *L) {
+    luaL_openlib(L, NULL, func, 0);
+    return 0;
+}
+
+/*=========================================================================*\
+* Global Lua functions
+\*=========================================================================*/
+/*-------------------------------------------------------------------------*\
+* Waits for a set of sockets until a condition is met or timeout.
+\*-------------------------------------------------------------------------*/
+static int global_select(lua_State *L) {
+    int rtab, wtab, itab, ret, ndirty;
+    t_socket max_fd;
+    fd_set rset, wset;
+    t_timeout tm;
+    double t = luaL_optnumber(L, 3, -1);
+    FD_ZERO(&rset); FD_ZERO(&wset);
+    lua_settop(L, 3);
+    lua_newtable(L); itab = lua_gettop(L);
+    lua_newtable(L); rtab = lua_gettop(L);
+    lua_newtable(L); wtab = lua_gettop(L);
+    max_fd = collect_fd(L, 1, SOCKET_INVALID, itab, &rset);
+    ndirty = check_dirty(L, 1, rtab, &rset);
+    t = ndirty > 0? 0.0: t;
+    timeout_init(&tm, t, -1);
+    timeout_markstart(&tm);
+    max_fd = collect_fd(L, 2, max_fd, itab, &wset);
+    ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm);
+    if (ret > 0 || ndirty > 0) {
+        return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
+        return_fd(L, &wset, max_fd+1, itab, wtab, 0);
+        make_assoc(L, rtab);
+        make_assoc(L, wtab);
+        return 2;
+    } else if (ret == 0) {
+        lua_pushstring(L, "timeout");
+        return 3;
+    } else {
+        lua_pushstring(L, "error");
+        return 3;
+    }
+}
+
+/*=========================================================================*\
+* Internal functions
+\*=========================================================================*/
+static t_socket getfd(lua_State *L) {
+    t_socket fd = SOCKET_INVALID;
+    lua_pushstring(L, "getfd");
+    lua_gettable(L, -2);
+    if (!lua_isnil(L, -1)) {
+        lua_pushvalue(L, -2);
+        lua_call(L, 1, 1);
+        if (lua_isnumber(L, -1)) 
+            fd = (t_socket) lua_tonumber(L, -1); 
+    } 
+    lua_pop(L, 1);
+    return fd;
+}
+
+static int dirty(lua_State *L) {
+    int is = 0;
+    lua_pushstring(L, "dirty");
+    lua_gettable(L, -2);
+    if (!lua_isnil(L, -1)) {
+        lua_pushvalue(L, -2);
+        lua_call(L, 1, 1);
+        is = lua_toboolean(L, -1);
+    } 
+    lua_pop(L, 1);
+    return is;
+}
+
+static t_socket collect_fd(lua_State *L, int tab, t_socket max_fd, 
+        int itab, fd_set *set) {
+    int i = 1;
+    if (lua_isnil(L, tab)) 
+        return max_fd;
+    while (1) {
+        t_socket fd;
+        lua_pushnumber(L, i);
+        lua_gettable(L, tab);
+        if (lua_isnil(L, -1)) {
+            lua_pop(L, 1);
+            break;
+        }
+        fd = getfd(L);
+        if (fd != SOCKET_INVALID) {
+            FD_SET(fd, set);
+            if (max_fd == SOCKET_INVALID || max_fd < fd) 
+                max_fd = fd;
+            lua_pushnumber(L, fd);
+            lua_pushvalue(L, -2);
+            lua_settable(L, itab);
+        }
+        lua_pop(L, 1);
+        i = i + 1;
+    }
+    return max_fd;
+}
+
+static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
+    int ndirty = 0, i = 1;
+    if (lua_isnil(L, tab)) 
+        return 0;
+    while (1) { 
+        t_socket fd;
+        lua_pushnumber(L, i);
+        lua_gettable(L, tab);
+        if (lua_isnil(L, -1)) {
+            lua_pop(L, 1);
+            break;
+        }
+        fd = getfd(L);
+        if (fd != SOCKET_INVALID && dirty(L)) {
+            lua_pushnumber(L, ++ndirty);
+            lua_pushvalue(L, -2);
+            lua_settable(L, dtab);
+            FD_CLR(fd, set);
+        }
+        lua_pop(L, 1);
+        i = i + 1;
+    }
+    return ndirty;
+}
+
+static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, 
+        int itab, int tab, int start) {
+    t_socket fd;
+    for (fd = 0; fd < max_fd; fd++) {
+        if (FD_ISSET(fd, set)) {
+            lua_pushnumber(L, ++start);
+            lua_pushnumber(L, fd);
+            lua_gettable(L, itab);
+            lua_settable(L, tab);
+        }
+    }
+}
+
+static void make_assoc(lua_State *L, int tab) {
+    int i = 1, atab;
+    lua_newtable(L); atab = lua_gettop(L);
+    while (1) {
+        lua_pushnumber(L, i);
+        lua_gettable(L, tab);
+        if (!lua_isnil(L, -1)) {
+            lua_pushnumber(L, i);
+            lua_pushvalue(L, -2);
+            lua_settable(L, atab);
+            lua_pushnumber(L, i);
+            lua_settable(L, atab);
+        } else {
+            lua_pop(L, 1);
+            break;
+        }
+        i = i+1;
+    }
+}
+