diff --git a/Makefile b/Makefile index 661c18ff..40430ef2 100644 --- a/Makefile +++ b/Makefile @@ -57,22 +57,24 @@ FINIT_RCSD ?= $(sysconfdir)/finit.d CFLAGS += -W -Wall -Werror -Os # Disable annoying gcc warning for "warn_unused_result", see GIT 37af997 CPPFLAGS += -U_FORTIFY_SOURCE -CPPFLAGS += -Ilibite -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE +CPPFLAGS += -Ilibite -Ilibuev +CPPFLAGS += -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_GNU_SOURCE CPPFLAGS += -DVERSION=\"$(VERSION)\" -DWHOAMI=\"`whoami`@`hostname`\" CPPFLAGS += -DFINIT_FIFO=\"$(FINIT_FIFO)\" -DFINIT_CONF=\"$(FINIT_CONF)\" CPPFLAGS += -DFINIT_RCSD=\"$(FINIT_RCSD)\" -DPLUGIN_PATH=\"$(plugindir)\" LDFLAGS += -rdynamic -L$(TOPDIR)/libite -DEPLIBS = libite/libite.so +DEPLIBS = libite/libite.so libuev/libuev.a LDLIBS += -ldl -lite include common.mk export libdir plugindir incdir ROOTDIR CPPFLAGS LDFLAGS LDLIBS all: $(DEPLIBS) $(EXEC) - $(MAKE) -C plugins $@ + +$(MAKE) -C plugins $@ $(DEPLIBS): Makefile - $(MAKE) -C libite all + +$(MAKE) -C libite all + +$(MAKE) -C libuev all $(OBJS): Makefile @@ -133,13 +135,15 @@ uninstall: uninstall-exec uninstall-data uninstall-dev clean: -@$(RM) $(OBJS) $(DEPS) $(EXEC) - $(MAKE) -C libite $@ - $(MAKE) -C plugins $@ + +$(MAKE) -C plugins $@ + +$(MAKE) -C libite $@ + +$(MAKE) -C libuev $@ distclean: clean -@$(RM) $(JUNK) unittest *.o .*.d - $(MAKE) -C libite $@ - $(MAKE) -C plugins $@ + +$(MAKE) -C plugins $@ + +$(MAKE) -C libite $@ + +$(MAKE) -C libuev $@ check: $(CHECK) *.c plugins/*.c libite/*.c diff --git a/finit.c b/finit.c index 0a363c01..5ff74638 100644 --- a/finit.c +++ b/finit.c @@ -131,25 +131,12 @@ static int client(int argc, char *argv[]) return 0; } -static int run_loop(void) +/* + * Delayed start of TTYs to let the system stabilize at boot + */ +static void delayed_tty_start(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) { - int delay = DELAY_TTY ?: 1; - - _d("Entering main loop ..."); - while (1) { - svc_monitor(); - plugin_monitor(); - - /* Delayed start of TTYs to let the system stabilize - * after switching runlevels. */ - if (delay) { - if (--delay == 0) - tty_runlevel(runlevel); - continue; - } - } - - return 0; + tty_runlevel(runlevel); } static void banner(void) @@ -160,6 +147,9 @@ static void banner(void) int main(int argc, char* argv[]) { + uev_t w; + uev_ctx_t ctx; + if (getpid() != 1) return client(argc, argv); @@ -173,6 +163,11 @@ int main(int argc, char* argv[]) */ sig_init(); + /* + * Initalize event context. + */ + uev_init(&ctx); + /* * Mount base file system, kernel is assumed to run devtmpfs for /dev */ @@ -208,7 +203,7 @@ int main(int argc, char* argv[]) * hook on to. */ print_desc("Loading plugins", NULL); - print_result(plugin_load_all(PLUGIN_PATH)); + print_result(plugin_load_all(&ctx, PLUGIN_PATH)); /* * Mount filesystems @@ -232,7 +227,7 @@ int main(int argc, char* argv[]) run_interactive("rm -rf /tmp/* /var/run/* /var/lock/*", "Cleanup temporary directories"); /* Base FS up, enable standard SysV init signals */ - sig_setup(); + sig_setup(&ctx); _d("Base FS up, calling hooks ..."); plugin_run_hooks(HOOK_BASEFS_UP); @@ -279,10 +274,13 @@ int main(int argc, char* argv[]) /* Hooks that should run at the very end */ plugin_run_hooks(HOOK_SYSTEM_UP); + /* Delayed start of TTY's at boot (one-shot timer) */ + uev_timer_init(&ctx, &w, delayed_tty_start, NULL, 2000, 0); + /* * Enter main loop to monior /dev/initctl and services */ - return run_loop(); + return uev_run(&ctx, 0); } /** diff --git a/finit.h b/finit.h index 553eb451..c25ccc88 100644 --- a/finit.h +++ b/finit.h @@ -65,9 +65,6 @@ # define DEFHOST "noname" #endif -/* Delay start of GETTY at boot. Must be > 0 */ -#define DELAY_TTY 2 - #define CMD_SIZE 256 #define LINE_SIZE 1024 #define BUF_SIZE 4096 diff --git a/plugin.c b/plugin.c index 56e2dab3..29aef084 100644 --- a/plugin.c +++ b/plugin.c @@ -36,10 +36,8 @@ #define is_io_plugin(p) ((p)->io.cb && (p)->io.fd >= 0) -static char *plugpath = NULL; /* Set by first load. */ -static size_t num_fds = 0; -static struct pollfd fds[MAX_NUM_FDS]; -static TAILQ_HEAD(, plugin) plugins = TAILQ_HEAD_INITIALIZER(plugins); +static char *plugpath = NULL; /* Set by first load. */ +static TAILQ_HEAD(, plugin) plugins = TAILQ_HEAD_INITIALIZER(plugins); static void check_plugin_depends(plugin_t *plugin); @@ -69,15 +67,8 @@ int plugin_register(plugin_t *plugin) check_plugin_depends(plugin); - if (is_io_plugin(plugin)) { - if (num_fds + 1 >= MAX_NUM_FDS) { - num_fds = MAX_NUM_SVC; - errno = ENOMEM; - return 1; - } - num_fds++; + if (is_io_plugin(plugin)) inuse++; - } if (plugin->svc.cb) { svc_t *svc = svc_find(plugin->name); @@ -189,62 +180,29 @@ void plugin_run_hooks(hook_point_t no) } /* Generic libev I/O callback, looks up correct plugin and calls its callback */ -static void generic_io_cb(struct pollfd *io) +static void generic_io_cb(uev_ctx_t *UNUSED(ctx), uev_t *w, void *arg, int events) { - plugin_t *p, *tmp; + plugin_t *p = (plugin_t *)arg; - /* Find matching plugin, pick first matching fd */ - PLUGIN_ITERATOR(p, tmp) { - if (is_io_plugin(p) && p->io.fd == io->fd) { - _d("Calling I/O %s from runloop...", basename(p->name)); - p->io.cb(p->io.arg, io->fd, io->events); + if (is_io_plugin(p) && p->io.fd == w->fd) { + _d("Calling I/O %s from runloop...", basename(p->name)); + p->io.cb(p->io.arg, w->fd, events); - /* Update fd, may be changed by plugin callback, e.g., if FIFO */ - io->fd = p->io.fd; - io->events = p->io.flags; - io->revents = 0; - break; - } - } -} - -void plugin_monitor(void) -{ - int ret; - size_t i; - - while ((ret = poll(fds, num_fds, 500))) { - if (-1 == ret) { - if (EINTR == errno) - continue; - - _e("Failed polling I/O plugin descriptors, error %d: %s", - errno, strerror(errno)); - break; - } - - /* Traverse all I/O fds and run callbacks */ - for (i = 0; i < num_fds; i++) { - if (fds[i].revents) - generic_io_cb(&fds[i]); - } - - break; + /* Update fd, may be changed by plugin callback, e.g., if FIFO */ + if (p->io.fd != w->fd) + uev_io_set (w, p->io.fd, p->io.flags); } } /* Setup any I/O callbacks for plugins that use them */ -static void init_plugins(void) +static void init_plugins(uev_ctx_t *ctx) { - int i = 0; plugin_t *p, *tmp; PLUGIN_ITERATOR(p, tmp) { if (is_io_plugin(p)) { _d("Initializing plugin %s for I/O", basename(p->name)); - fds[i].revents = 0; - fds[i].events = p->io.flags; - fds[i++].fd = p->io.fd; + uev_io_init(ctx, &p->watcher, generic_io_cb, p, p->io.fd, p->io.flags); } } } @@ -318,7 +276,7 @@ static void check_plugin_depends(plugin_t *plugin) } } -int plugin_load_all(char *path) +int plugin_load_all(uev_ctx_t *ctx, char *path) { int fail = 0; DIR *dp = opendir(path); @@ -341,7 +299,7 @@ int plugin_load_all(char *path) } closedir(dp); - init_plugins(); + init_plugins(ctx); return fail; } diff --git a/plugin.h b/plugin.h index a6e8c988..fa0a9d1b 100644 --- a/plugin.h +++ b/plugin.h @@ -24,13 +24,13 @@ #ifndef FINIT_PLUGIN_H_ #define FINIT_PLUGIN_H_ -#include #include "queue.h" /* BSD sys/queue.h API */ #include "svc.h" +#include "libuev/uev.h" #define PLUGIN_DEP_MAX 10 -#define PLUGIN_IO_READ POLLIN -#define PLUGIN_IO_WRITE POLLOUT +#define PLUGIN_IO_READ UEV_READ +#define PLUGIN_IO_WRITE UEV_WRITE #define PLUGIN_INIT(x) static void __attribute__ ((constructor)) x(void) #define PLUGIN_EXIT(x) static void __attribute__ ((destructor)) x(void) @@ -79,6 +79,9 @@ typedef struct plugin { /* BSD sys/queue.h linked list node. */ TAILQ_ENTRY(plugin) link; + /* Event loop handler, used internally by Finit */ + uev_t watcher; + /* Plugin name, defaults to basename of plugin path if unset. * NOTE: Must be same as @cmd for service plugins! */ char *name; diff --git a/private.h b/private.h index ec8048a6..f3150012 100644 --- a/private.h +++ b/private.h @@ -29,11 +29,10 @@ #include "plugin.h" void svc_bootstrap (void); -void svc_monitor (void); +void svc_monitor (pid_t lost); void plugin_run_hooks (hook_point_t no); -int plugin_load_all (char *path); -void plugin_monitor (void); +int plugin_load_all (uev_ctx_t *ctx, char *path); #endif /* FINIT_PRIVATE_H_ */ diff --git a/sig.c b/sig.c index 930e4ea5..da7b7cf1 100644 --- a/sig.c +++ b/sig.c @@ -47,9 +47,13 @@ #include "private.h" #include "sig.h" -static int stopped = 0; +static int stopped = 0; +static uev_t sigint_watcher, sigpwr_watcher; +static uev_t sigchld_watcher; +static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher; -void do_shutdown (int sig) + +void do_shutdown(int sig) { touch(SYNC_SHUTDOWN); @@ -84,38 +88,35 @@ void do_shutdown (int sig) } /* - * Shut down on INT USR1 USR2 + * Shut down on INT PWR */ -static void shutdown_handler(int sig, siginfo_t *info, void *UNUSED(ctx)) +static void sigint_cb(uev_ctx_t *UNUSED(ctx), uev_t *w, void *UNUSED(arg), int UNUSED(events)) { - _d("Rebooting on signal %d from %s (PID %d)", - sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid); - - do_shutdown(sig); + do_shutdown(w->signo); } /* * SIGCHLD: one of our children has died */ -static void chld_handler(int UNUSED(sig), siginfo_t *UNUSED(info), void *UNUSED(ctx)) +static void sigchld_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) { - /* Do nothing, the svc_monitor() is the designated child reaper. */ + svc_monitor(waitpid(-1, NULL, WNOHANG)); } /* - * SIGSTOP: Paused by user or netflash + * SIGSTOP/SIGTSTP: Paused by user or netflash */ -static void sigstop_handler(int sig, siginfo_t *info, void *UNUSED(ctx)) +static void sigstop_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) { - _d("Received SIGSTOP(%d) from %s (PID %d)", - sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid); touch(SYNC_STOPPED); stopped++; } -static void sigcont_handler(int sig, siginfo_t *info, void *UNUSED(ctx)) + +/* + * SIGCONT: Restart service monitor + */ +static void sigcont_cb(uev_ctx_t *UNUSED(ctx), uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) { - _d("Received SIGCONT(%d) from %s (PID %d)", - sig, pid_get_name(info->si_pid, NULL, 0), info->si_pid); stopped = 0; erase(SYNC_STOPPED); } @@ -131,6 +132,11 @@ int sig_stopped(void) /* * Inital signal setup - ignore everything but SIGCHLD until we're capable of responding */ +static void chld_handler(int UNUSED(sig), siginfo_t *UNUSED(info), void *UNUSED(ctx)) +{ + /* NOP */ +} + void sig_init(void) { int i; @@ -145,7 +151,7 @@ void sig_init(void) /* * Setup limited set of SysV compatible signals to respond to */ -void sig_setup(void) +void sig_setup(uev_ctx_t *ctx) { struct sigaction sa; @@ -156,12 +162,12 @@ void sig_setup(void) erase(SYNC_STOPPED); /* Standard SysV init calls ctrl-alt-delete handler */ - SETSIG(sa, SIGINT, shutdown_handler, 0); - SETSIG(sa, SIGPWR, shutdown_handler, 0); + uev_signal_init(ctx, &sigint_watcher, sigint_cb, NULL, SIGINT); + uev_signal_init(ctx, &sigpwr_watcher, sigint_cb, NULL, SIGPWR); /* Ignore SIGUSR1/2 for now, only BusyBox init implements them as reboot+halt. */ -// SETSIG2(sa, SIGUSR1, reopen_initctl, 0); -// SETSIG2(sa, SIGUSR2, pwrdwn_handler, 0); +// uev_signal_init(&ctx, &sigusr1_watcher, reopen_initctl_cb, NULL, SIGUSR1); +// uev_signal_init(&ctx, &sigusr2_watcher, pwrdwn_cb, NULL, SIGUSR2); /* Init must ignore SIGTERM. May otherwise get false SIGTERM in forked children! */ IGNSIG(sa, SIGTERM, 0); @@ -172,10 +178,13 @@ void sig_setup(void) /* We don't have any /etc/inittab yet, reread finit.conf? */ IGNSIG(sa, SIGHUP, 0); + /* After initial bootstrap of Finit we call the service monitor to reap children */ + uev_signal_init(ctx, &sigchld_watcher, sigchld_cb, NULL, SIGCHLD); + /* Stopping init is a bit tricky. */ - SETSIG(sa, SIGSTOP, sigstop_handler, 0); - SETSIG(sa, SIGTSTP, sigstop_handler, 0); - SETSIG(sa, SIGCONT, sigcont_handler, 0); + uev_signal_init(ctx, &sigstop_watcher, sigstop_cb, NULL, SIGSTOP); + uev_signal_init(ctx, &sigtstp_watcher, sigstop_cb, NULL, SIGTSTP); + uev_signal_init(ctx, &sigcont_watcher, sigcont_cb, NULL, SIGCONT); /* Disable CTRL-ALT-DELETE from kernel, we handle shutdown gracefully with SIGINT, above */ reboot(RB_DISABLE_CAD); diff --git a/sig.h b/sig.h index 37a649a0..e452db5b 100644 --- a/sig.h +++ b/sig.h @@ -26,6 +26,7 @@ #define FINIT_SIG_H_ #include +#include "libuev/uev.h" #define SYNC_SHUTDOWN "/var/lock/finit.shutdown" #define SYNC_STOPPED "/var/lock/finit.stopped" @@ -57,7 +58,7 @@ void do_shutdown (int sig); int sig_stopped (void); void sig_init (void); -void sig_setup (void); +void sig_setup (uev_ctx_t *ctx); #endif /* FINIT_SIG_H_ */ diff --git a/svc.c b/svc.c index ca359ed5..1cec0515 100644 --- a/svc.c +++ b/svc.c @@ -362,9 +362,8 @@ static void restart_any_lost_procs(void) } } -void svc_monitor(void) +void svc_monitor(pid_t lost) { - pid_t lost; svc_t *svc; if (was_stopped && !is_norespawn()) { @@ -373,10 +372,6 @@ void svc_monitor(void) return; } - lost = waitpid(-1, NULL, WNOHANG); - if (lost < 1) - return; - if (fexist(SYNC_SHUTDOWN) || lost <= 1) return;