moonbridge

view moonbridge_io.c @ 81:e1aec772a6ab

Implementation of write, write_nb, flush, flush_nb with double buffering technique
author jbe
date Mon Apr 06 03:36:37 2015 +0200 (2015-04-06)
parents 1a0346580e6d
children 069ee3f5ab17
line source
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <stdint.h>
5 #include <errno.h>
6 #include <string.h>
7 #include <stdio.h>
8 #include <time.h>
9 #include <sys/time.h>
10 #include <sys/socket.h>
11 #include <sys/select.h>
12 #include <fcntl.h>
14 #include <lua.h>
15 #include <lauxlib.h>
16 #include <lualib.h>
18 #define MOONBR_IO_MAXSTRERRORLEN 80
19 #define MOONBR_IO_WRITEBUFLEN 4096
21 #define moonbr_io_errmsg() \
22 char errmsg[MOONBR_IO_MAXSTRERRORLEN]; \
23 strerror_r(errno, errmsg, MOONBR_IO_MAXSTRERRORLEN)
26 #define MOONBR_IO_HANDLE_MT_REGKEY "moonbridge_io_handle"
27 #define MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY "moonbridge_io_handle_public"
29 typedef struct {
30 int fd;
31 int nonblocking;
32 int writeerr;
33 int writeleft;
34 int writeqoff;
35 int writebufcnt;
36 char writebuf[MOONBR_IO_WRITEBUFLEN];
37 } moonbr_io_handle_t;
39 static void moonbr_io_handle_set_nonblocking(lua_State *L, moonbr_io_handle_t *handle, int nonblocking) {
40 if (handle->nonblocking != nonblocking) {
41 int flags;
42 flags = fcntl(handle->fd, F_GETFL, 0);
43 if (flags == -1) {
44 moonbr_io_errmsg();
45 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
46 }
47 if (nonblocking) flags |= O_NONBLOCK;
48 else flags &= ~O_NONBLOCK;
49 if (fcntl(handle->fd, F_SETFL, flags) == -1) {
50 moonbr_io_errmsg();
51 luaL_error(L, "Unexpected error in fcntl call: %s", errmsg);
52 }
53 }
54 }
56 static int moonbr_io_close(lua_State *L) {
57 moonbr_io_handle_t *handle;
58 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
59 if (handle->fd < 0) luaL_error(L, "Attempt to close a closed I/O handle");
60 if (close(handle->fd)) {
61 handle->fd = -1;
62 moonbr_io_errmsg();
63 lua_pushnil(L);
64 lua_pushstring(L, errmsg);
65 return 2;
66 }
67 handle->fd = -1;
68 lua_pushboolean(L, 1);
69 return 1;
70 }
72 static int moonbr_io_write_impl(lua_State *L, int nonblocking, int flush) {
73 moonbr_io_handle_t *handle;
74 int i, top;
75 lua_Integer qlen, qpos, qpos2;
76 const char *str;
77 size_t strlen, strpos;
78 size_t written;
79 ssize_t result;
80 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
81 if (handle->writeerr) {
82 lua_pushnil(L);
83 lua_pushliteral(L, "Previous write error");
84 return 2;
85 }
86 moonbr_io_handle_set_nonblocking(L, handle, nonblocking);
87 if (!flush) top = lua_gettop(L);
88 lua_getuservalue(L, 1);
89 lua_getfield(L, -1, "writebuf");
90 qlen = lua_rawlen(L, -1);
91 if (!flush) {
92 for (i=2; i<=top; i++) {
93 luaL_checklstring(L, i, &strlen);
94 lua_pushvalue(L, i);
95 lua_rawseti(L, -2, ++qlen);
96 handle->writeleft += strlen;
97 }
98 }
99 for (qpos=1; qpos<=qlen; qpos++) {
100 lua_rawgeti(L, -1, qpos);
101 str = lua_tolstring(L, -1, &strlen);
102 strpos = handle->writeqoff;
103 while (strpos < strlen) {
104 if (strlen - strpos < MOONBR_IO_WRITEBUFLEN - handle->writebufcnt) {
105 memcpy(handle->writebuf + handle->writebufcnt, str + strpos, strlen - strpos);
106 handle->writebufcnt += strlen - strpos;
107 break;
108 } else {
109 written = 0;
110 memcpy(handle->writebuf + handle->writebufcnt, str + strpos, MOONBR_IO_WRITEBUFLEN - handle->writebufcnt);
111 strpos += MOONBR_IO_WRITEBUFLEN - handle->writebufcnt;
112 while (written < MOONBR_IO_WRITEBUFLEN) {
113 result = write(handle->fd, handle->writebuf + written, MOONBR_IO_WRITEBUFLEN - written);
114 if (result < 0) {
115 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
116 if (written) {
117 handle->writebufcnt -= written;
118 memmove(handle->writebuf, handle->writebuf + written, handle->writebufcnt);
119 }
120 if (i > 1) {
121 for (qpos2=1; qpos2<=qlen; qpos2++) {
122 if (qpos2+qpos-1 <= qlen) lua_rawgeti(L, -1, qpos2+qpos-1);
123 else lua_pushnil(L);
124 lua_rawseti(L, -2, qpos2);
125 }
126 }
127 handle->writeqoff = strpos;
128 goto moonbr_io_write_impl_block;
129 } else if (errno != EINTR) {
130 moonbr_io_errmsg();
131 handle->writeerr = 1;
132 lua_pushnil(L);
133 lua_pushstring(L, errmsg);
134 return 2;
135 }
136 } else {
137 written += result;
138 handle->writeleft -= result;
139 }
140 }
141 handle->writebufcnt = 0;
142 }
143 }
144 handle->writeqoff = 0;
145 lua_pop(L, 1);
146 lua_pushnil(L);
147 lua_rawseti(L, -2, qpos);
148 }
149 if (flush) {
150 written = 0;
151 while (written < handle->writebufcnt) {
152 result = write(handle->fd, handle->writebuf + written, handle->writebufcnt - written);
153 if (result < 0) {
154 if (nonblocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
155 if (written) {
156 handle->writebufcnt -= written;
157 memmove(handle->writebuf, handle->writebuf + written, handle->writebufcnt);
158 }
159 goto moonbr_io_write_impl_block;
160 } else if (errno != EINTR) {
161 moonbr_io_errmsg();
162 handle->writeerr = -1;
163 lua_pushnil(L);
164 lua_pushstring(L, errmsg);
165 return 2;
166 }
167 } else {
168 written += result;
169 handle->writeleft -= result;
170 }
171 }
172 handle->writebufcnt = 0;
173 lua_pushinteger(L, 0);
174 } else {
175 lua_pushinteger(L, handle->writeleft - handle->writebufcnt);
176 }
177 return 1;
178 moonbr_io_write_impl_block:
179 if (flush) lua_pushinteger(L, handle->writeleft);
180 else lua_pushinteger(L, handle->writeleft - handle->writebufcnt);
181 return 1;
182 }
184 static int moonbr_io_write(lua_State *L) {
185 return moonbr_io_write_impl(L, 0, 0);
186 }
188 static int moonbr_io_write_nb(lua_State *L) {
189 return moonbr_io_write_impl(L, 1, 0);
190 }
192 static int moonbr_io_flush(lua_State *L) {
193 return moonbr_io_write_impl(L, 0, 1);
194 }
196 static int moonbr_io_flush_nb(lua_State *L) {
197 return moonbr_io_write_impl(L, 1, 1);
198 }
200 void moonbr_io_pushhandle(lua_State *L, int fd, int gc_idx) {
201 moonbr_io_handle_t *handle;
202 handle = lua_newuserdata(L, sizeof(moonbr_io_handle_t));
203 handle->fd = fd;
204 handle->nonblocking = -1;
205 handle->writeerr = 0;
206 handle->writeleft = 0;
207 handle->writeqoff = 0;
208 handle->writebufcnt = 0;
209 luaL_getmetatable(L, MOONBR_IO_HANDLE_MT_REGKEY);
210 lua_setmetatable(L, -2);
211 lua_newtable(L); // uservalue
212 lua_newtable(L);
213 lua_setfield(L, -2, "writebuf");
214 if (gc_idx) lua_pushvalue(L, gc_idx);
215 else lua_pushcfunction(L, moonbr_io_close);
216 lua_setfield(L, -2, "gc");
217 lua_newtable(L); // public
218 luaL_getmetatable(L, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
219 lua_setmetatable(L, -2);
220 lua_setfield(L, -2, "public");
221 lua_setuservalue(L, -2);
222 }
224 static int moonbr_io_handleindex(lua_State *L) {
225 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
226 lua_getuservalue(L, 1);
227 lua_getfield(L, -1, "public");
228 lua_pushvalue(L, 2);
229 lua_gettable(L, -2);
230 return 1;
231 }
233 static int moonbr_io_handlenewindex(lua_State *L) {
234 luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
235 lua_getuservalue(L, 1);
236 lua_getfield(L, -1, "public");
237 lua_pushvalue(L, 2);
238 lua_pushvalue(L, 3);
239 lua_settable(L, -3);
240 return 0;
241 }
243 static int moonbr_io_handlegc(lua_State *L) {
244 moonbr_io_handle_t *handle;
245 handle = luaL_checkudata(L, 1, MOONBR_IO_HANDLE_MT_REGKEY);
246 if (handle->fd >= 0) {
247 lua_getuservalue(L, 1);
248 lua_getfield(L, -1, "gc");
249 lua_pushvalue(L, 1);
250 lua_call(L, 1, 0);
251 }
252 return 0;
253 }
255 static int moonbr_io_getdummy(lua_State *L) {
256 moonbr_io_pushhandle(L, 2, 0);
257 return 1;
258 }
260 static const struct luaL_Reg moonbr_io_handle_methods[] = {
261 {"close", moonbr_io_close},
262 {"write", moonbr_io_write},
263 {"write_nb", moonbr_io_write_nb},
264 {"flush", moonbr_io_flush},
265 {"flush_nb", moonbr_io_flush_nb},
266 {NULL, NULL}
267 };
269 static const struct luaL_Reg moonbr_io_handle_metamethods[] = {
270 {"__index", moonbr_io_handleindex},
271 {"__newindex", moonbr_io_handlenewindex},
272 {"__gc", moonbr_io_handlegc},
273 {NULL, NULL}
274 };
276 static const struct luaL_Reg moonbr_io_module_funcs[] = {
277 {"getdummy", moonbr_io_getdummy},
278 {NULL, NULL}
279 };
281 int luaopen_moonbridge_io(lua_State *L) {
283 lua_newtable(L); // module
285 lua_newtable(L); // public metatable
286 lua_newtable(L); // handle methods
287 luaL_setfuncs(L, moonbr_io_handle_methods, 0);
288 lua_pushvalue(L, -1);
289 lua_setfield(L, -4, "handle");
290 lua_setfield(L, -2, "__index");
291 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_PUBLIC_MT_REGKEY);
293 lua_newtable(L); // handle metatable
294 luaL_setfuncs(L, moonbr_io_handle_metamethods, 0);
295 lua_setfield(L, LUA_REGISTRYINDEX, MOONBR_IO_HANDLE_MT_REGKEY);
297 luaL_setfuncs(L, moonbr_io_module_funcs, 0);
298 return 1;
300 }

Impressum / About Us