uloop: add support for user defined signal handlers
[project/libubox.git] / lua / uloop.c
1 /*
2 * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20
21 #include <lua.h>
22 #include <lualib.h>
23 #include <lauxlib.h>
24
25 #include "../uloop.h"
26 #include "../list.h"
27
28 struct lua_uloop_fd {
29 struct uloop_fd fd;
30 int r;
31 int fd_r;
32 };
33
34 struct lua_uloop_timeout {
35 struct uloop_timeout t;
36 int r;
37 };
38
39 struct lua_uloop_process {
40 struct uloop_process p;
41 int r;
42 };
43
44 struct lua_uloop_interval {
45 struct uloop_interval i;
46 int r;
47 };
48
49 struct lua_uloop_signal {
50 struct uloop_signal s;
51 int r;
52 };
53
54 static lua_State *state;
55
56 static void *
57 ul_create_userdata(lua_State *L, size_t size, const luaL_Reg *reg, lua_CFunction gc)
58 {
59 void *ret = lua_newuserdata(L, size);
60
61 memset(ret, 0, size);
62 lua_createtable(L, 0, 2);
63 lua_pushvalue(L, -1);
64 lua_setfield(L, -2, "__index");
65 lua_pushcfunction(L, gc);
66 lua_setfield(L, -2, "__gc");
67 lua_pushvalue(L, -1);
68 lua_setmetatable(L, -3);
69 lua_pushvalue(L, -2);
70 luaI_openlib(L, NULL, reg, 1);
71 lua_pushvalue(L, -2);
72
73 return ret;
74 }
75
76 static void ul_timer_cb(struct uloop_timeout *t)
77 {
78 struct lua_uloop_timeout *tout = container_of(t, struct lua_uloop_timeout, t);
79
80 lua_getglobal(state, "__uloop_cb");
81 lua_rawgeti(state, -1, tout->r);
82 lua_remove(state, -2);
83
84 lua_call(state, 0, 0);
85
86 }
87
88 static int ul_timer_set(lua_State *L)
89 {
90 struct lua_uloop_timeout *tout;
91 double set;
92
93 if (!lua_isnumber(L, -1)) {
94 lua_pushstring(L, "invalid arg list");
95 lua_error(L);
96
97 return 0;
98 }
99
100 set = lua_tointeger(L, -1);
101 tout = lua_touserdata(L, 1);
102 uloop_timeout_set(&tout->t, set);
103
104 return 1;
105 }
106
107 static int ul_timer_remaining(lua_State *L)
108 {
109 struct lua_uloop_timeout *tout;
110
111 tout = lua_touserdata(L, 1);
112 lua_pushnumber(L, uloop_timeout_remaining64(&tout->t));
113 return 1;
114 }
115
116 static int ul_timer_free(lua_State *L)
117 {
118 struct lua_uloop_timeout *tout = lua_touserdata(L, 1);
119
120 uloop_timeout_cancel(&tout->t);
121
122 /* obj.__index.__gc = nil , make sure executing only once*/
123 lua_getfield(L, -1, "__index");
124 lua_pushstring(L, "__gc");
125 lua_pushnil(L);
126 lua_settable(L, -3);
127
128 lua_getglobal(state, "__uloop_cb");
129 luaL_unref(state, -1, tout->r);
130
131 return 1;
132 }
133
134 static const luaL_Reg timer_m[] = {
135 { "set", ul_timer_set },
136 { "remaining", ul_timer_remaining },
137 { "cancel", ul_timer_free },
138 { NULL, NULL }
139 };
140
141 static int ul_timer(lua_State *L)
142 {
143 struct lua_uloop_timeout *tout;
144 int set = 0;
145 int ref;
146
147 if (lua_isnumber(L, -1)) {
148 set = lua_tointeger(L, -1);
149 lua_pop(L, 1);
150 }
151
152 if (!lua_isfunction(L, -1)) {
153 lua_pushstring(L, "invalid arg list");
154 lua_error(L);
155
156 return 0;
157 }
158
159 lua_getglobal(L, "__uloop_cb");
160 lua_pushvalue(L, -2);
161 ref = luaL_ref(L, -2);
162
163 tout = ul_create_userdata(L, sizeof(*tout), timer_m, ul_timer_free);
164 tout->r = ref;
165 tout->t.cb = ul_timer_cb;
166
167 if (set)
168 uloop_timeout_set(&tout->t, set);
169
170 return 1;
171 }
172
173 static void ul_ufd_cb(struct uloop_fd *fd, unsigned int events)
174 {
175 struct lua_uloop_fd *ufd = container_of(fd, struct lua_uloop_fd, fd);
176
177 lua_getglobal(state, "__uloop_cb");
178 lua_rawgeti(state, -1, ufd->r);
179 lua_remove(state, -2);
180
181 /* push fd object */
182 lua_getglobal(state, "__uloop_fds");
183 lua_rawgeti(state, -1, ufd->fd_r);
184 lua_remove(state, -2);
185
186 /* push events */
187 lua_pushinteger(state, events);
188 lua_call(state, 2, 0);
189 }
190
191
192 static int get_sock_fd(lua_State* L, int idx) {
193 int fd;
194 if(lua_isnumber(L, idx)) {
195 fd = lua_tonumber(L, idx);
196 } else {
197 luaL_checktype(L, idx, LUA_TUSERDATA);
198 lua_getfield(L, idx, "getfd");
199 if(lua_isnil(L, -1))
200 return luaL_error(L, "socket type missing 'getfd' method");
201 /* if we have absolute, no need to adjust for getfield() call */
202 lua_pushvalue(L, idx > 0 ? idx: idx - 1);
203 lua_call(L, 1, 1);
204 fd = lua_tointeger(L, -1);
205 lua_pop(L, 1);
206 }
207 return fd;
208 }
209
210 static int ul_ufd_delete(lua_State *L)
211 {
212 struct lua_uloop_fd *ufd = lua_touserdata(L, 1);
213
214 uloop_fd_delete(&ufd->fd);
215
216 /* obj.__index.__gc = nil , make sure executing only once*/
217 lua_getfield(L, -1, "__index");
218 lua_pushstring(L, "__gc");
219 lua_pushnil(L);
220 lua_settable(L, -3);
221
222 lua_getglobal(state, "__uloop_cb");
223 luaL_unref(state, -1, ufd->r);
224 lua_remove(state, -1);
225
226 lua_getglobal(state, "__uloop_fds");
227 luaL_unref(state, -1, ufd->fd_r);
228 lua_remove(state, -1);
229
230 return 1;
231 }
232
233 static const luaL_Reg ufd_m[] = {
234 { "delete", ul_ufd_delete },
235 { NULL, NULL }
236 };
237
238 static int ul_ufd_add(lua_State *L)
239 {
240 struct lua_uloop_fd *ufd;
241 int fd = 0;
242 unsigned int flags = 0;
243 int ref;
244 int fd_ref;
245
246 flags = luaL_checkinteger(L, 3);
247 if (!flags) {
248 lua_pushstring(L, "flags cannot be zero");
249 lua_error(L);
250 }
251
252 luaL_checktype(L, 2, LUA_TFUNCTION);
253
254 fd = get_sock_fd(L, 1);
255
256 lua_getglobal(L, "__uloop_cb");
257 lua_pushvalue(L, 2);
258 ref = luaL_ref(L, -2);
259 lua_pop(L, 1);
260
261 lua_getglobal(L, "__uloop_fds");
262 lua_pushvalue(L, 1);
263 fd_ref = luaL_ref(L, -2);
264 lua_pop(L, 1);
265
266 ufd = ul_create_userdata(L, sizeof(*ufd), ufd_m, ul_ufd_delete);
267 ufd->r = ref;
268 ufd->fd.fd = fd;
269 ufd->fd_r = fd_ref;
270 ufd->fd.cb = ul_ufd_cb;
271 uloop_fd_add(&ufd->fd, flags);
272
273 return 1;
274 }
275
276 static int ul_process_free(lua_State *L)
277 {
278 struct lua_uloop_process *proc = lua_touserdata(L, 1);
279
280 /* obj.__index.__gc = nil , make sure executing only once*/
281 lua_getfield(L, -1, "__index");
282 lua_pushstring(L, "__gc");
283 lua_pushnil(L);
284 lua_settable(L, -3);
285
286 if (proc->r != LUA_NOREF) {
287 uloop_process_delete(&proc->p);
288
289 lua_getglobal(state, "__uloop_cb");
290 luaL_unref(state, -1, proc->r);
291 lua_remove(state, -1);
292 }
293
294 return 1;
295 }
296
297 static int ul_process_pid(lua_State *L)
298 {
299 struct lua_uloop_process *proc = lua_touserdata(L, 1);
300
301 if (proc->p.pid) {
302 lua_pushnumber(L, proc->p.pid);
303 return 1;
304 }
305
306 return 0;
307 }
308
309 static const luaL_Reg process_m[] = {
310 { "delete", ul_process_free },
311 { "pid", ul_process_pid },
312 { NULL, NULL }
313 };
314
315 static void ul_process_cb(struct uloop_process *p, int ret)
316 {
317 struct lua_uloop_process *proc = container_of(p, struct lua_uloop_process, p);
318
319 lua_getglobal(state, "__uloop_cb");
320 lua_rawgeti(state, -1, proc->r);
321
322 luaL_unref(state, -2, proc->r);
323 proc->r = LUA_NOREF;
324 lua_remove(state, -2);
325 lua_pushinteger(state, ret >> 8);
326 lua_call(state, 1, 0);
327 }
328
329 static int ul_process(lua_State *L)
330 {
331 struct lua_uloop_process *proc;
332 pid_t pid;
333 int ref;
334
335 if (!lua_isfunction(L, -1) || !lua_istable(L, -2) ||
336 !lua_istable(L, -3) || !lua_isstring(L, -4)) {
337 lua_pushstring(L, "invalid arg list");
338 lua_error(L);
339
340 return 0;
341 }
342
343 pid = fork();
344
345 if (pid == -1) {
346 lua_pushstring(L, "failed to fork");
347 lua_error(L);
348
349 return 0;
350 }
351
352 if (pid == 0) {
353 /* child */
354 int argn = lua_objlen(L, -3);
355 int envn = lua_objlen(L, -2);
356 char** argp = malloc(sizeof(char*) * (argn + 2));
357 char** envp = malloc(sizeof(char*) * (envn + 1));
358 int i = 1;
359
360 if (!argp || !envp)
361 _exit(-1);
362
363 argp[0] = (char*) lua_tostring(L, -4);
364 for (i = 1; i <= argn; i++) {
365 lua_rawgeti(L, -3, i);
366 argp[i] = (char*) lua_tostring(L, -1);
367 lua_pop(L, 1);
368 }
369 argp[i] = NULL;
370
371 for (i = 1; i <= envn; i++) {
372 lua_rawgeti(L, -2, i);
373 envp[i - 1] = (char*) lua_tostring(L, -1);
374 lua_pop(L, 1);
375 }
376 envp[i - 1] = NULL;
377
378 execve(*argp, argp, envp);
379 _exit(-1);
380 }
381
382 lua_getglobal(L, "__uloop_cb");
383 lua_pushvalue(L, -2);
384 ref = luaL_ref(L, -2);
385
386 proc = ul_create_userdata(L, sizeof(*proc), process_m, ul_process_free);
387 proc->r = ref;
388 proc->p.pid = pid;
389 proc->p.cb = ul_process_cb;
390 uloop_process_add(&proc->p);
391
392 return 1;
393 }
394
395 static void ul_interval_cb(struct uloop_interval *i)
396 {
397 struct lua_uloop_interval *intv = container_of(i, struct lua_uloop_interval, i);
398
399 lua_getglobal(state, "__uloop_cb");
400 lua_rawgeti(state, -1, intv->r);
401 lua_remove(state, -2);
402
403 lua_call(state, 0, 0);
404 }
405
406 static int ul_interval_set(lua_State *L)
407 {
408 struct lua_uloop_interval *intv;
409 double set;
410
411 if (!lua_isnumber(L, -1)) {
412 lua_pushstring(L, "invalid arg list");
413 lua_error(L);
414
415 return 0;
416 }
417
418 set = lua_tointeger(L, -1);
419 intv = lua_touserdata(L, 1);
420 uloop_interval_set(&intv->i, set);
421
422 return 1;
423 }
424
425 static int ul_interval_expirations(lua_State *L)
426 {
427 struct lua_uloop_interval *intv;
428
429 intv = lua_touserdata(L, 1);
430 lua_pushinteger(L, intv->i.expirations);
431 return 1;
432 }
433
434 static int ul_interval_remaining(lua_State *L)
435 {
436 struct lua_uloop_interval *intv;
437
438 intv = lua_touserdata(L, 1);
439 lua_pushnumber(L, uloop_interval_remaining(&intv->i));
440 return 1;
441 }
442
443 static int ul_interval_free(lua_State *L)
444 {
445 struct lua_uloop_interval *intv = lua_touserdata(L, 1);
446
447 uloop_interval_cancel(&intv->i);
448
449 /* obj.__index.__gc = nil , make sure executing only once*/
450 lua_getfield(L, -1, "__index");
451 lua_pushstring(L, "__gc");
452 lua_pushnil(L);
453 lua_settable(L, -3);
454
455 lua_getglobal(state, "__uloop_cb");
456 luaL_unref(state, -1, intv->r);
457
458 return 1;
459 }
460
461 static const luaL_Reg interval_m[] = {
462 { "set", ul_interval_set },
463 { "expirations", ul_interval_expirations },
464 { "remaining", ul_interval_remaining },
465 { "cancel", ul_interval_free },
466 { NULL, NULL }
467 };
468
469 static int ul_interval(lua_State *L)
470 {
471 struct lua_uloop_interval *intv;
472 unsigned int set = 0;
473 int ref;
474
475 if (lua_isnumber(L, -1)) {
476 set = lua_tointeger(L, -1);
477 lua_pop(L, 1);
478 }
479
480 if (!lua_isfunction(L, -1)) {
481 lua_pushstring(L, "invalid arg list");
482 lua_error(L);
483
484 return 0;
485 }
486
487 lua_getglobal(L, "__uloop_cb");
488 lua_pushvalue(L, -2);
489 ref = luaL_ref(L, -2);
490
491 intv = ul_create_userdata(L, sizeof(*intv), interval_m, ul_interval_free);
492 intv->r = ref;
493 intv->i.cb = ul_interval_cb;
494
495 if (set)
496 uloop_interval_set(&intv->i, set);
497
498 return 1;
499 }
500
501 static void ul_signal_cb(struct uloop_signal *s)
502 {
503 struct lua_uloop_signal *sig = container_of(s, struct lua_uloop_signal, s);
504
505 lua_getglobal(state, "__uloop_cb");
506 lua_rawgeti(state, -1, sig->r);
507 lua_remove(state, -2);
508 lua_pushinteger(state, sig->s.signo);
509
510 lua_call(state, 1, 0);
511 }
512
513 static int ul_signal_signo(lua_State *L)
514 {
515 struct lua_uloop_signal *sig = lua_touserdata(L, 1);
516
517 lua_pushinteger(L, sig->s.signo);
518
519 return 1;
520 }
521
522 static int ul_signal_free(lua_State *L)
523 {
524 struct lua_uloop_signal *sig = lua_touserdata(L, 1);
525
526 uloop_signal_delete(&sig->s);
527
528 /* obj.__index.__gc = nil , make sure executing only once*/
529 lua_getfield(L, -1, "__index");
530 lua_pushstring(L, "__gc");
531 lua_pushnil(L);
532 lua_settable(L, -3);
533
534 lua_getglobal(state, "__uloop_cb");
535 luaL_unref(state, -1, sig->r);
536
537 return 1;
538 }
539
540 static const luaL_Reg signal_m[] = {
541 { "signo", ul_signal_signo },
542 { "delete", ul_signal_free },
543 { NULL, NULL }
544 };
545
546 static int ul_signal(lua_State *L)
547 {
548 struct lua_uloop_signal *sig;
549 int signo = -1;
550 int ref;
551
552 if (lua_isnumber(L, -1)) {
553 signo = lua_tointeger(L, -1);
554 lua_pop(L, 1);
555 }
556
557 if (!lua_isfunction(L, -1) || signo <= 0 || signo > NSIG) {
558 lua_pushstring(L, "invalid arg list");
559 lua_error(L);
560
561 return 0;
562 }
563
564 lua_getglobal(L, "__uloop_cb");
565 lua_pushvalue(L, -2);
566 ref = luaL_ref(L, -2);
567
568 sig = ul_create_userdata(L, sizeof(*sig), signal_m, ul_signal_free);
569 sig->r = ref;
570 sig->s.cb = ul_signal_cb;
571 sig->s.signo = signo;
572
573 uloop_signal_add(&sig->s);
574
575 return 1;
576 }
577
578 static int ul_init(lua_State *L)
579 {
580 uloop_init();
581 lua_pushboolean(L, 1);
582
583 return 1;
584 }
585
586 static int ul_run(lua_State *L)
587 {
588 uloop_run();
589 lua_pushboolean(L, 1);
590
591 return 1;
592 }
593
594 static int ul_end(lua_State *L)
595 {
596 uloop_end();
597 return 1;
598 }
599
600 static luaL_reg uloop_func[] = {
601 {"init", ul_init},
602 {"run", ul_run},
603 {"timer", ul_timer},
604 {"process", ul_process},
605 {"fd_add", ul_ufd_add},
606 {"interval", ul_interval},
607 {"signal", ul_signal},
608 {"cancel", ul_end},
609 {NULL, NULL},
610 };
611
612 /* avoid warnings about missing declarations */
613 int luaopen_uloop(lua_State *L);
614 int luaclose_uloop(lua_State *L);
615
616 int luaopen_uloop(lua_State *L)
617 {
618 state = L;
619
620 lua_createtable(L, 1, 0);
621 lua_setglobal(L, "__uloop_cb");
622
623 lua_createtable(L, 1, 0);
624 lua_setglobal(L, "__uloop_fds");
625
626 luaL_openlib(L, "uloop", uloop_func, 0);
627 lua_pushstring(L, "_VERSION");
628 lua_pushstring(L, "1.0");
629 lua_rawset(L, -3);
630
631 lua_pushstring(L, "ULOOP_READ");
632 lua_pushinteger(L, ULOOP_READ);
633 lua_rawset(L, -3);
634
635 lua_pushstring(L, "ULOOP_WRITE");
636 lua_pushinteger(L, ULOOP_WRITE);
637 lua_rawset(L, -3);
638
639 lua_pushstring(L, "ULOOP_EDGE_TRIGGER");
640 lua_pushinteger(L, ULOOP_EDGE_TRIGGER);
641 lua_rawset(L, -3);
642
643 lua_pushstring(L, "ULOOP_BLOCKING");
644 lua_pushinteger(L, ULOOP_BLOCKING);
645 lua_rawset(L, -3);
646
647 #define SIGNAME_CONST(signame) do { \
648 lua_pushstring(L, #signame); \
649 lua_pushinteger(L, signame); \
650 lua_rawset(L, -3); \
651 } while(0)
652
653 #if defined(SIGINT)
654 SIGNAME_CONST(SIGINT);
655 #endif
656 #if defined(SIGILL)
657 SIGNAME_CONST(SIGILL);
658 #endif
659 #if defined(SIGABRT)
660 SIGNAME_CONST(SIGABRT);
661 #endif
662 #if defined(SIGFPE)
663 SIGNAME_CONST(SIGFPE);
664 #endif
665 #if defined(SIGSEGV)
666 SIGNAME_CONST(SIGSEGV);
667 #endif
668 #if defined(SIGTERM)
669 SIGNAME_CONST(SIGTERM);
670 #endif
671 #if defined(SIGHUP)
672 SIGNAME_CONST(SIGHUP);
673 #endif
674 #if defined(SIGQUIT)
675 SIGNAME_CONST(SIGQUIT);
676 #endif
677 #if defined(SIGTRAP)
678 SIGNAME_CONST(SIGTRAP);
679 #endif
680 #if defined(SIGKILL)
681 SIGNAME_CONST(SIGKILL);
682 #endif
683 #if defined(SIGPIPE)
684 SIGNAME_CONST(SIGPIPE);
685 #endif
686 #if defined(SIGALRM)
687 SIGNAME_CONST(SIGALRM);
688 #endif
689 #if defined(SIGSTKFLT)
690 SIGNAME_CONST(SIGSTKFLT);
691 #endif
692 #if defined(SIGPWR)
693 SIGNAME_CONST(SIGPWR);
694 #endif
695 #if defined(SIGBUS)
696 SIGNAME_CONST(SIGBUS);
697 #endif
698 #if defined(SIGSYS)
699 SIGNAME_CONST(SIGSYS);
700 #endif
701 #if defined(SIGURG)
702 SIGNAME_CONST(SIGURG);
703 #endif
704 #if defined(SIGSTOP)
705 SIGNAME_CONST(SIGSTOP);
706 #endif
707 #if defined(SIGTSTP)
708 SIGNAME_CONST(SIGTSTP);
709 #endif
710 #if defined(SIGCONT)
711 SIGNAME_CONST(SIGCONT);
712 #endif
713 #if defined(SIGCHLD)
714 SIGNAME_CONST(SIGCHLD);
715 #endif
716 #if defined(SIGTTIN)
717 SIGNAME_CONST(SIGTTIN);
718 #endif
719 #if defined(SIGTTOU)
720 SIGNAME_CONST(SIGTTOU);
721 #endif
722 #if defined(SIGPOLL)
723 SIGNAME_CONST(SIGPOLL);
724 #endif
725 #if defined(SIGXFSZ)
726 SIGNAME_CONST(SIGXFSZ);
727 #endif
728 #if defined(SIGXCPU)
729 SIGNAME_CONST(SIGXCPU);
730 #endif
731 #if defined(SIGVTALRM)
732 SIGNAME_CONST(SIGVTALRM);
733 #endif
734 #if defined(SIGPROF)
735 SIGNAME_CONST(SIGPROF);
736 #endif
737 #if defined(SIGUSR1)
738 SIGNAME_CONST(SIGUSR1);
739 #endif
740 #if defined(SIGUSR2)
741 SIGNAME_CONST(SIGUSR2);
742 #endif
743
744 return 1;
745 }
746
747 int luaclose_uloop(lua_State *L)
748 {
749 lua_pushstring(L, "Called");
750
751 return 1;
752 }