beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luasocket / src / select.c
blob51fb198611a6b39f1a87bc52b9192c0a6b33c2b8
1 /*=========================================================================*\
2 * Select implementation
3 * LuaSocket toolkit
4 \*=========================================================================*/
5 #include <string.h>
7 #include "lua.h"
8 #include "lauxlib.h"
10 #include "socket.h"
11 #include "timeout.h"
12 #include "select.h"
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},
30 {NULL, NULL}
33 /*=========================================================================*\
34 * Exported functions
35 \*=========================================================================*/
36 /*-------------------------------------------------------------------------*\
37 * Initializes module
38 \*-------------------------------------------------------------------------*/
39 int select_open(lua_State *L) {
40 lua_pushstring(L, "_SETSIZE");
41 lua_pushnumber(L, FD_SETSIZE);
42 lua_rawset(L, -3);
43 luaL_openlib(L, NULL, func, 0);
44 return 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;
56 fd_set rset, wset;
57 t_timeout tm;
58 double t = luaL_optnumber(L, 3, -1);
59 FD_ZERO(&rset); FD_ZERO(&wset);
60 lua_settop(L, 3);
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);
74 make_assoc(L, rtab);
75 make_assoc(L, wtab);
76 return 2;
77 } else if (ret == 0) {
78 lua_pushstring(L, "timeout");
79 return 3;
80 } else {
81 luaL_error(L, "select failed");
82 return 3;
86 /*=========================================================================*\
87 * Internal functions
88 \*=========================================================================*/
89 static t_socket getfd(lua_State *L) {
90 t_socket fd = SOCKET_INVALID;
91 lua_pushstring(L, "getfd");
92 lua_gettable(L, -2);
93 if (!lua_isnil(L, -1)) {
94 lua_pushvalue(L, -2);
95 lua_call(L, 1, 1);
96 if (lua_isnumber(L, -1)) {
97 double numfd = lua_tonumber(L, -1);
98 fd = (numfd >= 0.0)? (t_socket) numfd: SOCKET_INVALID;
101 lua_pop(L, 1);
102 return fd;
105 static int dirty(lua_State *L) {
106 int is = 0;
107 lua_pushstring(L, "dirty");
108 lua_gettable(L, -2);
109 if (!lua_isnil(L, -1)) {
110 lua_pushvalue(L, -2);
111 lua_call(L, 1, 1);
112 is = lua_toboolean(L, -1);
114 lua_pop(L, 1);
115 return is;
118 static void collect_fd(lua_State *L, int tab, int itab,
119 fd_set *set, t_socket *max_fd) {
120 int i = 1, n = 0;
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);
125 for ( ;; ) {
126 t_socket fd;
127 lua_pushnumber(L, i);
128 lua_gettable(L, tab);
129 if (lua_isnil(L, -1)) {
130 lua_pop(L, 1);
131 break;
133 /* getfd figures out if this is a socket */
134 fd = getfd(L);
135 if (fd != SOCKET_INVALID) {
136 /* make sure we don't overflow the fd_set */
137 #ifdef _WIN32
138 if (n >= FD_SETSIZE)
139 luaL_argerror(L, tab, "too many sockets");
140 #else
141 if (fd >= FD_SETSIZE)
142 luaL_argerror(L, tab, "descriptor too large for set size");
143 #endif
144 FD_SET(fd, set);
145 n++;
146 /* keep track of the largest descriptor so far */
147 if (*max_fd == SOCKET_INVALID || *max_fd < fd)
148 *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);
154 lua_pop(L, 1);
155 i = i + 1;
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))
162 return 0;
163 for ( ;; ) {
164 t_socket fd;
165 lua_pushnumber(L, i);
166 lua_gettable(L, tab);
167 if (lua_isnil(L, -1)) {
168 lua_pop(L, 1);
169 break;
171 fd = getfd(L);
172 if (fd != SOCKET_INVALID && dirty(L)) {
173 lua_pushnumber(L, ++ndirty);
174 lua_pushvalue(L, -2);
175 lua_settable(L, dtab);
176 FD_CLR(fd, set);
178 lua_pop(L, 1);
179 i = i + 1;
181 return ndirty;
184 static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
185 int itab, int tab, int start) {
186 t_socket fd;
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) {
198 int i = 1, atab;
199 lua_newtable(L); atab = lua_gettop(L);
200 for ( ;; ) {
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);
209 } else {
210 lua_pop(L, 1);
211 break;
213 i = i+1;