static DBusHandlerResult signal_handler(lua_State *S, DBusMessage *msg) { lua_State *T; const char *path = dbus_message_get_path(msg); const char *interface = dbus_message_get_interface(msg); const char *member = dbus_message_get_member(msg); lem_debug("received signal\n %s\n %s\n %s(%s)", path, interface, member, dbus_message_get_signature(msg)); /* NOTE: this magic string representation of an * incoming signal must match the one in the Lua code */ lua_pushfstring(S, "%s\n%s\n%s", path ? path : "", interface ? interface : "", member ? member : ""); lua_rawget(S, LEM_DBUS_SIGNAL_TABLE); if (lua_type(S, -1) != LUA_TFUNCTION) { lua_settop(S, LEM_DBUS_TOP); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } /* create new thread */ T = lem_newthread(); lua_xmove(S, T, 1); lem_queue(T, lem_dbus_push_arguments(T, msg)); return DBUS_HANDLER_RESULT_HANDLED; }
static int queue_file(int argc, char *argv[], int fidx) { lua_State *T = lem_newthread(); const char *filename; int i; if (fidx < argc) filename = argv[fidx]; else filename = LEM_LDIR "lem/repl.lua"; switch (luaL_loadfile(T, filename)) { case LUA_OK: /* success */ break; case LUA_ERRMEM: oom(); default: lem_log_error("lem: %s", lua_tostring(T, 1)); return -1; } lua_createtable(T, argc, 0); for (i = 0; i < argc; i++) { lua_pushstring(T, argv[i]); lua_rawseti(T, -2, i - fidx); } lua_setglobal(T, "arg"); lem_queue(T, 0); return 0; }
static void signal_child_handler(EV_P_ struct ev_child *w, int revents) { lua_State *S; int status; int pid = w->pid; int rpid = w->rpid; (void)revents; S = lem_newthread(); lua_pushlightuserdata(S, &sigmap); lua_rawget(S, LUA_REGISTRYINDEX); if (lua_type(S, 1) != LUA_TFUNCTION) { lem_forgetthread(S); return; } lua_pushinteger(S, SIGCHLD); status = w->rstatus; lua_createtable(S, 0, 5); lua_pushinteger(S, pid); lua_setfield(S, -2, "pid"); lua_pushinteger(S, rpid); lua_setfield(S, -2, "rpid"); if (WIFEXITED(status)) { lua_pushinteger(S, WEXITSTATUS(status)); lua_setfield(S, -2, "status"); lua_pushstring(S, "exited"); } else if (WIFSIGNALED(status)) { lua_pushinteger(S, WTERMSIG(status)); lua_setfield(S, -2, "signal"); #ifdef WCOREDUMP lua_pushboolean(S, WCOREDUMP(status)); lua_setfield(S, -2, "coredumped"); #endif lua_pushstring(S, "signaled"); } else if (WIFSTOPPED(status)) { lua_pushinteger(S, WSTOPSIG(status)); lua_setfield(S, -2, "signal"); lua_pushstring(S, "stopped"); } else if (WIFCONTINUED(status)) { lua_pushstring(S, "continued"); } else { assert(0); /* XXX do something more graceful */ } lua_setfield(S, -2, "type"); lem_queue(S, 2); }
static DBusHandlerResult method_call_handler(lua_State *S, DBusMessage *msg) { lua_State *T; struct message_object *m; const char *path = dbus_message_get_path(msg); const char *interface = dbus_message_get_interface(msg); const char *member = dbus_message_get_member(msg); lem_debug("received call\n %s\n %s\n %s(%s)", path, interface, member, dbus_message_get_signature(msg)); lua_pushstring(S, path ? path : ""); lua_rawget(S, LEM_DBUS_OBJECT_TABLE); if (lua_type(S, -1) != LUA_TTABLE) { lua_settop(S, LEM_DBUS_TOP); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } lua_pushfstring(S, "%s.%s", interface ? interface : "", member ? member : ""); lua_rawget(S, -2); if (lua_type(S, -1) != LUA_TFUNCTION) { lua_settop(S, LEM_DBUS_TOP); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } /* create new thread */ T = lem_newthread(); lua_pushvalue(S, LEM_DBUS_BUS_OBJECT); lua_xmove(S, T, 2); lua_settop(S, LEM_DBUS_TOP); /* push the send_reply function */ m = lua_newuserdata(T, sizeof(struct message_object)); m->msg = msg; dbus_message_ref(msg); /* set metatable */ lua_pushvalue(S, LEM_DBUS_MESSAGE_META); lua_xmove(S, T, 1); lua_setmetatable(T, -2); lua_pushcclosure(T, message_reply, 2); lem_queue(T, lem_dbus_push_arguments(T, msg) + 1); return DBUS_HANDLER_RESULT_HANDLED; }
static int utils_spawn(lua_State *T) { lua_State *S; int nargs; luaL_checktype(T, 1, LUA_TFUNCTION); S = lem_newthread(); nargs = lua_gettop(T); lua_xmove(T, S, nargs); lem_queue(S, nargs - 1); lua_pushboolean(T, 1); return 1; }
static void signal_os_handler(EV_P_ struct ev_signal *w, int revents) { lua_State *S; (void)revents; S = lem_newthread(); lua_pushlightuserdata(S, &sigmap); lua_rawget(S, LUA_REGISTRYINDEX); if (lua_type(S, 1) != LUA_TFUNCTION) { lem_forgetthread(S); return; } lua_pushinteger(S, w->signum); lem_queue(S, 1); }
static void server_autospawn_cb(EV_P_ struct ev_io *w, int revents) { lua_State *T = w->data; int sock; lua_State *S; (void)revents; /* dequeue the incoming connection */ #ifdef SOCK_CLOEXEC sock = accept4(w->fd, NULL, NULL, SOCK_CLOEXEC | SOCK_NONBLOCK); #else sock = accept(w->fd, NULL, NULL); #endif if (sock < 0) { switch (errno) { case EAGAIN: case EINTR: case ECONNABORTED: case ENETDOWN: case EPROTO: case ENOPROTOOPT: case EHOSTDOWN: #ifdef ENONET case ENONET: #endif case EHOSTUNREACH: case EOPNOTSUPP: case ENETUNREACH: return; } lua_pushnil(T); lua_pushfstring(T, "error accepting connection: %s", strerror(errno)); goto error; } #ifndef SOCK_CLOEXEC /* set FD_CLOEXEC and make the socket non-blocking */ if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1 || fcntl(sock, F_SETFL, O_NONBLOCK) == -1) { close(sock); lua_pushnil(T); lua_pushfstring(T, "error setting socket flags: %s", strerror(errno)); goto error; } #endif S = lem_newthread(); /* copy handler function */ lua_pushvalue(T, 2); /* create stream */ stream_new(T, sock, 3); /* move function and stream to new thread */ lua_xmove(T, S, 2); lem_queue(S, 1); return; error: ev_io_stop(EV_A_ w); close(w->fd); w->fd = -1; w->data = NULL; lem_queue(T, 2); }
static void runqueue_pop(EV_P_ struct ev_idle *w, int revents) { struct lem_runqueue_slot *slot; lua_State *T; int nargs; (void)revents; if (rq.first == rq.last) { /* queue is empty */ lem_debug("runqueue is empty, collecting.."); #if 0 if (lua_gc(L, LUA_GCSTEP, 0)) { lem_debug("done collecting"); ev_idle_stop(EV_A_ w); } #else ev_idle_stop(EV_A_ w); lua_gc(L, LUA_GCCOLLECT, 0); #endif return; } lem_debug("running thread..."); slot = &rq.queue[rq.first]; T = slot->T; nargs = slot->nargs; rq.first++; rq.first &= rq.mask; /* run Lua thread */ #if LUA_VERSION_NUM >= 502 switch (lua_resume(T, NULL, nargs)) { #else switch (lua_resume(T, nargs)) { #endif case LUA_OK: /* thread finished successfully */ lem_debug("thread finished successfully"); lem_forgetthread(T); return; case LUA_YIELD: /* thread yielded */ lem_debug("thread yielded"); return; case LUA_ERRERR: /* error running error handler */ lem_debug("thread errored while running error handler"); #if LUA_VERSION_NUM >= 502 case LUA_ERRGCMM: lem_debug("error in __gc metamethod"); #endif case LUA_ERRRUN: /* runtime error */ lem_debug("thread errored"); thread_error(T); break; case LUA_ERRMEM: /* out of memory */ oom(); default: /* this shouldn't happen */ lem_debug("lua_resume: unknown error"); lua_pushliteral(L, "unknown error"); break; } lem_exit(EXIT_FAILURE); } #include "pool.c" static int queue_file(int argc, char *argv[], int fidx) { lua_State *T = lem_newthread(); const char *filename; int i; if (fidx < argc) filename = argv[fidx]; else filename = LEM_LDIR "lem/repl.lua"; switch (luaL_loadfile(T, filename)) { case LUA_OK: /* success */ break; case LUA_ERRMEM: oom(); default: lem_log_error("lem: %s", lua_tostring(T, 1)); return -1; } lua_createtable(T, argc, 0); for (i = 0; i < argc; i++) { lua_pushstring(T, argv[i]); lua_rawseti(T, -2, i - fidx); } lua_setglobal(T, "arg"); lem_queue(T, 0); return 0; }