static struct pa_io_event * io_new(pa_mainloop_api *a, int fd, pa_io_event_flags_t events, pa_io_event_cb_t cb, void *userdata) { struct pa_io_event *ev = lem_xmalloc(sizeof(struct pa_io_event)); int revents = 0; (void)a; lem_debug("flags = %d", events); if (events & PA_IO_EVENT_INPUT) revents |= EV_READ; if (events & PA_IO_EVENT_OUTPUT) revents |= EV_WRITE; if (events & PA_IO_EVENT_HANGUP) revents |= EV_READ; ev_io_init(&ev->w, io_handler, fd, revents); ev->w.data = userdata; ev->cb = cb; ev->destroy = NULL; if (revents) ev_io_start(LEM_ &ev->w); return ev; }
static struct pa_defer_event * defer_new(pa_mainloop_api *a, pa_defer_event_cb_t cb, void *userdata) { struct pa_defer_event *ev = lem_xmalloc(sizeof(struct pa_defer_event)); (void)a; lem_debug("new defer %p", ev); ev_idle_init(&ev->w, defer_handler); ev->w.data = userdata; ev->cb = cb; ev->destroy = NULL; ev_idle_start(LEM_ &ev->w); return ev; }
static int file_gc(lua_State *T) { struct file *f = lua_touserdata(T, 1); lem_debug("collecting %p, fd = %d", f, f->fd); if (f->fd >= 0) { struct file_gc *gc = lem_xmalloc(sizeof(struct file_gc)); gc->fd = f->fd; f->fd = -1; lem_async_do(&gc->a, file_gc_work, NULL); } return 0; }
void lem_queue(lua_State *T, int nargs) { struct lem_runqueue_slot *slot; assert(T != NULL); lem_debug("enqueueing thread with %d argument%s", nargs, nargs == 1 ? "" : "s"); if (rq.first == rq.last) ev_idle_start(LEM_ &rq.w); slot = &rq.queue[rq.last]; slot->T = T; slot->nargs = nargs; rq.last++; rq.last &= rq.mask; if (rq.first == rq.last) { unsigned int i; unsigned int j; struct lem_runqueue_slot *new_queue; lem_debug("expanding queue to %u slots", 2*(rq.mask + 1)); new_queue = lem_xmalloc(2*(rq.mask + 1) * sizeof(struct lem_runqueue_slot)); i = 0; j = rq.first; do { new_queue[i] = rq.queue[j]; i++; j++; j &= rq.mask; } while (j != rq.first); free(rq.queue); rq.queue = new_queue; rq.first = 0; rq.last = i; rq.mask = 2*rq.mask + 1; } }
static struct pa_time_event * time_new(pa_mainloop_api *a, const struct timeval *tv, pa_time_event_cb_t cb, void *userdata) { struct pa_time_event *ev = lem_xmalloc(sizeof(struct pa_time_event)); ev_tstamp timeout = timeval_to_stamp(tv); (void)a; lem_debug("after = %f seconds", timeout - ev_now(LEM)); ev->w.data = userdata; ev->tv.tv_sec = tv->tv_sec; ev->tv.tv_usec = tv->tv_usec; ev->cb = cb; ev->destroy = NULL; ev_timer_init(&ev->w, time_handler, timeout - ev_now(LEM), 0); ev_timer_start(LEM_ &ev->w); return ev; }
static int stream_sendfile(lua_State *T) { struct stream *s; struct file *f; off_t size; off_t offset; struct sfhandle *sf; luaL_checktype(T, 1, LUA_TUSERDATA); luaL_checktype(T, 2, LUA_TUSERDATA); size = (off_t)luaL_checknumber(T, 3); offset = (off_t)luaL_optnumber(T, 4, 0); s = lua_touserdata(T, 1); if (!s->open) return io_closed(T); if (s->w.data != NULL) return io_busy(T); f = lua_touserdata(T, 2); if (f->fd < 0) { lua_pushnil(T); lua_pushliteral(T, "file closed"); return 2; } s->w.data = T; sf = lem_xmalloc(sizeof(struct sfhandle)); sf->T = T; sf->s = s; sf->size = size; sf->offset = offset; sf->fd = f->fd; lem_async_do(&sf->a, stream_sendfile_work, stream_sendfile_reap); lua_settop(T, 2); return lua_yield(T, 2); }
static int db_open(lua_State *T) { const char *filename = luaL_checkstring(T, 1); #if SQLITE_VERSION_NUMBER >= 3005000 int flags = luaL_optnumber(T, 2, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); #endif struct db *db; db = lem_xmalloc(sizeof(struct db)); db->T = T; db->handle = NULL; db->refs = 1; db->req.open.filename = filename; #if SQLITE_VERSION_NUMBER >= 3005000 db->req.open.flags = flags; #endif lem_async_do(&db->a, db_open_work, db_open_reap); lua_settop(T, 1); lua_pushvalue(T, lua_upvalueindex(1)); return lua_yield(T, 2); }
static dbus_bool_t watch_add(DBusWatch *watch, void *data) { struct watch *w; lem_debug("watch = %p, fd = %d, flags = %s, enabled = %s", (void *)watch, dbus_watch_get_unix_fd(watch), dbus_watch_get_flags(watch) & DBUS_WATCH_READABLE ? "READ" : "WRITE", dbus_watch_get_enabled(watch) ? "true" : "false"); w = lem_xmalloc(sizeof(struct watch)); ev_io_init(&w->ev, watch_handler, dbus_watch_get_unix_fd(watch), flags_to_revents(dbus_watch_get_flags(watch))); w->conn = data; w->watch = watch; dbus_watch_set_data(watch, w, NULL); if (dbus_watch_get_enabled(watch)) ev_io_start(EV_G_ &w->ev); return TRUE; }
static dbus_bool_t timeout_add(DBusTimeout *timeout, void *data) { struct timeout *t; ev_tstamp interval = dbus_timeout_get_interval(timeout); lem_debug("timeout = %p, interval = %d, enabled = %s", (void *)timeout, dbus_timeout_get_interval(timeout), dbus_timeout_get_enabled(timeout) ? "true" : "false"); t = lem_xmalloc(sizeof(struct timeout)); interval = ((ev_tstamp)dbus_timeout_get_interval(timeout))/1000.0; ev_timer_init(&t->ev, timeout_handler, interval, interval); t->conn = data; t->timeout = timeout; dbus_timeout_set_data(timeout, t, NULL); if (dbus_timeout_get_enabled(timeout)) ev_timer_start(EV_G_ &t->ev); return TRUE; }
static int signal_os_watch(lua_State *T, int sig) { struct sigwatcher *s; if (sigismember(&signal_sigset, sig)) goto out; /* already watched */ s = lem_xmalloc(sizeof(struct sigwatcher)); signal_watcher_init(s, sig); ev_set_priority(&s->w, EV_MAXPRI); ev_signal_start(LEM_ &s->w); ev_unref(LEM); /* watcher shouldn't keep loop alive */ sigaddset(&signal_sigset, sig); pthread_sigmask(SIG_UNBLOCK, &signal_sigset, NULL); s->next = signal_watchers; signal_watchers = s; out: lua_pushboolean(T, 1); return 1; }
int main(int argc, char *argv[]) { #if EV_MULTIPLICITY lem_loop = ev_default_loop(LEM_LOOPFLAGS); if (lem_loop == NULL) { #else if (!ev_default_loop(LEM_LOOPFLAGS)) { #endif lem_log_error("lem: error initializing event loop"); return EXIT_FAILURE; } if (setsignal(SIGPIPE, SIG_IGN, 0) #if !EV_CHILD_ENABLE || setsignal(SIGCHLD, SIG_DFL, SA_NOCLDSTOP | SA_NOCLDWAIT) #endif ) goto error; /* create main Lua state */ L = luaL_newstate(); if (L == NULL) { lem_log_error("lem: error initializing Lua state"); goto error; } luaL_openlibs(L); /* push thread table */ lua_newtable(L); /* initialize runqueue */ ev_idle_init(&rq.w, runqueue_pop); ev_idle_start(LEM_ &rq.w); rq.queue = lem_xmalloc(LEM_INITIAL_QUEUESIZE * sizeof(struct lem_runqueue_slot)); rq.first = rq.last = 0; rq.mask = LEM_INITIAL_QUEUESIZE - 1; /* initialize threadpool */ if (pool_init()) { lem_log_error("lem: error initializing threadpool"); goto error; } /* load file */ if (queue_file(argc, argv, 1)) goto error; /* start the mainloop */ ev_loop(LEM_ 0); lem_debug("event loop exited"); /* if there is an error message left on L print it */ if (lua_type(L, -1) == LUA_TSTRING) lem_log_error("lem: %s", lua_tostring(L, -1)); /* shutdown Lua */ lua_close(L); /* free runqueue */ free(rq.queue); /* destroy loop */ #if EV_MULTIPLICITY ev_loop_destroy(lem_loop); #else ev_default_destroy(); #endif lem_debug("Bye %s", exit_status == EXIT_SUCCESS ? "o/" : ":("); return exit_status; error: if (L) lua_close(L); if (rq.queue) free(rq.queue); #if EV_MULTIPLICITY ev_loop_destroy(lem_loop); #else ev_default_destroy(); #endif return EXIT_FAILURE; }