Merge nixio 0.2
[project/luci.git] / libs / nixio / src / poll.c
1 /*
2  * nixio - Linux I/O library for lua
3  *
4  *   Copyright (C) 2009 Steven Barth <steven@midlink.org>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */
18
19 #include "nixio.h"
20 #include <time.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <stdlib.h>
24
25
26 /**
27  * nanosleep()
28  */
29 static int nixio_nanosleep(lua_State *L) {
30         struct timespec req, rem;
31         req.tv_sec = luaL_optint(L, 1, 0);
32         req.tv_nsec = luaL_optint(L, 2, 0);
33
34         int status = nanosleep(&req, &rem);
35         if (!status) {
36                 lua_pushboolean(L, 1);
37                 return 1;
38         } else {
39                 if (errno == EINTR) {
40                         lua_pushboolean(L, 0);
41                         lua_pushinteger(L, rem.tv_sec);
42                         lua_pushinteger(L, rem.tv_nsec);
43                         return 3;
44                 } else {
45                         return nixio__perror(L);
46                 }
47         }
48 }
49
50 /**
51  * Checks whether a flag is set in the bitmap and sets the matching table value
52  */
53 static void nixio_poll_flags__r(lua_State *L, int *map, int f, const char *t) {
54         lua_pushstring(L, t);
55         if (*map & f) {
56                 lua_pushboolean(L, 1);
57         } else {
58                 lua_pushnil(L);
59         }
60         lua_rawset(L, -3);
61 }
62
63 /**
64  * Translate integer to poll flags and vice versa
65  */
66 static int nixio_poll_flags(lua_State *L) {
67         int flags;
68         if (lua_isnumber(L, 1)) {
69                 flags = luaL_checkinteger(L, 1);
70                 lua_newtable(L);
71                 nixio_poll_flags__r(L, &flags, POLLIN, "in");
72                 nixio_poll_flags__r(L, &flags, POLLOUT, "out");
73                 nixio_poll_flags__r(L, &flags, POLLERR, "err");
74 #ifndef __WINNT__
75                 nixio_poll_flags__r(L, &flags, POLLPRI, "pri");
76                 nixio_poll_flags__r(L, &flags, POLLHUP, "hup");
77                 nixio_poll_flags__r(L, &flags, POLLNVAL, "nval");
78 #endif
79          } else {
80                 flags = 0;
81                 const int j = lua_gettop(L);
82                 for (int i=1; i<=j; i++) {
83                         const char *flag = luaL_checkstring(L, i);
84                         if (!strcmp(flag, "in")) {
85                                 flags |= POLLIN;
86                         } else if (!strcmp(flag, "out")) {
87                                 flags |= POLLOUT;
88                         } else if (!strcmp(flag, "err")) {
89                                 flags |= POLLERR;
90                         } else if (!strcmp(flag, "pri")) {
91 #ifndef __WINNT__
92                                 flags |= POLLPRI;
93 #endif
94                         } else if (!strcmp(flag, "hup")) {
95 #ifndef __WINNT__
96                                 flags |= POLLHUP;
97 #endif
98                         } else if (!strcmp(flag, "nval")) {
99 #ifndef __WINNT__
100                                 flags |= POLLNVAL;
101 #endif
102                         } else {
103                                 return luaL_argerror(L, i,
104                                  "supported values: in, pri, out, err, hup, nval");
105                         }
106                 }
107                 lua_pushinteger(L, flags);
108         }
109         return 1;
110 }
111
112 /**
113  * poll({{fd = socket, events = FLAGS}, ...}, timeout)
114  */
115 static int nixio_poll(lua_State *L) {
116         int len = lua_objlen(L, 1);
117         int i, fd;
118         int timeout = luaL_optint(L, 2, 0);
119         int status = -1;
120
121         /* we are being abused as sleep() replacement... */
122         if (lua_isnoneornil(L, 1) || len < 1) {
123                 if (!poll(NULL, 0, timeout)) {
124                         lua_pushinteger(L, 0);
125                         return 1;
126                 } else {
127                         return nixio__perror(L);
128                 }
129         }
130
131         luaL_checktype(L, 1, LUA_TTABLE);
132         struct pollfd *fds = calloc(len, sizeof(struct pollfd));
133         if (!fds) {
134                 return luaL_error(L, NIXIO_OOM);
135         }
136
137         for (i = 0; i < len; i++) {
138                 lua_rawgeti(L, 1, i+1);
139                 if (!lua_istable(L, -1)) {
140                         free(fds);
141                         return luaL_argerror(L, 1, "invalid datastructure");
142                 }
143
144                 lua_pushliteral(L, "fd");
145                 lua_rawget(L, -2);
146                 fd = nixio__tofd(L, -1);
147                 if (fd == -1) {
148                         free(fds);
149                         return luaL_argerror(L, 1, "invalid fd in datastructure");
150                 }
151                 fds[i].fd = fd;
152
153                 lua_pushliteral(L, "events");
154                 lua_rawget(L, -3);
155                 fds[i].events = (short)lua_tointeger(L, -1);
156
157                 lua_pop(L, 3);
158         }
159
160         status = poll(fds, (nfds_t)len, timeout);
161
162         if (status == 0) {
163                 free(fds);
164                 lua_pushboolean(L, 0);
165                 return 1;
166         } else if (status < 0) {
167                 free(fds);
168                 return nixio__perror(L);
169         }
170
171         for (i = 0; i < len; i++) {
172                 lua_rawgeti(L, 1, i+1);
173
174                 lua_pushliteral(L, "revents");
175                 lua_pushinteger(L, fds[i].revents);
176                 lua_rawset(L, -3);
177
178                 lua_pop(L, 1);
179         }
180
181         free(fds);
182
183         lua_pushinteger(L, status);
184         lua_pushvalue(L, 1);
185
186         return 2;
187 }
188
189 /* module table */
190 static const luaL_reg R[] = {
191         {"nanosleep",   nixio_nanosleep},
192         {"poll",                nixio_poll},
193         {"poll_flags",  nixio_poll_flags},
194         {NULL,                  NULL}
195 };
196
197 void nixio_open_poll(lua_State *L) {
198         luaL_register(L, NULL, R);
199 }