aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Nehab <diego@tecgraf.puc-rio.br>2002-07-03 19:06:53 +0000
committerDiego Nehab <diego@tecgraf.puc-rio.br>2002-07-03 19:06:53 +0000
commit9b8bce6465d2c7de84782f9e12f529a020a16444 (patch)
tree8a9e7319c1e60e015364dbf22d03aba7d38cd550
parentb04b81ddd959948143f817ee7230783660e24222 (diff)
downloadluasocket-9b8bce6465d2c7de84782f9e12f529a020a16444.tar.gz
luasocket-9b8bce6465d2c7de84782f9e12f529a020a16444.tar.bz2
luasocket-9b8bce6465d2c7de84782f9e12f529a020a16444.zip
select implementation.
-rw-r--r--src/select.c248
1 files 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 @@
1#include <lua.h>
2#include "lspriv.h"
3#include "lsselect.h"
4#include "lsfd.h"
5
6/* auxiliar functions */
7static int local_select(lua_State *L);
8static int local_getfd(lua_State *L);
9static int local_pending(lua_State *L);
10static int local_FD_SET(lua_State *L);
11static int local_FD_ISSET(lua_State *L);
12
13static int select_lua_select(lua_State *L);
14
1/*-------------------------------------------------------------------------*\ 15/*-------------------------------------------------------------------------*\
2* Marks type as selectable 16* Marks type as selectable
3* Input 17* Input
4* name: type name 18* name: type name
5\*-------------------------------------------------------------------------*/ 19\*-------------------------------------------------------------------------*/
6void slct_addclass(lua_State *L, cchar *lsclass) 20void select_addclass(lua_State *L, cchar *lsclass)
7{ 21{
8 lua_pushstring(L, "selectable sockets"); 22 lua_pushstring(L, "luasocket(select)");
9 lua_gettable(L, LUA_REGISTRYINDEX); 23 lua_gettable(L, LUA_REGISTRYINDEX);
10 lua_pushstring(L, lsclass); 24 lua_pushstring(L, lsclass);
11 lua_pushnumber(L, 1); 25 lua_pushnumber(L, 1);
12 lua_settable(L, -3); 26 lua_settable(L, -3);
13 lua_pop(L, 2); 27 lua_pop(L, 1);
14} 28}
15 29
16/*-------------------------------------------------------------------------*\ 30void select_open(lua_State *L)
17* Gets a pointer to a socket structure from a userdata
18* Input
19* pos: userdata stack index
20* Returns
21* pointer to structure, or NULL if invalid type
22\*-------------------------------------------------------------------------*/
23static p_sock ls_toselectable(lua_State *L)
24{ 31{
25 lua_getregistry(L); 32 /* push select auxiliar lua function and register
26 lua_pushstring(L, "sock(selectable)"); 33 * select_lua_select with it as an upvalue */
27 lua_gettable(L, -2); 34#include "lsselect.loh"
28 lua_pushstring(L, lua_type(L, -3)); 35 lua_pushcclosure(L, select_lua_select, 1);
29 lua_gettable(L, -2); 36 lua_setglobal(L, "select");
30 if (lua_isnil(L, -1)) { 37 /* create luasocket(select) table */
31 lua_pop(L, 3); 38 lua_pushstring(L, "luasocket(select)");
32 return NULL; 39 lua_newtable(L);
33 } else { 40 lua_settable(L, LUA_REGISTRYINDEX);
34 lua_pop(L, 3);
35 return (p_sock) lua_touserdata(L, -1);
36 }
37} 41}
38 42
39/*-------------------------------------------------------------------------*\ 43/*-------------------------------------------------------------------------*\
@@ -47,148 +51,86 @@ static p_sock ls_toselectable(lua_State *L)
47* {output}: table with sockets ready for output 51* {output}: table with sockets ready for output
48* err: "timeout" or nil 52* err: "timeout" or nil
49\*-------------------------------------------------------------------------*/ 53\*-------------------------------------------------------------------------*/
50int global_select(lua_State *L) 54static int select_lua_select(lua_State *L)
51{ 55{
52 int ms = lua_isnil(L, 3) ? -1 : (int) (luaL_opt_number(L, 3, -1) * 1000); 56 fd_set read, write;
53 fd_set rfds, *prfds = NULL, wfds, *pwfds = NULL; 57 FD_ZERO(&read);
54 struct timeval tv, *ptv = NULL; 58 FD_ZERO(&write);
55 unsigned max = 0; 59 /* push select lua auxiliar function */
56 int byfds, readable, writable; 60 lua_pushvalue(L, lua_upvalueindex(1)); lua_insert(L, 1);
57 int toread = 1, towrite = 2; 61 /* make sure we have enough arguments (nil is the default) */
58 lua_newtable(L); byfds = lua_gettop(L); /* sockets indexed by descriptor */ 62 lua_settop(L, 4);
59 lua_newtable(L); readable = lua_gettop(L); 63 /* pass FD_SET and manipulation functions */
60 lua_newtable(L); writable = lua_gettop(L); 64 lua_newuserdatabox(L, &read);
61 /* collect sockets to be tested into FD_SET structures and fill byfds */ 65 lua_newuserdatabox(L, &write);
62 if (lua_istable(L, toread)) 66 lua_pushcfunction(L, local_FD_SET);
63 prfds = tab2rfds(L, toread, &rfds, &max, byfds, readable, &ms); 67 lua_pushcfunction(L, local_FD_ISSET);
64 else if (!lua_isnil(L, toread)) 68 /* pass getfd function with selectable table as upvalue */
65 luaL_argerror(L, toread, "expected table or nil"); 69 lua_pushstring(L, "luasocket(select)"); lua_gettable(L, LUA_REGISTRYINDEX);
66 if (lua_istable(L, towrite)) 70 lua_pushcclosure(L, local_getfd, 1);
67 pwfds = tab2wfds(L, towrite, &wfds, &max, byfds); 71 /* pass pending function */
68 else if (!lua_isnil(L, towrite)) 72 lua_pushstring(L, "luasocket(select)"); lua_gettable(L, LUA_REGISTRYINDEX);
69 luaL_argerror(L, towrite, "expected table or nil"); 73 lua_pushcclosure(L, local_pending, 1);
70 /* fill timeval structure */ 74 /* pass select auxiliar C function */
71 if (ms >= 0) { 75 lua_pushcfunction(L, local_select);
72 tv.tv_sec = ms / 1000; 76 /* call select auxiliar lua function */
73 tv.tv_usec = (ms % 1000) * 1000; 77 lua_call(L, 10, 3);
74 ptv = &tv;
75 } else ptv = NULL; /* ptv == NULL when we don't have timeout */
76 /* see if we can read, write or if we timedout */
77 if (select(max+1, prfds, pwfds, NULL, ptv) <= 0 && ms >= 0) {
78 ls_pusherror(L, LS_TIMEOUT);
79 return 3;
80 }
81 /* collect readable and writable sockets into result tables */
82 fds2tab(L, prfds, max+1, byfds, readable);
83 fds2tab(L, pwfds, max+1, byfds, writable);
84 lua_pushnil(L);
85 return 3; 78 return 3;
86} 79}
87 80
88/*=========================================================================*\ 81static int local_getfd(lua_State *L)
89* Select auxiliar functions
90\*=========================================================================*/
91/*-------------------------------------------------------------------------*\
92* Converts a FD_SET structure into a socket table set
93* Input
94* fds: pointer to FD_SET structure
95* max: 1 plus the largest descriptor value in FD_SET
96* byfds: table indexed by descriptor number, with corresponding socket tables
97* can: table to receive corresponding socket table set
98\*-------------------------------------------------------------------------*/
99static void fds2tab(lua_State *L, fd_set *fds, int max, int byfds, int can)
100{ 82{
101 int s; 83 priv_pushclass(L, 1);
102 if (!fds) return; 84 lua_gettable(L, lua_upvalueindex(1));
103 for (s = 0; s < max; s++) { 85 if (!lua_isnil(L, -1)) {
104 if (FD_ISSET(s, fds)) { 86 p_fd sock = (p_fd) lua_touserdata(L, 1);
105 lua_pushnumber(L, lua_getn(L, can) + 1); 87 lua_pushnumber(L, sock->fd);
106 lua_pushnumber(L, s);
107 lua_gettable(L, byfds);
108 lua_settable(L, can);
109 }
110 } 88 }
89 return 1;
111} 90}
112 91
113/*-------------------------------------------------------------------------*\ 92static int local_pending(lua_State *L)
114* Converts a socket table set ito a FD_SET structure
115* Input
116* towrite: socket table set
117* Output
118* wfds: pointer to FD_SET structure to be filled
119* max: largest descriptor value found in wfds
120* byfds: table indexed by descriptor number, with corresponding socket tables
121\*-------------------------------------------------------------------------*/
122static fd_set *tab2wfds(lua_State *L, int towrite, fd_set *wfds,
123 int *max, int byfds)
124{ 93{
125 int empty = 1; 94 priv_pushclass(L, 1);
126 FD_ZERO(wfds); 95 lua_gettable(L, lua_upvalueindex(1));
127 lua_pushnil(L); 96 if (!lua_isnil(L, -1)) {
128 while (lua_next(L, towrite)) { 97 p_fd sock = (p_fd) lua_touserdata(L, 1);
129 p_sock sock = ls_toselectable(L); 98 if (sock->fd_pending(L, sock)) lua_pushnumber(L, 1);
130 if (sock) { /* skip strange fields */ 99 else lua_pushnil(L);
131 NET_FD s = sock->fd;
132 if (s != NET_INVALIDFD) { /* skip closed sockets */
133 lua_pushnumber(L, s);
134 lua_pushvalue(L, -2);
135 lua_settable(L, byfds);
136 if (s > *max) *max = s;
137 FD_SET(s, wfds);
138 empty = 0;
139 }
140 }
141 /* get rid of value and expose index */
142 lua_pop(L, 1);
143 } 100 }
144 if (empty) return NULL; 101 return 1;
145 else return wfds;
146} 102}
147 103
148/*-------------------------------------------------------------------------*\ 104static int local_select(lua_State *L)
149* Converts a socket table set ito a FD_SET structure
150* Input
151* toread: socket table set
152* Output
153* rfds: pointer to FD_SET structure to be filled
154* max: largest descriptor value found in rfds
155* byfds: table indexed by descriptor number, with corresponding socket tables
156* readable: table to receive socket table if socket is obviously readable
157* ms: will be zeroed if a readable socket is detected
158\*-------------------------------------------------------------------------*/
159static fd_set *tab2rfds(lua_State *L, int toread, fd_set *rfds,
160 int *max, int byfds, int readable, int *ms)
161{ 105{
162 int empty = 1; 106 int max_fd = (int) lua_tonumber(L, 1);
163 FD_ZERO(rfds); 107 fd_set *read_set = (fd_set *) lua_touserdata(L, 2);
164 lua_pushnil(L); 108 fd_set *write_set = (fd_set *) lua_touserdata(L, 3);
165 while (lua_next(L, toread)) { 109 int deadline = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000);
166 p_sock sock = ls_toselectable(L); 110 struct timeval tv;
167 if (sock) { /* skip strange fields */ 111 if (deadline >= 0) {
168 NET_FD s = sock->fd; 112 tv.tv_sec = deadline / 1000;
169 if (s != NET_INVALID) { /* skip closed sockets */ 113 tv.tv_usec = (deadline % 1000) * 1000;
170 /* a socket can have unread data in our internal buffer. we 114 lua_pushnumber(L, select(max_fd, read_set, write_set, NULL, &tv));
171 pass them straight to the readable set, and test only to 115 } else {
172 find out which of the other sockets can be written to or 116 lua_pushnumber(L, select(max_fd, read_set, write_set, NULL, NULL));
173 read from immediately. */
174 if (sock->vt->readable(sock)) {
175 *ms = 0;
176 lua_pushnumber(L, lua_getn(L, readable) + 1);
177 lua_pushvalue(L, -2);
178 lua_settable(L, readable);
179 } else {
180 lua_pushnumber(L, s);
181 lua_pushvalue(L, -2);
182 lua_settable(L, byfds);
183 if (s > *max) *max = s;
184 FD_SET(s, rfds);
185 empty = 0;
186 }
187 }
188 }
189 /* get rid of value and exposed index */
190 lua_pop(L, 1);
191 } 117 }
192 if (empty) return NULL; 118 return 1;
193 else return rfds; 119}
120
121static int local_FD_SET(lua_State *L)
122{
123 COMPAT_FD fd = (COMPAT_FD) lua_tonumber(L, 1);
124 fd_set *set = (fd_set *) lua_touserdata(L, 2);
125 if (fd >= 0) FD_SET(fd, set);
126 return 0;
127}
128
129static int local_FD_ISSET(lua_State *L)
130{
131 COMPAT_FD fd = (COMPAT_FD) lua_tonumber(L, 1);
132 fd_set *set = (fd_set *) lua_touserdata(L, 2);
133 if (fd >= 0 && FD_ISSET(fd, set)) lua_pushnumber(L, 1);
134 else lua_pushnil(L);
135 return 1;
194} 136}