X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=manager.c;h=f15cf79869f3a23028e60025037c759661612ca2;hb=c25fb0edbb8a1d4fc2e466a355e7d3e5ddeacd5e;hp=600b89ccf5af9510b339e7e3d57c883cdc1e3e4f;hpb=01184e042b1798e9b2f688463637aaf3b0ef576f;p=elogind.git diff --git a/manager.c b/manager.c index 600b89ccf..f15cf7986 100644 --- a/manager.c +++ b/manager.c @@ -15,6 +15,7 @@ #include "macro.h" #include "strv.h" #include "log.h" +#include "util.h" Manager* manager_new(void) { Manager *m; @@ -24,7 +25,7 @@ Manager* manager_new(void) { 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 +42,25 @@ Manager* manager_new(void) { if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) goto fail; + assert_se(reset_all_signal_handlers() == 0); + assert_se(sigemptyset(&mask) == 0); assert_se(sigaddset(&mask, SIGCHLD) == 0); + assert_se(sigaddset(&mask, SIGINT) == 0); + assert_se(sigaddset(&mask, SIGTERM) == 0); + assert_se(sigaddset(&mask, SIGWINCH) == 0); + assert_se(sigaddset(&mask, SIGHUP) == 0); assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); - if ((m->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) + m->signal_watch.type = WATCH_SIGNAL_FD; + if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) goto fail; zero(ev); ev.events = EPOLLIN; - ev.data.fd = m->signal_fd; + ev.data.ptr = &m->signal_watch; - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_fd, &ev) < 0) + if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0) goto fail; return m; @@ -81,8 +89,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 +117,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 +147,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 +563,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 +952,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 +973,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 +984,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 +992,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 +1025,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,6 +1079,7 @@ static int process_event(Manager *m, struct epoll_event *ev) { int manager_loop(Manager *m) { int r; + bool quit = false; assert(m); @@ -1057,8 +1097,12 @@ int manager_loop(Manager *m) { return -errno; } - for (i = 0; i < n; i++) - if ((r = process_event(m, events + i)) < 0) + for (i = 0; i < n; i++) { + if ((r = process_event(m, events + i, &quit)) < 0) return r; + + if (quit) + return 0; + } } }