1 /*=========================================================================*\
2 * Select implementation
4 \*=========================================================================*/
14 /*=========================================================================*\
15 * Internal function prototypes.
16 \*=========================================================================*/
17 static t_socket
getfd(lua_State
*L
);
18 static int dirty(lua_State
*L
);
19 static void collect_fd(lua_State
*L
, int tab
, int itab
,
20 fd_set
*set
, t_socket
*max_fd
);
21 static int check_dirty(lua_State
*L
, int tab
, int dtab
, fd_set
*set
);
22 static void return_fd(lua_State
*L
, fd_set
*set
, t_socket max_fd
,
23 int itab
, int tab
, int start
);
24 static void make_assoc(lua_State
*L
, int tab
);
25 static int global_select(lua_State
*L
);
27 /* functions in library namespace */
28 static luaL_Reg func
[] = {
29 {"select", global_select
},
33 /*=========================================================================*\
35 \*=========================================================================*/
36 /*-------------------------------------------------------------------------*\
38 \*-------------------------------------------------------------------------*/
39 int select_open(lua_State
*L
) {
40 lua_pushstring(L
, "_SETSIZE");
41 lua_pushnumber(L
, FD_SETSIZE
);
43 luaL_openlib(L
, NULL
, func
, 0);
47 /*=========================================================================*\
48 * Global Lua functions
49 \*=========================================================================*/
50 /*-------------------------------------------------------------------------*\
51 * Waits for a set of sockets until a condition is met or timeout.
52 \*-------------------------------------------------------------------------*/
53 static int global_select(lua_State
*L
) {
54 int rtab
, wtab
, itab
, ret
, ndirty
;
55 t_socket max_fd
= SOCKET_INVALID
;
58 double t
= luaL_optnumber(L
, 3, -1);
59 FD_ZERO(&rset
); FD_ZERO(&wset
);
61 lua_newtable(L
); itab
= lua_gettop(L
);
62 lua_newtable(L
); rtab
= lua_gettop(L
);
63 lua_newtable(L
); wtab
= lua_gettop(L
);
64 collect_fd(L
, 1, itab
, &rset
, &max_fd
);
65 collect_fd(L
, 2, itab
, &wset
, &max_fd
);
66 ndirty
= check_dirty(L
, 1, rtab
, &rset
);
67 t
= ndirty
> 0? 0.0: t
;
68 timeout_init(&tm
, t
, -1);
69 timeout_markstart(&tm
);
70 ret
= socket_select(max_fd
+1, &rset
, &wset
, NULL
, &tm
);
71 if (ret
> 0 || ndirty
> 0) {
72 return_fd(L
, &rset
, max_fd
+1, itab
, rtab
, ndirty
);
73 return_fd(L
, &wset
, max_fd
+1, itab
, wtab
, 0);
77 } else if (ret
== 0) {
78 lua_pushstring(L
, "timeout");
81 luaL_error(L
, "select failed");
86 /*=========================================================================*\
88 \*=========================================================================*/
89 static t_socket
getfd(lua_State
*L
) {
90 t_socket fd
= SOCKET_INVALID
;
91 lua_pushstring(L
, "getfd");
93 if (!lua_isnil(L
, -1)) {
96 if (lua_isnumber(L
, -1)) {
97 double numfd
= lua_tonumber(L
, -1);
98 fd
= (numfd
>= 0.0)? (t_socket
) numfd
: SOCKET_INVALID
;
105 static int dirty(lua_State
*L
) {
107 lua_pushstring(L
, "dirty");
109 if (!lua_isnil(L
, -1)) {
110 lua_pushvalue(L
, -2);
112 is
= lua_toboolean(L
, -1);
118 static void collect_fd(lua_State
*L
, int tab
, int itab
,
119 fd_set
*set
, t_socket
*max_fd
) {
121 /* nil is the same as an empty table */
122 if (lua_isnil(L
, tab
)) return;
123 /* otherwise we need it to be a table */
124 luaL_checktype(L
, tab
, LUA_TTABLE
);
127 lua_pushnumber(L
, i
);
128 lua_gettable(L
, tab
);
129 if (lua_isnil(L
, -1)) {
133 /* getfd figures out if this is a socket */
135 if (fd
!= SOCKET_INVALID
) {
136 /* make sure we don't overflow the fd_set */
139 luaL_argerror(L
, tab
, "too many sockets");
141 if (fd
>= FD_SETSIZE
)
142 luaL_argerror(L
, tab
, "descriptor too large for set size");
146 /* keep track of the largest descriptor so far */
147 if (*max_fd
== SOCKET_INVALID
|| *max_fd
< fd
)
149 /* make sure we can map back from descriptor to the object */
150 lua_pushnumber(L
, (lua_Number
) fd
);
151 lua_pushvalue(L
, -2);
152 lua_settable(L
, itab
);
159 static int check_dirty(lua_State
*L
, int tab
, int dtab
, fd_set
*set
) {
160 int ndirty
= 0, i
= 1;
161 if (lua_isnil(L
, tab
))
165 lua_pushnumber(L
, i
);
166 lua_gettable(L
, tab
);
167 if (lua_isnil(L
, -1)) {
172 if (fd
!= SOCKET_INVALID
&& dirty(L
)) {
173 lua_pushnumber(L
, ++ndirty
);
174 lua_pushvalue(L
, -2);
175 lua_settable(L
, dtab
);
184 static void return_fd(lua_State
*L
, fd_set
*set
, t_socket max_fd
,
185 int itab
, int tab
, int start
) {
187 for (fd
= 0; fd
< max_fd
; fd
++) {
188 if (FD_ISSET(fd
, set
)) {
189 lua_pushnumber(L
, ++start
);
190 lua_pushnumber(L
, (lua_Number
) fd
);
191 lua_gettable(L
, itab
);
192 lua_settable(L
, tab
);
197 static void make_assoc(lua_State
*L
, int tab
) {
199 lua_newtable(L
); atab
= lua_gettop(L
);
201 lua_pushnumber(L
, i
);
202 lua_gettable(L
, tab
);
203 if (!lua_isnil(L
, -1)) {
204 lua_pushnumber(L
, i
);
205 lua_pushvalue(L
, -2);
206 lua_settable(L
, atab
);
207 lua_pushnumber(L
, i
);
208 lua_settable(L
, atab
);