mirror of
https://github.com/morgan9e/systemd
synced 2026-04-15 00:47:10 +09:00
sd-event: Allow passing WNOWAIT to sd_event_add_child()
This allows doing the reaping outside of the callback, we'll use this when adding fibers in a later commit.
This commit is contained in:
@@ -116,8 +116,9 @@
|
||||
parameter specifies the PID of the process to watch, which must be a direct child process of the invoking
|
||||
process. The <parameter>options</parameter> parameter determines which state changes will be watched for.
|
||||
It must contain an OR-ed mask of <constant>WEXITED</constant> (watch for the child process terminating),
|
||||
<constant>WSTOPPED</constant> (watch for the child process being stopped by a signal), and
|
||||
<constant>WCONTINUED</constant> (watch for the child process being resumed by a signal). See
|
||||
<constant>WSTOPPED</constant> (watch for the child process being stopped by a signal),
|
||||
<constant>WCONTINUED</constant> (watch for the child process being resumed by a signal) and
|
||||
<constant>WNOWAIT</constant> (Do not reap the child process after it exits). See
|
||||
<citerefentry project='man-pages'><refentrytitle>waitid</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||
for further information.</para>
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ static bool EVENT_SOURCE_WATCH_PIDFD(const 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.options == WEXITED;
|
||||
(s->child.options & ~WNOWAIT) == WEXITED;
|
||||
}
|
||||
|
||||
static bool event_source_is_online(sd_event_source *s) {
|
||||
@@ -1583,7 +1583,7 @@ _public_ int sd_event_add_child(
|
||||
assert_return(e, -EINVAL);
|
||||
assert_return(e = event_resolve(e), -ENOPKG);
|
||||
assert_return(pid > 1, -EINVAL);
|
||||
assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL);
|
||||
assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED|WNOWAIT)), -EINVAL);
|
||||
assert_return(options != 0, -EINVAL);
|
||||
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
||||
assert_return(!event_origin_changed(e), -ECHILD);
|
||||
@@ -1675,7 +1675,7 @@ _public_ int sd_event_add_child_pidfd(
|
||||
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 & ~(WEXITED|WSTOPPED|WCONTINUED|WNOWAIT)), -EINVAL);
|
||||
assert_return(options != 0, -EINVAL);
|
||||
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
||||
assert_return(!event_origin_changed(e), -ECHILD);
|
||||
@@ -3689,7 +3689,7 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori
|
||||
|
||||
zero(s->child.siginfo);
|
||||
if (waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo,
|
||||
WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options) < 0)
|
||||
WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | (s->child.options & ~WNOWAIT)) < 0)
|
||||
return negative_errno();
|
||||
|
||||
if (s->child.siginfo.si_pid != 0) {
|
||||
@@ -3737,7 +3737,6 @@ static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) {
|
||||
/* Note that pidfd would also generate EPOLLHUP when the process gets reaped. But at this point we
|
||||
* only permit EPOLLIN, under the assumption that upon EPOLLHUP the child source should already
|
||||
* be set to pending, and we would have returned early above. */
|
||||
assert(!s->child.exited);
|
||||
|
||||
zero(s->child.siginfo);
|
||||
if (waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0)
|
||||
@@ -4174,10 +4173,11 @@ static int source_dispatch(sd_event_source *s) {
|
||||
|
||||
r = s->child.callback(s, &s->child.siginfo, s->userdata);
|
||||
|
||||
/* Now, reap the PID for good. */
|
||||
/* Now, reap the PID for good (unless WNOWAIT was specified by the caller). */
|
||||
if (zombie) {
|
||||
(void) waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo, WNOHANG|WEXITED);
|
||||
s->child.waited = true;
|
||||
(void) waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo, WNOHANG|WEXITED|(s->child.options & WNOWAIT));
|
||||
if (!FLAGS_SET(s->child.options, WNOWAIT))
|
||||
s->child.waited = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -985,4 +985,84 @@ TEST(defer_add_post) {
|
||||
ASSERT_TRUE(dispatched_post);
|
||||
}
|
||||
|
||||
static int child_handler_wnowait(sd_event_source *s, const siginfo_t *si, void *userdata) {
|
||||
int *counter = ASSERT_PTR(userdata);
|
||||
|
||||
(*counter)++;
|
||||
|
||||
if (*counter == 5)
|
||||
ASSERT_OK(sd_event_exit(sd_event_source_get_event(s), 0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(child_wnowait) {
|
||||
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
|
||||
|
||||
ASSERT_OK(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD));
|
||||
|
||||
ASSERT_OK(sd_event_default(&e));
|
||||
|
||||
/* Fork a subprocess */
|
||||
pid_t pid;
|
||||
ASSERT_OK_ERRNO(pid = fork());
|
||||
|
||||
if (pid == 0)
|
||||
/* Child process - exit with a specific code */
|
||||
_exit(42);
|
||||
|
||||
/* Add a child source with WNOWAIT flag */
|
||||
_cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
|
||||
int counter = 0;
|
||||
ASSERT_OK(sd_event_add_child(e, &s, pid, WEXITED|WNOWAIT, child_handler_wnowait, &counter));
|
||||
ASSERT_OK(sd_event_source_set_enabled(s, SD_EVENT_ON));
|
||||
|
||||
/* Run the event loop - this should call the handler */
|
||||
ASSERT_OK(sd_event_loop(e));
|
||||
ASSERT_EQ(counter, 5);
|
||||
|
||||
/* Since we used WNOWAIT, the child should still be waitable */
|
||||
siginfo_t si = {};
|
||||
ASSERT_OK_ERRNO(waitid(P_PID, pid, &si, WEXITED|WNOHANG));
|
||||
ASSERT_EQ(si.si_pid, pid);
|
||||
ASSERT_EQ(si.si_code, CLD_EXITED);
|
||||
ASSERT_EQ(si.si_status, 42);
|
||||
}
|
||||
|
||||
TEST(child_pidfd_wnowait) {
|
||||
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
|
||||
|
||||
ASSERT_OK(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD));
|
||||
|
||||
ASSERT_OK(sd_event_default(&e));
|
||||
|
||||
/* Fork a subprocess */
|
||||
pid_t pid;
|
||||
ASSERT_OK_ERRNO(pid = fork());
|
||||
|
||||
if (pid == 0)
|
||||
/* Child process - exit with a specific code */
|
||||
_exit(42);
|
||||
|
||||
_cleanup_close_ int pidfd = -EBADF;
|
||||
ASSERT_OK_ERRNO(pidfd = pidfd_open(pid, 0));
|
||||
|
||||
/* Add a child source with WNOWAIT flag */
|
||||
_cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
|
||||
int counter = 0;
|
||||
ASSERT_OK(sd_event_add_child_pidfd(e, &s, pidfd, WEXITED|WNOWAIT, child_handler_wnowait, &counter));
|
||||
ASSERT_OK(sd_event_source_set_enabled(s, SD_EVENT_ON));
|
||||
|
||||
/* Run the event loop - this should call the handler */
|
||||
ASSERT_OK(sd_event_loop(e));
|
||||
ASSERT_EQ(counter, 5);
|
||||
|
||||
/* Since we used WNOWAIT, the child should still be waitable */
|
||||
siginfo_t si = {};
|
||||
ASSERT_OK_ERRNO(waitid(P_PIDFD, pidfd, &si, WEXITED|WNOHANG));
|
||||
ASSERT_EQ(si.si_pid, pid);
|
||||
ASSERT_EQ(si.si_code, CLD_EXITED);
|
||||
ASSERT_EQ(si.si_status, 42);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
|
||||
Reference in New Issue
Block a user