diff options
author | Thomas Haller <thaller@redhat.com> | 2019-12-15 14:28:45 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-12-16 10:22:09 +0100 |
commit | 9e02a676196300370487b39cbcff4e28d6c5f27c (patch) | |
tree | af6373d1ca2b7cd64994fc9c875964267ae5277a /src/systemd | |
parent | a1771c738dd2e1437bd9f7c73805fd8a1b1b3d1d (diff) | |
parent | 0d155d1821875ab0de1ebe95570e5684daeb7d52 (diff) | |
download | NetworkManager-9e02a676196300370487b39cbcff4e28d6c5f27c.tar.gz |
systemd: merge branch systemd into master
Diffstat (limited to 'src/systemd')
-rw-r--r-- | src/systemd/src/libsystemd-network/sd-ipv4acd.c | 6 | ||||
-rw-r--r-- | src/systemd/src/libsystemd-network/sd-ipv4ll.c | 2 | ||||
-rw-r--r-- | src/systemd/src/libsystemd/sd-event/event-source.h | 8 | ||||
-rw-r--r-- | src/systemd/src/libsystemd/sd-event/sd-event.c | 462 | ||||
-rw-r--r-- | src/systemd/src/libsystemd/sd-id128/id128-util.c | 2 | ||||
-rw-r--r-- | src/systemd/src/libsystemd/sd-id128/id128-util.h | 4 | ||||
-rw-r--r-- | src/systemd/src/systemd/sd-event.h | 12 | ||||
-rw-r--r-- | src/systemd/src/systemd/sd-ipv4acd.h | 3 |
8 files changed, 459 insertions, 40 deletions
diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c index 3efa8170b1..9f69088dea 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c @@ -443,7 +443,7 @@ int sd_ipv4acd_is_running(sd_ipv4acd *acd) { return acd->state != IPV4ACD_STATE_INIT; } -int sd_ipv4acd_start(sd_ipv4acd *acd) { +int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts) { int r; assert_return(acd, -EINVAL); @@ -460,7 +460,9 @@ int sd_ipv4acd_start(sd_ipv4acd *acd) { safe_close(acd->fd); acd->fd = r; acd->defend_window = 0; - acd->n_conflict = 0; + + if (reset_conflicts) + acd->n_conflict = 0; r = sd_event_add_io(acd->event, &acd->receive_message_event_source, acd->fd, EPOLLIN, ipv4acd_on_packet, acd); if (r < 0) diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c index 2d17b4fe81..a610546c4f 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c @@ -243,7 +243,7 @@ static int ipv4ll_start_internal(sd_ipv4ll *ll, bool reset_generation) { picked_address = true; } - r = sd_ipv4acd_start(ll->acd); + r = sd_ipv4acd_start(ll->acd, reset_generation); if (r < 0) { /* We couldn't start? If so, let's forget the picked address again, the user might make a change and diff --git a/src/systemd/src/libsystemd/sd-event/event-source.h b/src/systemd/src/libsystemd/sd-event/event-source.h index 99ab8fc169..08eb9b6a61 100644 --- a/src/systemd/src/libsystemd/sd-event/event-source.h +++ b/src/systemd/src/libsystemd/sd-event/event-source.h @@ -34,7 +34,7 @@ typedef enum EventSourceType { * we know how to dispatch it */ typedef enum WakeupType { WAKEUP_NONE, - WAKEUP_EVENT_SOURCE, + WAKEUP_EVENT_SOURCE, /* either I/O or pidfd wakeup */ WAKEUP_CLOCK_DATA, WAKEUP_SIGNAL_DATA, WAKEUP_INOTIFY_DATA, @@ -96,6 +96,12 @@ struct sd_event_source { siginfo_t siginfo; pid_t pid; int options; + int pidfd; + bool registered:1; /* whether the pidfd is registered in the epoll */ + bool pidfd_owned:1; /* close pidfd when event source is freed */ + bool process_owned:1; /* kill+reap process when event source is freed */ + bool exited:1; /* true if process exited (i.e. if there's value in SIGKILLing it if we want to get rid of it) */ + bool waited:1; /* true if process was waited for (i.e. if there's value in waitid(P_PID)'ing it if we want to get rid of it) */ } child; struct { sd_event_handler_t callback; diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index 7c4566e342..8ffaa75d51 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -11,6 +11,7 @@ #include "sd-id128.h" #include "alloc-util.h" +#include "env-util.h" #include "event-source.h" #include "fd-util.h" #include "fs-util.h" @@ -30,6 +31,14 @@ #define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC) +static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) { + /* Returns true if this is a PID event source and can be implemented by watching EPOLLIN */ + return s && + s->type == SOURCE_CHILD && + s->child.pidfd >= 0 && + s->child.options == WEXITED; +} + static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = { [SOURCE_IO] = "io", [SOURCE_TIME_REALTIME] = "realtime", @@ -358,8 +367,6 @@ static bool event_pid_changed(sd_event *e) { } static void source_io_unregister(sd_event_source *s) { - int r; - assert(s); assert(s->type == SOURCE_IO); @@ -369,8 +376,7 @@ static void source_io_unregister(sd_event_source *s) { if (!s->io.registered) return; - r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL); - if (r < 0) + if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL) < 0) log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m", strna(s->description), event_source_type_to_string(s->type)); @@ -406,6 +412,51 @@ static int source_io_register( return 0; } +static void source_child_pidfd_unregister(sd_event_source *s) { + assert(s); + assert(s->type == SOURCE_CHILD); + + if (event_pid_changed(s->event)) + return; + + if (!s->child.registered) + return; + + if (EVENT_SOURCE_WATCH_PIDFD(s)) + if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->child.pidfd, NULL) < 0) + log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m", + strna(s->description), event_source_type_to_string(s->type)); + + s->child.registered = false; +} + +static int source_child_pidfd_register(sd_event_source *s, int enabled) { + int r; + + assert(s); + assert(s->type == SOURCE_CHILD); + assert(enabled != SD_EVENT_OFF); + + if (EVENT_SOURCE_WATCH_PIDFD(s)) { + struct epoll_event ev; + + ev = (struct epoll_event) { + .events = EPOLLIN | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0), + .data.ptr = s, + }; + + if (s->child.registered) + r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->child.pidfd, &ev); + else + r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->child.pidfd, &ev); + if (r < 0) + return -errno; + } + + s->child.registered = true; + return 0; +} + static clockid_t event_source_type_to_clock(EventSourceType t) { switch (t) { @@ -616,9 +667,8 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig) assert(e); - /* Rechecks if the specified signal is still something we are - * interested in. If not, we'll unmask it, and possibly drop - * the signalfd for it. */ + /* Rechecks if the specified signal is still something we are interested in. If not, we'll unmask it, + * and possibly drop the signalfd for it. */ if (sig == SIGCHLD && e->n_enabled_child_sources > 0) @@ -709,9 +759,13 @@ static void source_disconnect(sd_event_source *s) { } (void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid)); - event_gc_signal_data(s->event, &s->priority, SIGCHLD); } + if (EVENT_SOURCE_WATCH_PIDFD(s)) + source_child_pidfd_unregister(s); + else + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + break; case SOURCE_DEFER: @@ -792,6 +846,44 @@ static void source_free(sd_event_source *s) { if (s->type == SOURCE_IO && s->io.owned) s->io.fd = safe_close(s->io.fd); + if (s->type == SOURCE_CHILD) { + /* Eventually the kernel will do this automatically for us, but for now let's emulate this (unreliably) in userspace. */ + + if (s->child.process_owned) { + + if (!s->child.exited) { + bool sent = false; + + if (s->child.pidfd >= 0) { + if (pidfd_send_signal(s->child.pidfd, SIGKILL, NULL, 0) < 0) { + if (errno == ESRCH) /* Already dead */ + sent = true; + else if (!ERRNO_IS_NOT_SUPPORTED(errno)) + log_debug_errno(errno, "Failed to kill process " PID_FMT " via pidfd_send_signal(), re-trying via kill(): %m", + s->child.pid); + } else + sent = true; + } + + if (!sent) + if (kill(s->child.pid, SIGKILL) < 0) + if (errno != ESRCH) /* Already dead */ + log_debug_errno(errno, "Failed to kill process " PID_FMT " via kill(), ignoring: %m", + s->child.pid); + } + + if (!s->child.waited) { + siginfo_t si = {}; + + /* Reap the child if we can */ + (void) waitid(P_PID, s->child.pid, &si, WEXITED); + } + } + + if (s->child.pidfd_owned) + s->child.pidfd = safe_close(s->child.pidfd); + } + if (s->destroy_callback) s->destroy_callback(s->userdata); @@ -1076,7 +1168,6 @@ _public_ int sd_event_add_signal( _cleanup_(source_freep) sd_event_source *s = NULL; struct signal_data *d; - sigset_t ss; int r; assert_return(e, -EINVAL); @@ -1088,11 +1179,10 @@ _public_ int sd_event_add_signal( if (!callback) callback = signal_exit_callback; - r = pthread_sigmask(SIG_SETMASK, NULL, &ss); - if (r != 0) - return -r; - - if (!sigismember(&ss, sig)) + r = signal_is_blocked(sig); + if (r < 0) + return r; + if (r == 0) return -EBUSY; if (!e->signal_sources) { @@ -1126,7 +1216,11 @@ _public_ int sd_event_add_signal( return 0; } -#endif /* NM_IGNORED */ + +static bool shall_use_pidfd(void) { + /* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */ + return getenv_bool_secure("SYSTEMD_PIDFD") != 0; +} _public_ int sd_event_add_child( sd_event *e, @@ -1148,6 +1242,20 @@ _public_ int sd_event_add_child( assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + if (e->n_enabled_child_sources == 0) { + /* Caller must block SIGCHLD before using us to watch children, even if pidfd is available, + * for compatibility with pre-pidfd and because we don't want the reap the child processes + * ourselves, i.e. call waitid(), and don't want Linux' default internal logic for that to + * take effect. + * + * (As an optimization we only do this check on the first child event source created.) */ + r = signal_is_blocked(SIGCHLD); + if (r < 0) + return r; + if (r == 0) + return -EBUSY; + } + r = hashmap_ensure_allocated(&e->child_sources, NULL); if (r < 0) return r; @@ -1159,32 +1267,147 @@ _public_ int sd_event_add_child( if (!s) return -ENOMEM; + s->wakeup = WAKEUP_EVENT_SOURCE; s->child.pid = pid; s->child.options = options; s->child.callback = callback; s->userdata = userdata; s->enabled = SD_EVENT_ONESHOT; + /* We always take a pidfd here if we can, even if we wait for anything else than WEXITED, so that we + * pin the PID, and make regular waitid() handling race-free. */ + + if (shall_use_pidfd()) { + s->child.pidfd = pidfd_open(s->child.pid, 0); + if (s->child.pidfd < 0) { + /* Propagate errors unless the syscall is not supported or blocked */ + if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) + return -errno; + } else + s->child.pidfd_owned = true; /* If we allocate the pidfd we own it by default */ + } else + s->child.pidfd = -1; + r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s); if (r < 0) return r; e->n_enabled_child_sources++; - r = event_make_signal_data(e, SIGCHLD, NULL); - if (r < 0) { - e->n_enabled_child_sources--; - return r; - } + if (EVENT_SOURCE_WATCH_PIDFD(s)) { + /* We have a pidfd and we only want to watch for exit */ + + r = source_child_pidfd_register(s, s->enabled); + if (r < 0) { + e->n_enabled_child_sources--; + return r; + } + } else { + /* We have no pidfd or we shall wait for some other event than WEXITED */ + + r = event_make_signal_data(e, SIGCHLD, NULL); + if (r < 0) { + e->n_enabled_child_sources--; + return r; + } - e->need_process_child = true; + e->need_process_child = true; + } if (ret) *ret = s; + TAKE_PTR(s); + return 0; +} + +_public_ int sd_event_add_child_pidfd( + sd_event *e, + sd_event_source **ret, + int pidfd, + int options, + sd_event_child_handler_t callback, + void *userdata) { + + + _cleanup_(source_freep) sd_event_source *s = NULL; + pid_t pid; + int r; + + assert_return(e, -EINVAL); + assert_return(e = event_resolve(e), -ENOPKG); + assert_return(pidfd >= 0, -EBADF); + assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL); + assert_return(options != 0, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + + if (e->n_enabled_child_sources == 0) { + r = signal_is_blocked(SIGCHLD); + if (r < 0) + return r; + if (r == 0) + return -EBUSY; + } + + r = hashmap_ensure_allocated(&e->child_sources, NULL); + if (r < 0) + return r; + + r = pidfd_get_pid(pidfd, &pid); + if (r < 0) + return r; + if (hashmap_contains(e->child_sources, PID_TO_PTR(pid))) + return -EBUSY; + + s = source_new(e, !ret, SOURCE_CHILD); + if (!s) + return -ENOMEM; + + s->wakeup = WAKEUP_EVENT_SOURCE; + s->child.pidfd = pidfd; + s->child.pid = pid; + s->child.options = options; + s->child.callback = callback; + s->child.pidfd_owned = false; /* If we got the pidfd passed in we don't own it by default (similar to the IO fd case) */ + s->userdata = userdata; + s->enabled = SD_EVENT_ONESHOT; + + r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s); + if (r < 0) + return r; + + e->n_enabled_child_sources++; + + if (EVENT_SOURCE_WATCH_PIDFD(s)) { + /* We only want to watch for WEXITED */ + + r = source_child_pidfd_register(s, s->enabled); + if (r < 0) { + e->n_enabled_child_sources--; + return r; + } + } else { + /* We shall wait for some other event than WEXITED */ + + r = event_make_signal_data(e, SIGCHLD, NULL); + if (r < 0) { + e->n_enabled_child_sources--; + return r; + } + + e->need_process_child = true; + } + + if (ret) + *ret = s; + + TAKE_PTR(s); return 0; } +#endif /* NM_IGNORED */ _public_ int sd_event_add_defer( sd_event *e, @@ -1769,7 +1992,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) { return r; } - epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL); + (void) epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL); } return 0; @@ -2030,7 +2253,11 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { assert(s->event->n_enabled_child_sources > 0); s->event->n_enabled_child_sources--; - event_gc_signal_data(s->event, &s->priority, SIGCHLD); + if (EVENT_SOURCE_WATCH_PIDFD(s)) + source_child_pidfd_unregister(s); + else + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + break; case SOURCE_EXIT: @@ -2104,12 +2331,25 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { s->enabled = m; - r = event_make_signal_data(s->event, SIGCHLD, NULL); - if (r < 0) { - s->enabled = SD_EVENT_OFF; - s->event->n_enabled_child_sources--; - event_gc_signal_data(s->event, &s->priority, SIGCHLD); - return r; + if (EVENT_SOURCE_WATCH_PIDFD(s)) { + /* yes, we have pidfd */ + + r = source_child_pidfd_register(s, s->enabled); + if (r < 0) { + s->enabled = SD_EVENT_OFF; + s->event->n_enabled_child_sources--; + return r; + } + } else { + /* no pidfd, or something other to watch for than WEXITED */ + + r = event_make_signal_data(s->event, SIGCHLD, NULL); + if (r < 0) { + s->enabled = SD_EVENT_OFF; + s->event->n_enabled_child_sources--; + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + return r; + } } break; @@ -2232,6 +2472,98 @@ _public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) { return 0; } +_public_ int sd_event_source_get_child_pidfd(sd_event_source *s) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); + + if (s->child.pidfd < 0) + return -EOPNOTSUPP; + + return s->child.pidfd; +} + +_public_ int sd_event_source_send_child_signal(sd_event_source *s, int sig, const siginfo_t *si, unsigned flags) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(SIGNAL_VALID(sig), -EINVAL); + + /* If we already have seen indication the process exited refuse sending a signal early. This way we + * can be sure we don't accidentally kill the wrong process on PID reuse when pidfds are not + * available. */ + if (s->child.exited) + return -ESRCH; + + if (s->child.pidfd >= 0) { + siginfo_t copy; + + /* pidfd_send_signal() changes the siginfo_t argument. This is weird, let's hence copy the + * structure here */ + if (si) + copy = *si; + + if (pidfd_send_signal(s->child.pidfd, sig, si ? © : NULL, 0) < 0) { + /* Let's propagate the error only if the system call is not implemented or prohibited */ + if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) + return -errno; + } else + return 0; + } + + /* Flags are only supported for pidfd_send_signal(), not for rt_sigqueueinfo(), hence let's refuse + * this here. */ + if (flags != 0) + return -EOPNOTSUPP; + + if (si) { + /* We use rt_sigqueueinfo() only if siginfo_t is specified. */ + siginfo_t copy = *si; + + if (rt_sigqueueinfo(s->child.pid, sig, ©) < 0) + return -errno; + } else if (kill(s->child.pid, sig) < 0) + return -errno; + + return 0; +} + +_public_ int sd_event_source_get_child_pidfd_own(sd_event_source *s) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + + if (s->child.pidfd < 0) + return -EOPNOTSUPP; + + return s->child.pidfd_owned; +} + +_public_ int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + + if (s->child.pidfd < 0) + return -EOPNOTSUPP; + + s->child.pidfd_owned = own; + return 0; +} + +_public_ int sd_event_source_get_child_process_own(sd_event_source *s) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + + return s->child.process_owned; +} + +_public_ int sd_event_source_set_child_process_own(sd_event_source *s, int own) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + + s->child.process_owned = own; + return 0; +} + _public_ int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *mask) { assert_return(s, -EINVAL); assert_return(mask, -EINVAL); @@ -2542,6 +2874,12 @@ static int process_child(sd_event *e) { if (s->enabled == SD_EVENT_OFF) continue; + if (s->child.exited) + continue; + + if (EVENT_SOURCE_WATCH_PIDFD(s)) /* There's a usable pidfd known for this event source? then don't waitid() for it here */ + continue; + zero(s->child.siginfo); r = waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options); @@ -2551,6 +2889,9 @@ static int process_child(sd_event *e) { if (s->child.siginfo.si_pid != 0) { bool zombie = IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED); + if (zombie) + s->child.exited = true; + if (!zombie && (s->child.options & WEXITED)) { /* If the child isn't dead then let's * immediately remove the state change @@ -2570,6 +2911,33 @@ static int process_child(sd_event *e) { return 0; } +static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) { + assert(e); + assert(s); + assert(s->type == SOURCE_CHILD); + + if (s->pending) + return 0; + + if (s->enabled == SD_EVENT_OFF) + return 0; + + if (!EVENT_SOURCE_WATCH_PIDFD(s)) + return 0; + + zero(s->child.siginfo); + if (waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0) + return -errno; + + if (s->child.siginfo.si_pid == 0) + return 0; + + if (IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED)) + s->child.exited = true; + + return source_set_pending(s, true); +} + static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) { bool read_one = false; int r; @@ -2854,8 +3222,10 @@ static int source_dispatch(sd_event_source *s) { r = s->child.callback(s, &s->child.siginfo, s->userdata); /* Now, reap the PID for good. */ - if (zombie) + if (zombie) { (void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|WEXITED); + s->child.waited = true; + } break; } @@ -3056,6 +3426,11 @@ _public_ int sd_event_prepare(sd_event *e) { assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); + /* Let's check that if we are a default event loop we are executed in the correct thread. We only do + * this check here once, since gettid() is typically not cached, and thus want to minimize + * syscalls */ + assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO); + if (e->exit_requested) goto pending; @@ -3151,12 +3526,33 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { switch (*t) { - case WAKEUP_EVENT_SOURCE: - r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events); + case WAKEUP_EVENT_SOURCE: { + sd_event_source *s = ev_queue[i].data.ptr; + + assert(s); + + switch (s->type) { + + case SOURCE_IO: + r = process_io(e, s, ev_queue[i].events); + break; + + case SOURCE_CHILD: + r = process_pidfd(e, s, ev_queue[i].events); + break; + + default: + assert_not_reached("Unexpected event source type"); + } + break; + } case WAKEUP_CLOCK_DATA: { struct clock_data *d = ev_queue[i].data.ptr; + + assert(d); + r = flush_timer(e, d->fd, ev_queue[i].events, &d->next); break; } @@ -3481,7 +3877,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) { } else { if (e->watchdog_fd >= 0) { - epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL); + (void) epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL); e->watchdog_fd = safe_close(e->watchdog_fd); } } diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c index f8f0883caf..11ae9037a3 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.c +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c @@ -14,7 +14,7 @@ #include "stdio-util.h" #if 0 /* NM_IGNORED */ -char *id128_to_uuid_string(sd_id128_t id, char s[37]) { +char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]) { unsigned n, k = 0; assert(s); diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.h b/src/systemd/src/libsystemd/sd-id128/id128-util.h index 82a69a77f3..fe0149a8aa 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.h +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.h @@ -8,7 +8,9 @@ #include "hash-funcs.h" #include "macro.h" -char *id128_to_uuid_string(sd_id128_t id, char s[37]); +#define ID128_UUID_STRING_MAX 37 + +char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]); bool id128_is_valid(const char *s) _pure_; diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h index b14c92697b..2ec726a897 100644 --- a/src/systemd/src/systemd/sd-event.h +++ b/src/systemd/src/systemd/sd-event.h @@ -23,6 +23,7 @@ #include <sys/inotify.h> #include <sys/signalfd.h> #include <sys/types.h> +#include <sys/wait.h> #include <time.h> #include "_sd-common.h" @@ -89,6 +90,7 @@ int sd_event_add_io(sd_event *e, sd_event_source **s, int fd, uint32_t events, s int sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata); int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_signal_handler_t callback, void *userdata); int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata); +int sd_event_add_child_pidfd(sd_event *e, sd_event_source **s, int pidfd, int options, sd_event_child_handler_t callback, void *userdata); int sd_event_add_inotify(sd_event *e, sd_event_source **s, const char *path, uint32_t mask, sd_event_inotify_handler_t callback, void *userdata); int sd_event_add_defer(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); @@ -141,6 +143,16 @@ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec); int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock); int sd_event_source_get_signal(sd_event_source *s); int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid); +int sd_event_source_get_child_pidfd(sd_event_source *s); +int sd_event_source_get_child_pidfd_own(sd_event_source *s); +int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own); +int sd_event_source_get_child_process_own(sd_event_source *s); +int sd_event_source_set_child_process_own(sd_event_source *s, int own); +#if defined _GNU_SOURCE || (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L) +int sd_event_source_send_child_signal(sd_event_source *s, int sig, const siginfo_t *si, unsigned flags); +#else +int sd_event_source_send_child_signal(sd_event_source *s, int sig, const void *si, unsigned flags); +#endif int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *ret); int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback); int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret); diff --git a/src/systemd/src/systemd/sd-ipv4acd.h b/src/systemd/src/systemd/sd-ipv4acd.h index 039ed3c7f2..ebf723fc22 100644 --- a/src/systemd/src/systemd/sd-ipv4acd.h +++ b/src/systemd/src/systemd/sd-ipv4acd.h @@ -20,6 +20,7 @@ #include <net/ethernet.h> #include <netinet/in.h> +#include <stdbool.h> #include "sd-event.h" @@ -44,7 +45,7 @@ int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr); int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index); int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address); int sd_ipv4acd_is_running(sd_ipv4acd *acd); -int sd_ipv4acd_start(sd_ipv4acd *acd); +int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts); int sd_ipv4acd_stop(sd_ipv4acd *acd); sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd); sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd); |