diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2003-06-09 18:23:40 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2003-06-09 18:23:40 +0000 |
commit | 58bdb658aaa1c30a8f3bed46eef880d308fae582 (patch) | |
tree | 5bf880c715daff79c1a2062f2f3ae8336858c83f /src/select.c | |
parent | b2724ad2d1cc3768a04270ed3f8014ec65ad133b (diff) | |
download | luasocket-58bdb658aaa1c30a8f3bed46eef880d308fae582.tar.gz luasocket-58bdb658aaa1c30a8f3bed46eef880d308fae582.tar.bz2 luasocket-58bdb658aaa1c30a8f3bed46eef880d308fae582.zip |
Select re-implemented in a nicer way.
Few changes in internal class and group registration.
Lua modules are compiled and built into library.
Dynamic library tested in Linux and Mac OS X.
Diffstat (limited to 'src/select.c')
-rw-r--r-- | src/select.c | 191 |
1 files changed, 83 insertions, 108 deletions
diff --git a/src/select.c b/src/select.c index 9f56b47..3cabbd1 100644 --- a/src/select.c +++ b/src/select.c | |||
@@ -1,154 +1,129 @@ | |||
1 | /*=========================================================================*\ | 1 | /*=========================================================================*\ |
2 | * Select implementation | 2 | * Select implementation |
3 | * Global Lua fuctions: | ||
4 | * select: waits until socket ready | ||
5 | * RCS ID: $Id$ | 3 | * RCS ID: $Id$ |
6 | \*=========================================================================*/ | 4 | \*=========================================================================*/ |
7 | #include <string.h> | 5 | #include <string.h> |
6 | |||
8 | #include <lua.h> | 7 | #include <lua.h> |
9 | #include <lauxlib.h> | 8 | #include <lauxlib.h> |
10 | 9 | ||
11 | #include "luasocket.h" | 10 | #include "luasocket.h" |
12 | #include "lspriv.h" | 11 | #include "socket.h" |
13 | #include "lsselect.h" | 12 | #include "auxiliar.h" |
14 | #include "lsfd.h" | 13 | #include "select.h" |
15 | 14 | ||
16 | /* auxiliar functions */ | 15 | static int meth_set(lua_State *L); |
17 | static int local_select(lua_State *L); | 16 | static int meth_isset(lua_State *L); |
18 | static int local_getfd(lua_State *L); | 17 | static int c_select(lua_State *L); |
19 | static int local_pending(lua_State *L); | 18 | static int global_select(lua_State *L); |
20 | static int local_FD_SET(lua_State *L); | 19 | static void check_obj_tab(lua_State *L, int tabidx); |
21 | static int local_FD_ISSET(lua_State *L); | ||
22 | 20 | ||
23 | static int select_lua_select(lua_State *L); | 21 | /* fd_set object methods */ |
22 | static luaL_reg set[] = { | ||
23 | {"set", meth_set}, | ||
24 | {"isset", meth_isset}, | ||
25 | {NULL, NULL} | ||
26 | }; | ||
24 | 27 | ||
25 | /*-------------------------------------------------------------------------*\ | 28 | /* functions in library namespace */ |
26 | * Marks type as selectable | 29 | static luaL_reg func[] = { |
27 | * Input | 30 | {"select", global_select}, |
28 | * name: type name | 31 | {NULL, NULL} |
29 | \*-------------------------------------------------------------------------*/ | 32 | }; |
30 | void select_addclass(lua_State *L, cchar *lsclass) | ||
31 | { | ||
32 | lua_pushstring(L, "luasocket(select)"); | ||
33 | lua_gettable(L, LUA_REGISTRYINDEX); | ||
34 | lua_pushstring(L, lsclass); | ||
35 | lua_pushnumber(L, 1); | ||
36 | lua_settable(L, -3); | ||
37 | lua_pop(L, 1); | ||
38 | } | ||
39 | 33 | ||
40 | void select_open(lua_State *L) | 34 | void select_open(lua_State *L) |
41 | { | 35 | { |
42 | /* push select auxiliar lua function and register | 36 | /* get select auxiliar lua function from lua code and register |
43 | * select_lua_select with it as an upvalue */ | 37 | * pass it as an upvalue to global_select */ |
44 | #ifdef LUASOCKET_DOFILE | 38 | #ifdef LUASOCKET_COMPILED |
45 | lua_dofile(L, "lsselect.lua"); | 39 | #include "select.lch" |
46 | #else | 40 | #else |
47 | #include "lsselect.loh" | 41 | lua_dofile(L, "select.lua"); |
48 | #endif | 42 | #endif |
49 | lua_getglobal(L, LUASOCKET_LIBNAME); | 43 | luaL_openlib(L, LUASOCKET_LIBNAME, func, 1); |
50 | lua_pushstring(L, "_select"); | ||
51 | lua_gettable(L, -2); | ||
52 | lua_pushcclosure(L, select_lua_select, 1); | ||
53 | priv_newglobal(L, "select"); | ||
54 | lua_pop(L, 1); | 44 | lua_pop(L, 1); |
55 | /* create luasocket(select) table */ | 45 | aux_newclass(L, "select{fd_set}", set); |
56 | lua_pushstring(L, "luasocket(select)"); | ||
57 | lua_newtable(L); | ||
58 | lua_settable(L, LUA_REGISTRYINDEX); | ||
59 | } | 46 | } |
60 | 47 | ||
61 | /*-------------------------------------------------------------------------*\ | 48 | /*-------------------------------------------------------------------------*\ |
62 | * Waits for a set of sockets until a condition is met or timeout. | 49 | * Waits for a set of sockets until a condition is met or timeout. |
63 | * Lua Input: {input}, {output} [, timeout] | ||
64 | * {input}: table of sockets to be tested for input | ||
65 | * {output}: table of sockets to be tested for output | ||
66 | * timeout: maximum amount of time to wait for condition, in seconds | ||
67 | * Lua Returns: {input}, {output}, err | ||
68 | * {input}: table with sockets ready for input | ||
69 | * {output}: table with sockets ready for output | ||
70 | * err: "timeout" or nil | ||
71 | \*-------------------------------------------------------------------------*/ | 50 | \*-------------------------------------------------------------------------*/ |
72 | static int select_lua_select(lua_State *L) | 51 | static int global_select(lua_State *L) |
73 | { | 52 | { |
74 | fd_set read, write; | 53 | fd_set *read_fd_set, *write_fd_set; |
75 | FD_ZERO(&read); | ||
76 | FD_ZERO(&write); | ||
77 | /* push select lua auxiliar function */ | ||
78 | lua_pushvalue(L, lua_upvalueindex(1)); lua_insert(L, 1); | ||
79 | /* make sure we have enough arguments (nil is the default) */ | 54 | /* make sure we have enough arguments (nil is the default) */ |
80 | lua_settop(L, 4); | 55 | lua_settop(L, 3); |
81 | /* pass FD_SET and manipulation functions */ | 56 | /* check object tables */ |
82 | lua_boxpointer(L, &read); | 57 | check_obj_tab(L, 1); |
83 | lua_boxpointer(L, &write); | 58 | check_obj_tab(L, 2); |
84 | lua_pushcfunction(L, local_FD_SET); | 59 | /* check timeout */ |
85 | lua_pushcfunction(L, local_FD_ISSET); | 60 | if (!lua_isnil(L, 3) && !lua_isnumber(L, 3)) |
86 | /* pass getfd function with selectable table as upvalue */ | 61 | luaL_argerror(L, 3, "number or nil expected"); |
87 | lua_pushstring(L, "luasocket(select)"); lua_gettable(L, LUA_REGISTRYINDEX); | 62 | /* select auxiliar lua function to be called comes first */ |
88 | lua_pushcclosure(L, local_getfd, 1); | 63 | lua_pushvalue(L, lua_upvalueindex(1)); |
89 | /* pass pending function */ | 64 | lua_insert(L, 1); |
90 | lua_pushstring(L, "luasocket(select)"); lua_gettable(L, LUA_REGISTRYINDEX); | 65 | /* pass fd_set objects */ |
91 | lua_pushcclosure(L, local_pending, 1); | 66 | read_fd_set = lua_newuserdata(L, sizeof(fd_set)); |
67 | FD_ZERO(read_fd_set); | ||
68 | aux_setclass(L, "select{fd_set}", -1); | ||
69 | write_fd_set = lua_newuserdata(L, sizeof(fd_set)); | ||
70 | FD_ZERO(write_fd_set); | ||
71 | aux_setclass(L, "select{fd_set}", -1); | ||
92 | /* pass select auxiliar C function */ | 72 | /* pass select auxiliar C function */ |
93 | lua_pushcfunction(L, local_select); | 73 | lua_pushcfunction(L, c_select); |
94 | /* call select auxiliar lua function */ | 74 | /* call select auxiliar lua function */ |
95 | lua_call(L, 10, 3); | 75 | lua_call(L, 6, 3); |
96 | return 3; | 76 | return 3; |
97 | } | 77 | } |
98 | 78 | ||
99 | static int local_getfd(lua_State *L) | 79 | static int c_select(lua_State *L) |
100 | { | ||
101 | priv_pushclass(L, 1); | ||
102 | lua_gettable(L, lua_upvalueindex(1)); | ||
103 | if (!lua_isnil(L, -1)) { | ||
104 | p_fd sock = (p_fd) lua_touserdata(L, 1); | ||
105 | lua_pushnumber(L, sock->fd); | ||
106 | } | ||
107 | return 1; | ||
108 | } | ||
109 | |||
110 | static int local_pending(lua_State *L) | ||
111 | { | ||
112 | priv_pushclass(L, 1); | ||
113 | lua_gettable(L, lua_upvalueindex(1)); | ||
114 | if (!lua_isnil(L, -1)) { | ||
115 | p_fd sock = (p_fd) lua_touserdata(L, 1); | ||
116 | if (sock->fd_pending(L, sock)) lua_pushnumber(L, 1); | ||
117 | else lua_pushnil(L); | ||
118 | } | ||
119 | return 1; | ||
120 | } | ||
121 | |||
122 | static int local_select(lua_State *L) | ||
123 | { | 80 | { |
124 | int max_fd = (int) lua_tonumber(L, 1); | 81 | int max_fd = (int) lua_tonumber(L, 1); |
125 | fd_set *read_set = (fd_set *) lua_touserdata(L, 2); | 82 | fd_set *read_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 2); |
126 | fd_set *write_set = (fd_set *) lua_touserdata(L, 3); | 83 | fd_set *write_fd_set = (fd_set *) aux_checkclass(L, "select{fd_set}", 3); |
127 | int deadline = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000); | 84 | int timeout = lua_isnil(L, 4) ? -1 : (int)(lua_tonumber(L, 4) * 1000); |
128 | struct timeval tv; | 85 | struct timeval tv; |
129 | if (deadline >= 0) { | 86 | tv.tv_sec = timeout / 1000; |
130 | tv.tv_sec = deadline / 1000; | 87 | tv.tv_usec = (timeout % 1000) * 1000; |
131 | tv.tv_usec = (deadline % 1000) * 1000; | 88 | lua_pushnumber(L, select(max_fd, read_fd_set, write_fd_set, NULL, |
132 | lua_pushnumber(L, select(max_fd, read_set, write_set, NULL, &tv)); | 89 | timeout < 0 ? NULL : &tv)); |
133 | } else { | ||
134 | lua_pushnumber(L, select(max_fd, read_set, write_set, NULL, NULL)); | ||
135 | } | ||
136 | return 1; | 90 | return 1; |
137 | } | 91 | } |
138 | 92 | ||
139 | static int local_FD_SET(lua_State *L) | 93 | static int meth_set(lua_State *L) |
140 | { | 94 | { |
141 | COMPAT_FD fd = (COMPAT_FD) lua_tonumber(L, 1); | 95 | fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1); |
142 | fd_set *set = (fd_set *) lua_topointer(L, 2); | 96 | t_sock fd = (t_sock) lua_tonumber(L, 2); |
143 | if (fd >= 0) FD_SET(fd, set); | 97 | if (fd >= 0) FD_SET(fd, set); |
144 | return 0; | 98 | return 0; |
145 | } | 99 | } |
146 | 100 | ||
147 | static int local_FD_ISSET(lua_State *L) | 101 | static int meth_isset(lua_State *L) |
148 | { | 102 | { |
149 | COMPAT_FD fd = (COMPAT_FD) lua_tonumber(L, 1); | 103 | fd_set *set = (fd_set *) aux_checkclass(L, "select{fd_set}", 1); |
150 | fd_set *set = (fd_set *) lua_topointer(L, 2); | 104 | t_sock fd = (t_sock) lua_tonumber(L, 2); |
151 | if (fd >= 0 && FD_ISSET(fd, set)) lua_pushnumber(L, 1); | 105 | if (fd >= 0 && FD_ISSET(fd, set)) lua_pushnumber(L, 1); |
152 | else lua_pushnil(L); | 106 | else lua_pushnil(L); |
153 | return 1; | 107 | return 1; |
154 | } | 108 | } |
109 | |||
110 | static void check_obj_tab(lua_State *L, int tabidx) | ||
111 | { | ||
112 | if (tabidx < 0) tabidx = lua_gettop(L) + tabidx + 1; | ||
113 | if (lua_istable(L, tabidx)) { | ||
114 | lua_pushnil(L); | ||
115 | while (lua_next(L, tabidx) != 0) { | ||
116 | if (aux_getgroupudata(L, "select{able}", -1) == NULL) { | ||
117 | char msg[45]; | ||
118 | if (lua_isnumber(L, -2)) | ||
119 | sprintf(msg, "table entry #%g is invalid", | ||
120 | lua_tonumber(L, -2)); | ||
121 | else | ||
122 | sprintf(msg, "invalid entry found in table"); | ||
123 | luaL_argerror(L, tabidx, msg); | ||
124 | } | ||
125 | lua_pop(L, 1); | ||
126 | } | ||
127 | } else if (!lua_isnil(L, tabidx)) | ||
128 | luaL_argerror(L, tabidx, "table or nil expected"); | ||
129 | } | ||