X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=manager.c;h=8ee560c5543f0eb570857b12ed4fa7edb1445a96;hp=600b89ccf5af9510b339e7e3d57c883cdc1e3e4f;hb=fb33a393e21a15ce3b4ac8c16d947fd9b6e77206;hpb=01184e042b1798e9b2f688463637aaf3b0ef576f diff --git a/manager.c b/manager.c index 600b89ccf..8ee560c55 100644 --- a/manager.c +++ b/manager.c @@ -15,16 +15,71 @@ #include "macro.h" #include "strv.h" #include "log.h" +#include "util.h" -Manager* manager_new(void) { - Manager *m; +static const char * const special_table[_SPECIAL_UNIT_MAX] = { + [SPECIAL_SYSLOG_SERVICE] = "syslog.service", + [SPECIAL_DBUS_SERVICE] = "messagebus.service", + [SPECIAL_LOGGER_SOCKET] = "systemd-logger.socket", + [SPECIAL_KBREQUEST_TARGET] = "kbrequest.target", + [SPECIAL_CTRL_ALT_DEL_TARGET] = "ctrl-alt-del.target" +}; + +static int manager_setup_signals(Manager *m) { sigset_t mask; struct epoll_event ev; + assert(m); + + assert_se(reset_all_signal_handlers() == 0); + + assert_se(sigemptyset(&mask) == 0); + assert_se(sigaddset(&mask, SIGCHLD) == 0); + assert_se(sigaddset(&mask, SIGINT) == 0); /* Kernel sends us this on control-alt-del */ + assert_se(sigaddset(&mask, SIGWINCH) == 0); /* Kernel sends us this on kbrequest (alt-arrowup) */ + assert_se(sigaddset(&mask, SIGTERM) == 0); + assert_se(sigaddset(&mask, SIGHUP) == 0); + assert_se(sigaddset(&mask, SIGUSR1) == 0); + assert_se(sigaddset(&mask, SIGUSR2) == 0); + assert_se(sigaddset(&mask, SIGPIPE) == 0); + assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); + + m->signal_watch.type = WATCH_SIGNAL_FD; + if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) + return -errno; + + zero(ev); + ev.events = EPOLLIN; + ev.data.ptr = &m->signal_watch; + + if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0) + return -errno; + + return 0; +} + +static int manager_load_special_units(Manager *m) { + SpecialUnit c; + int r; + + assert(m); + + /* Loads all 'special' units, so that we have easy access to them later */ + + for (c = 0; c < _SPECIAL_UNIT_MAX; c++) + if ((r = manager_load_unit(m, special_table[c], m->special_units+c)) < 0) + return r; + + return 0; +}; + +Manager* manager_new(void) { + Manager *m; + if (!(m = new0(Manager, 1))) return NULL; - m->signal_fd = m->epoll_fd = -1; + m->signal_watch.fd = m->epoll_fd = -1; if (!(m->units = hashmap_new(string_hash_func, string_compare_func))) goto fail; @@ -41,18 +96,10 @@ Manager* manager_new(void) { if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) goto fail; - assert_se(sigemptyset(&mask) == 0); - assert_se(sigaddset(&mask, SIGCHLD) == 0); - assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); - - if ((m->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) + if (manager_setup_signals(m) < 0) goto fail; - zero(ev); - ev.events = EPOLLIN; - ev.data.fd = m->signal_fd; - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_fd, &ev) < 0) + if (manager_load_special_units(m) < 0) goto fail; return m; @@ -81,8 +128,8 @@ void manager_free(Manager *m) { if (m->epoll_fd >= 0) close_nointr(m->epoll_fd); - if (m->signal_fd >= 0) - close_nointr(m->signal_fd); + if (m->signal_watch.fd >= 0) + close_nointr(m->signal_watch.fd); free(m); } @@ -109,6 +156,24 @@ static void transaction_delete_unit(Manager *m, Unit *u) { transaction_delete_job(m, j); } +static void transaction_clean_dependencies(Manager *m) { + Iterator i; + Job *j; + + assert(m); + + /* Drops all dependencies of all installed jobs */ + + HASHMAP_FOREACH(j, m->jobs, i) { + while (j->subject_list) + job_dependency_free(j->subject_list); + while (j->object_list) + job_dependency_free(j->object_list); + } + + assert(!m->transaction_anchor); +} + static void transaction_abort(Manager *m) { Job *j; @@ -121,7 +186,8 @@ static void transaction_abort(Manager *m) { job_free(j); assert(hashmap_isempty(m->transaction_jobs)); - assert(!m->transaction_anchor); + + transaction_clean_dependencies(m); } static void transaction_find_jobs_that_matter_to_anchor(Manager *m, Job *j, unsigned generation) { @@ -536,17 +602,11 @@ static int transaction_apply(Manager *m, JobMode mode) { assert(!j->transaction_next); assert(!j->transaction_prev); + job_schedule_run(j); } /* As last step, kill all remaining job dependencies. */ - HASHMAP_FOREACH(j, m->jobs, i) { - while (j->subject_list) - job_dependency_free(j->subject_list); - while (j->object_list) - job_dependency_free(j->object_list); - } - - assert(!m->transaction_anchor); + transaction_clean_dependencies(m); return 0; @@ -931,13 +991,20 @@ void manager_dispatch_run_queue(Manager *m) { static int manager_dispatch_sigchld(Manager *m) { assert(m); + log_debug("dispatching SIGCHLD"); + for (;;) { siginfo_t si; Unit *u; zero(si); - if (waitid(P_ALL, 0, &si, WNOHANG) < 0) + if (waitid(P_ALL, 0, &si, WEXITED|WNOHANG) < 0) { + + if (errno == ECHILD) + break; + return -errno; + } if (si.si_pid == 0) break; @@ -945,6 +1012,8 @@ static int manager_dispatch_sigchld(Manager *m) { if (si.si_code != CLD_EXITED && si.si_code != CLD_KILLED && si.si_code != CLD_DUMPED) continue; + log_debug("child %llu died (code=%s, status=%i)", (long long unsigned) si.si_pid, sigchld_code(si.si_code), si.si_status); + if (!(u = hashmap_remove(m->watch_pids, UINT32_TO_PTR(si.si_pid)))) continue; @@ -954,7 +1023,7 @@ static int manager_dispatch_sigchld(Manager *m) { return 0; } -static int manager_process_signal_fd(Manager *m) { +static int manager_process_signal_fd(Manager *m, bool *quit) { ssize_t n; struct signalfd_siginfo sfsi; bool sigchld = false; @@ -962,19 +1031,31 @@ static int manager_process_signal_fd(Manager *m) { assert(m); for (;;) { - if ((n = read(m->signal_fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) { + if ((n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) { if (n >= 0) return -EIO; if (errno == EAGAIN) - return 0; + break; return -errno; } - if (sfsi.ssi_signo == SIGCHLD) + switch (sfsi.ssi_signo) { + + case SIGCHLD: sigchld = true; + break; + + case SIGINT: + case SIGTERM: + *quit = true; + return 0; + + default: + log_info("Got unhandled signal <%s>.", strsignal(sfsi.ssi_signo)); + } } if (sigchld) @@ -983,56 +1064,53 @@ static int manager_process_signal_fd(Manager *m) { return 0; } -static int process_event(Manager *m, struct epoll_event *ev) { +static int process_event(Manager *m, struct epoll_event *ev, bool *quit) { int r; + Watch *w; assert(m); assert(ev); - switch (ev->data.u32) { + assert(w = ev->data.ptr); - case MANAGER_SIGNAL: - assert(ev->data.fd == m->signal_fd); + switch (w->type) { - /* An incoming signal? */ - if (ev->events != POLLIN) - return -EINVAL; + case WATCH_SIGNAL_FD: - if ((r = manager_process_signal_fd(m)) < 0) - return -r; + /* An incoming signal? */ + if (ev->events != POLLIN) + return -EINVAL; - break; + if ((r = manager_process_signal_fd(m, quit)) < 0) + return r; - case MANAGER_FD: { - Unit *u; + break; - /* Some fd event, to be dispatched to the units */ - assert_se(u = ev->data.ptr); - UNIT_VTABLE(u)->fd_event(u, ev->data.fd, ev->events); - break; - } + case WATCH_FD: - case MANAGER_TIMER: { - Unit *u; - uint64_t v; - ssize_t k; + /* Some fd event, to be dispatched to the units */ + UNIT_VTABLE(w->unit)->fd_event(w->unit, w->fd, ev->events, w); + break; - /* Some timer event, to be dispatched to the units */ - if ((k = read(ev->data.fd, &v, sizeof(v))) != sizeof(v)) { + case WATCH_TIMER: { + uint64_t v; + ssize_t k; - if (k < 0 && (errno == EINTR || errno == EAGAIN)) - break; + /* Some timer event, to be dispatched to the units */ + if ((k = read(ev->data.fd, &v, sizeof(v))) != sizeof(v)) { - return k < 0 ? -errno : -EIO; - } + if (k < 0 && (errno == EINTR || errno == EAGAIN)) + break; - assert_se(u = ev->data.ptr); - UNIT_VTABLE(u)->timer_event(u, ev->data.fd, v); - break; + return k < 0 ? -errno : -EIO; } - default: - assert_not_reached("Unknown epoll event type."); + UNIT_VTABLE(w->unit)->timer_event(w->unit, v, w); + break; + } + + default: + assert_not_reached("Unknown epoll event type."); } return 0; @@ -1040,16 +1118,17 @@ static int process_event(Manager *m, struct epoll_event *ev) { int manager_loop(Manager *m) { int r; + bool quit = false; assert(m); for (;;) { - struct epoll_event events[32]; - int n, i; + struct epoll_event event; + int n; manager_dispatch_run_queue(m); - if ((n = epoll_wait(m->epoll_fd, events, ELEMENTSOF(events), -1)) < 0) { + if ((n = epoll_wait(m->epoll_fd, &event, 1, -1)) < 0) { if (errno == -EINTR) continue; @@ -1057,8 +1136,12 @@ int manager_loop(Manager *m) { return -errno; } - for (i = 0; i < n; i++) - if ((r = process_event(m, events + i)) < 0) - return r; + assert(n == 1); + + if ((r = process_event(m, &event, &quit)) < 0) + return r; + + if (quit) + return 0; } }