aboutsummaryrefslogtreecommitdiff
path: root/src/select.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/select.c')
-rw-r--r--src/select.c221
1 files changed, 146 insertions, 75 deletions
diff --git a/src/select.c b/src/select.c
index 1ebd82c..13f9d6e 100644
--- a/src/select.c
+++ b/src/select.c
@@ -9,26 +9,21 @@
9#include <lua.h> 9#include <lua.h>
10#include <lauxlib.h> 10#include <lauxlib.h>
11 11
12#include "luasocket.h"
13#include "socket.h" 12#include "socket.h"
14#include "auxiliar.h"
15#include "select.h" 13#include "select.h"
16 14
17/*=========================================================================*\ 15/*=========================================================================*\
18* Internal function prototypes. 16* Internal function prototypes.
19\*=========================================================================*/ 17\*=========================================================================*/
20static int meth_set(lua_State *L); 18static int getfd(lua_State *L);
21static int meth_isset(lua_State *L); 19static int dirty(lua_State *L);
22static int c_select(lua_State *L); 20static int collect_fd(lua_State *L, int tab, int max_fd, int itab, fd_set *set);
21static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set);
22static void return_fd(lua_State *L, fd_set *set, int max_fd,
23 int itab, int tab, int start);
24static void make_assoc(lua_State *L, int tab);
23static int global_select(lua_State *L); 25static int global_select(lua_State *L);
24 26
25/* fd_set object methods */
26static luaL_reg set[] = {
27 {"set", meth_set},
28 {"isset", meth_isset},
29 {NULL, NULL}
30};
31
32/* functions in library namespace */ 27/* functions in library namespace */
33static luaL_reg func[] = { 28static luaL_reg func[] = {
34 {"select", global_select}, 29 {"select", global_select},
@@ -36,22 +31,13 @@ static luaL_reg func[] = {
36}; 31};
37 32
38/*=========================================================================*\ 33/*=========================================================================*\
39* Internal function prototypes. 34* Exported functions
40\*=========================================================================*/ 35\*=========================================================================*/
41/*-------------------------------------------------------------------------*\ 36/*-------------------------------------------------------------------------*\
42* Initializes module 37* Initializes module
43\*-------------------------------------------------------------------------*/ 38\*-------------------------------------------------------------------------*/
44int select_open(lua_State *L) 39int select_open(lua_State *L) {
45{ 40 luaL_openlib(L, NULL, func, 0);
46 /* get select auxiliar lua function from lua code and register
47 * pass it as an upvalue to global_select */
48#ifdef LUASOCKET_COMPILED
49#include "select.lch"
50#else
51 lua_dofile(L, "select.lua");
52#endif
53 luaL_openlib(L, NULL, func, 1);
54 aux_newclass(L, "select{fd_set}", set);
55 return 0; 41 return 0;
56} 42}
57 43
@@ -61,64 +47,149 @@ int select_open(lua_State *L)
61/*-------------------------------------------------------------------------*\ 47/*-------------------------------------------------------------------------*\
62* Waits for a set of sockets until a condition is met or timeout. 48* Waits for a set of sockets until a condition is met or timeout.
63\*-------------------------------------------------------------------------*/ 49\*-------------------------------------------------------------------------*/
64static int global_select(lua_State *L) 50static int global_select(lua_State *L) {
65{ 51 int timeout, rtab, wtab, itab, max_fd, ret, ndirty;
66 fd_set *read_fd_set, *write_fd_set; 52 fd_set rset, wset;
67 /* make sure we have enough arguments (nil is the default) */ 53 FD_ZERO(&rset); FD_ZERO(&wset);
68 lua_settop(L, 3); 54 lua_settop(L, 3);
69 /* check timeout */ 55 timeout = lua_isnil(L, 3) ? -1 : (int)(luaL_checknumber(L, 3) * 1000);
70 if (!lua_isnil(L, 3) && !lua_isnumber(L, 3)) 56 lua_newtable(L); itab = lua_gettop(L);
71 luaL_argerror(L, 3, "number or nil expected"); 57 lua_newtable(L); rtab = lua_gettop(L);
72 /* select auxiliar lua function to be called comes first */ 58 lua_newtable(L); wtab = lua_gettop(L);
73 lua_pushvalue(L, lua_upvalueindex(1)); 59 max_fd = collect_fd(L, 1, -1, itab, &rset);
74 lua_insert(L, 1); 60 ndirty = check_dirty(L, 1, rtab, &rset);
75 /* pass fd_set objects */ 61 timeout = ndirty > 0? 0: timeout;
76 read_fd_set = (fd_set *) lua_newuserdata(L, sizeof(fd_set)); 62 max_fd = collect_fd(L, 2, max_fd, itab, &wset);
77 FD_ZERO(read_fd_set); 63 ret = sock_select(max_fd+1, &rset, &wset, NULL, timeout);
78 aux_setclass(L, "select{fd_set}", -1); 64 if (ret > 0 || (ret == 0 && ndirty > 0)) {
79 write_fd_set = (fd_set *) lua_newuserdata(L, sizeof(fd_set)); 65 return_fd(L, &rset, max_fd+1, itab, rtab, ndirty);
80 FD_ZERO(write_fd_set); 66 return_fd(L, &wset, max_fd+1, itab, wtab, 0);
81 aux_setclass(L, "select{fd_set}", -1); 67 make_assoc(L, rtab);
82 /* pass select auxiliar C function */ 68 make_assoc(L, wtab);
83 lua_pushcfunction(L, c_select); 69 return 2;
84 /* call select auxiliar lua function */ 70 } else if (ret == 0) {
85 lua_call(L, 6, 3); 71 lua_pushstring(L, "timeout");
86 return 3; 72 return 3;
73 } else {
74 lua_pushnil(L);
75 lua_pushnil(L);
76 lua_pushstring(L, "error");
77 return 3;
78 }
87} 79}
88 80
89/*=========================================================================*\ 81/*=========================================================================*\
90* Lua methods 82* Internal functions
91\*=========================================================================*/ 83\*=========================================================================*/
92static int meth_set(lua_State *L) 84static int getfd(lua_State *L) {
93{ 85 int fd = -1;
94 fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1); 86 lua_pushstring(L, "getfd");
95 t_sock fd = (t_sock) lua_tonumber(L, 2); 87 lua_gettable(L, -2);
96 if (fd >= 0) FD_SET(fd, set); 88 if (!lua_isnil(L, -1)) {
97 return 0; 89 lua_pushvalue(L, -2);
90 lua_call(L, 1, 1);
91 if (lua_isnumber(L, -1))
92 fd = lua_tonumber(L, -1);
93 }
94 lua_pop(L, 1);
95 return fd;
98} 96}
99 97
100static int meth_isset(lua_State *L) 98static int dirty(lua_State *L) {
101{ 99 int is = 0;
102 fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1); 100 lua_pushstring(L, "dirty");
103 t_sock fd = (t_sock) lua_tonumber(L, 2); 101 lua_gettable(L, -2);
104 if (fd >= 0 && FD_ISSET(fd, set)) lua_pushnumber(L, 1); 102 if (!lua_isnil(L, -1)) {
105 else lua_pushnil(L); 103 lua_pushvalue(L, -2);
106 return 1; 104 lua_call(L, 1, 1);
105 is = lua_toboolean(L, -1);
106 }
107 lua_pop(L, 1);
108 return is;
107} 109}
108 110
109/*=========================================================================*\ 111static int collect_fd(lua_State *L, int tab, int max_fd,
110* Internal functions 112 int itab, fd_set *set) {
111\*=========================================================================*/ 113 int i = 1;
112static int c_select(lua_State *L) 114 if (lua_isnil(L, tab))
113{ 115 return max_fd;
114 int max_fd = (int) lua_tonumber(L, 1); 116 while (1) {
115 fd_set *read_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 2); 117 int fd;
116 fd_set *write_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 3); 118 lua_pushnumber(L, i);
117 int timeout = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000); 119 lua_gettable(L, tab);
118 struct timeval tv; 120 if (lua_isnil(L, -1)) {
119 tv.tv_sec = timeout / 1000; 121 lua_pop(L, 1);
120 tv.tv_usec = (timeout % 1000) * 1000; 122 break;
121 lua_pushnumber(L, select(max_fd, read_fd_set, write_fd_set, NULL, 123 }
122 timeout < 0 ? NULL : &tv)); 124 fd = getfd(L);
123 return 1; 125 if (fd > 0) {
126 FD_SET(fd, set);
127 if (max_fd < fd) max_fd = fd;
128 lua_pushnumber(L, fd);
129 lua_pushvalue(L, -2);
130 lua_settable(L, itab);
131 }
132 lua_pop(L, 1);
133 i = i + 1;
134 }
135 return max_fd;
136}
137
138static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
139 int ndirty = 0, i = 1;
140 if (lua_isnil(L, tab))
141 return 0;
142 while (1) {
143 int fd;
144 lua_pushnumber(L, i);
145 lua_gettable(L, tab);
146 if (lua_isnil(L, -1)) {
147 lua_pop(L, 1);
148 break;
149 }
150 fd = getfd(L);
151 if (fd > 0 && dirty(L)) {
152 lua_pushnumber(L, ++ndirty);
153 lua_pushvalue(L, -2);
154 lua_settable(L, dtab);
155 FD_CLR(fd, set);
156 }
157 lua_pop(L, 1);
158 i = i + 1;
159 }
160 return ndirty;
161}
162
163static void return_fd(lua_State *L, fd_set *set, int max_fd,
164 int itab, int tab, int start) {
165 int fd;
166 for (fd = 0; fd < max_fd; fd++) {
167 if (FD_ISSET(fd, set)) {
168 lua_pushnumber(L, ++start);
169 lua_pushnumber(L, fd);
170 lua_gettable(L, itab);
171 lua_settable(L, tab);
172 }
173 }
174}
175
176static void make_assoc(lua_State *L, int tab) {
177 int i = 1, atab;
178 lua_newtable(L); atab = lua_gettop(L);
179 while (1) {
180 lua_pushnumber(L, i);
181 lua_gettable(L, tab);
182 if (!lua_isnil(L, -1)) {
183 lua_pushnumber(L, i);
184 lua_pushvalue(L, -2);
185 lua_settable(L, atab);
186 lua_pushnumber(L, i);
187 lua_settable(L, atab);
188 } else {
189 lua_pop(L, 1);
190 break;
191 }
192 i = i+1;
193 }
124} 194}
195