mirror of
https://github.com/systemd/systemd
synced 2026-03-31 12:14:57 +02:00
Compare commits
13 Commits
98ae19d9fe
...
10c79431a0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10c79431a0 | ||
|
|
bc8aebdce9 | ||
|
|
5cf894ad58 | ||
|
|
a3dd54c097 | ||
|
|
5a5cb6ba50 | ||
|
|
475729b805 | ||
|
|
c11e1001db | ||
|
|
0a79791d0a | ||
|
|
d0ddb0aafb | ||
|
|
4c8b6d636c | ||
|
|
6403a81b28 | ||
|
|
1312353fdd | ||
|
|
a0fb74153d |
@ -302,6 +302,15 @@
|
|||||||
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--same-root-dir</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Execute the <command>run0</command> session in the same root directory that the
|
||||||
|
<command>run0</command> command is executed in.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--machine=</option></term>
|
<term><option>--machine=</option></term>
|
||||||
|
|
||||||
|
|||||||
@ -116,8 +116,9 @@
|
|||||||
parameter specifies the PID of the process to watch, which must be a direct child process of the invoking
|
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.
|
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),
|
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>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). See
|
<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>
|
<citerefentry project='man-pages'><refentrytitle>waitid</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||||
for further information.</para>
|
for further information.</para>
|
||||||
|
|
||||||
|
|||||||
116
man/sd_event_set_exit_on_idle.xml
Normal file
116
man/sd_event_set_exit_on_idle.xml
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<?xml version='1.0'?>
|
||||||
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||||
|
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||||
|
|
||||||
|
<refentry id="sd_event_set_exit_on_idle" xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
|
||||||
|
<refentryinfo>
|
||||||
|
<title>sd_event_set_exit_on_idle</title>
|
||||||
|
<productname>systemd</productname>
|
||||||
|
</refentryinfo>
|
||||||
|
|
||||||
|
<refmeta>
|
||||||
|
<refentrytitle>sd_event_set_exit_on_idle</refentrytitle>
|
||||||
|
<manvolnum>3</manvolnum>
|
||||||
|
</refmeta>
|
||||||
|
|
||||||
|
<refnamediv>
|
||||||
|
<refname>sd_event_set_exit_on_idle</refname>
|
||||||
|
<refname>sd_event_get_exit_on_idle</refname>
|
||||||
|
|
||||||
|
<refpurpose>Enable event loop exit-on-idle support</refpurpose>
|
||||||
|
</refnamediv>
|
||||||
|
|
||||||
|
<refsynopsisdiv>
|
||||||
|
<funcsynopsis>
|
||||||
|
<funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo>
|
||||||
|
|
||||||
|
<funcprototype>
|
||||||
|
<funcdef>int <function>sd_event_set_exit_on_idle</function></funcdef>
|
||||||
|
<paramdef>sd_event *<parameter>event</parameter></paramdef>
|
||||||
|
<paramdef>int b</paramdef>
|
||||||
|
</funcprototype>
|
||||||
|
|
||||||
|
<funcprototype>
|
||||||
|
<funcdef>int <function>sd_event_get_exit_on_idle</function></funcdef>
|
||||||
|
<paramdef>sd_event *<parameter>event</parameter></paramdef>
|
||||||
|
</funcprototype>
|
||||||
|
|
||||||
|
</funcsynopsis>
|
||||||
|
</refsynopsisdiv>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Description</title>
|
||||||
|
|
||||||
|
<para><function>sd_event_set_exit_on_idle()</function> may be used to
|
||||||
|
enable or disable the exit-on-idle support in the
|
||||||
|
event loop object specified in the <parameter>event</parameter>
|
||||||
|
parameter. If enabled, the event loop will exit with a zero exit code
|
||||||
|
there are no more enabled (<constant>SD_EVENT_ON</constant>, <constant>SD_EVENT_ONESHOT</constant>),
|
||||||
|
non-exit, non-post event sources.</para>
|
||||||
|
|
||||||
|
<para><function>sd_event_get_exit_on_idle()</function> may be used to
|
||||||
|
determine whether exit-on-idle support was previously requested by a
|
||||||
|
call to <function>sd_event_set_exit_on_idle()</function> with a true
|
||||||
|
<parameter>b</parameter> parameter and successfully enabled.</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Return Value</title>
|
||||||
|
|
||||||
|
<para>On success, <function>sd_event_set_exit_on_idle()</function> and
|
||||||
|
<function>sd_event_get_exit_on_idle()</function> return a non-zero positive integer if the exit-on-idle
|
||||||
|
support was successfully enabled. They return zero if the exit-on-idle support was explicitly disabled
|
||||||
|
with a false <parameter>b</parameter> parameter. On failure, they return a negative errno-style error
|
||||||
|
code.</para>
|
||||||
|
|
||||||
|
<refsect2>
|
||||||
|
<title>Errors</title>
|
||||||
|
|
||||||
|
<para>Returned errors may indicate the following problems:</para>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><constant>-ECHILD</constant></term>
|
||||||
|
|
||||||
|
<listitem><para>The event loop has been created in a different process, library or module instance.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><constant>-EINVAL</constant></term>
|
||||||
|
|
||||||
|
<listitem><para>The passed event loop object was invalid.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
</refsect2>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<xi:include href="libsystemd-pkgconfig.xml" />
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>History</title>
|
||||||
|
<para><function>sd_event_set_exit_on_idle()</function> and
|
||||||
|
<function>sd_event_get_exit_on_idle()</function> were added in version 259.</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>See Also</title>
|
||||||
|
|
||||||
|
<para><simplelist type="inline">
|
||||||
|
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry><refentrytitle>sd_event_add_inotify</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry></member>
|
||||||
|
<member><citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
|
||||||
|
</simplelist></para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
</refentry>
|
||||||
@ -94,6 +94,7 @@ typedef enum TimestampStyle TimestampStyle;
|
|||||||
typedef enum UnitActiveState UnitActiveState;
|
typedef enum UnitActiveState UnitActiveState;
|
||||||
typedef enum UnitDependency UnitDependency;
|
typedef enum UnitDependency UnitDependency;
|
||||||
typedef enum UnitType UnitType;
|
typedef enum UnitType UnitType;
|
||||||
|
typedef enum WaitFlags WaitFlags;
|
||||||
|
|
||||||
typedef struct Hashmap Hashmap;
|
typedef struct Hashmap Hashmap;
|
||||||
typedef struct HashmapBase HashmapBase;
|
typedef struct HashmapBase HashmapBase;
|
||||||
|
|||||||
@ -58,7 +58,9 @@ static LogContext* log_context_detach(LogContext *c) {
|
|||||||
LogContext* log_context_new(const char *key, const char *value) {
|
LogContext* log_context_new(const char *key, const char *value) {
|
||||||
assert(key);
|
assert(key);
|
||||||
assert(endswith(key, "="));
|
assert(endswith(key, "="));
|
||||||
assert(value);
|
|
||||||
|
if (!value)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
LIST_FOREACH(ll, i, _log_context)
|
LIST_FOREACH(ll, i, _log_context)
|
||||||
if (i->key == key && i->value == value)
|
if (i->key == key && i->value == value)
|
||||||
|
|||||||
@ -1081,5 +1081,7 @@ global:
|
|||||||
|
|
||||||
LIBSYSTEMD_259 {
|
LIBSYSTEMD_259 {
|
||||||
global:
|
global:
|
||||||
|
sd_event_set_exit_on_idle;
|
||||||
|
sd_event_get_exit_on_idle;
|
||||||
sd_varlink_is_connected;
|
sd_varlink_is_connected;
|
||||||
} LIBSYSTEMD_258;
|
} LIBSYSTEMD_258;
|
||||||
|
|||||||
@ -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 */
|
/* Returns true if this is a PID event source and can be implemented by watching EPOLLIN */
|
||||||
return s &&
|
return s &&
|
||||||
s->type == SOURCE_CHILD &&
|
s->type == SOURCE_CHILD &&
|
||||||
s->child.options == WEXITED;
|
(s->child.options & ~WNOWAIT) == WEXITED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool event_source_is_online(sd_event_source *s) {
|
static bool event_source_is_online(sd_event_source *s) {
|
||||||
@ -157,6 +157,7 @@ struct sd_event {
|
|||||||
bool need_process_child:1;
|
bool need_process_child:1;
|
||||||
bool watchdog:1;
|
bool watchdog:1;
|
||||||
bool profile_delays:1;
|
bool profile_delays:1;
|
||||||
|
bool exit_on_idle:1;
|
||||||
|
|
||||||
int exit_code;
|
int exit_code;
|
||||||
|
|
||||||
@ -1583,7 +1584,7 @@ _public_ int sd_event_add_child(
|
|||||||
assert_return(e, -EINVAL);
|
assert_return(e, -EINVAL);
|
||||||
assert_return(e = event_resolve(e), -ENOPKG);
|
assert_return(e = event_resolve(e), -ENOPKG);
|
||||||
assert_return(pid > 1, -EINVAL);
|
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(options != 0, -EINVAL);
|
||||||
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
||||||
assert_return(!event_origin_changed(e), -ECHILD);
|
assert_return(!event_origin_changed(e), -ECHILD);
|
||||||
@ -1675,7 +1676,7 @@ _public_ int sd_event_add_child_pidfd(
|
|||||||
assert_return(e, -EINVAL);
|
assert_return(e, -EINVAL);
|
||||||
assert_return(e = event_resolve(e), -ENOPKG);
|
assert_return(e = event_resolve(e), -ENOPKG);
|
||||||
assert_return(pidfd >= 0, -EBADF);
|
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(options != 0, -EINVAL);
|
||||||
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
|
||||||
assert_return(!event_origin_changed(e), -ECHILD);
|
assert_return(!event_origin_changed(e), -ECHILD);
|
||||||
@ -2987,9 +2988,11 @@ static int event_source_online(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SOURCE_MEMORY_PRESSURE:
|
case SOURCE_MEMORY_PRESSURE:
|
||||||
|
if (s->memory_pressure.write_buffer_size == 0) {
|
||||||
r = source_memory_pressure_register(s, enabled);
|
r = source_memory_pressure_register(s, enabled);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -3042,16 +3045,8 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) {
|
|||||||
|
|
||||||
if (m == SD_EVENT_OFF)
|
if (m == SD_EVENT_OFF)
|
||||||
r = event_source_offline(s, m, s->ratelimited);
|
r = event_source_offline(s, m, s->ratelimited);
|
||||||
else {
|
else
|
||||||
if (s->enabled != SD_EVENT_OFF) {
|
|
||||||
/* Switching from "on" to "oneshot" or back? If that's the case, we can take a shortcut, the
|
|
||||||
* event source is already enabled after all. */
|
|
||||||
s->enabled = m;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = event_source_online(s, m, s->ratelimited);
|
r = event_source_online(s, m, s->ratelimited);
|
||||||
}
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -3695,7 +3690,7 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori
|
|||||||
|
|
||||||
zero(s->child.siginfo);
|
zero(s->child.siginfo);
|
||||||
if (waitid(P_PIDFD, s->child.pidfd, &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();
|
return negative_errno();
|
||||||
|
|
||||||
if (s->child.siginfo.si_pid != 0) {
|
if (s->child.siginfo.si_pid != 0) {
|
||||||
@ -3743,7 +3738,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
|
/* 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
|
* 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. */
|
* be set to pending, and we would have returned early above. */
|
||||||
assert(!s->child.exited);
|
|
||||||
|
|
||||||
zero(s->child.siginfo);
|
zero(s->child.siginfo);
|
||||||
if (waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0)
|
if (waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0)
|
||||||
@ -4083,6 +4077,22 @@ static int source_memory_pressure_initiate_dispatch(sd_event_source *s) {
|
|||||||
return 0; /* go on, dispatch to user callback */
|
return 0; /* go on, dispatch to user callback */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mark_post_sources_pending(sd_event *e) {
|
||||||
|
sd_event_source *z;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
SET_FOREACH(z, e->post_sources) {
|
||||||
|
if (event_source_is_offline(z))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
r = source_set_pending(z, true);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int source_dispatch(sd_event_source *s) {
|
static int source_dispatch(sd_event_source *s) {
|
||||||
EventSourceType saved_type;
|
EventSourceType saved_type;
|
||||||
sd_event *saved_event;
|
sd_event *saved_event;
|
||||||
@ -4110,26 +4120,24 @@ static int source_dispatch(sd_event_source *s) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
if (IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) {
|
||||||
|
/* Make sure this event source is moved to the end of the priority list now. We do this here
|
||||||
|
* because defer and exit event sources are always pending from the moment they're added so
|
||||||
|
* the same logic in source_set_pending() is never triggered. */
|
||||||
|
s->pending_iteration = s->event->iteration;
|
||||||
|
event_source_pp_prioq_reshuffle(s);
|
||||||
|
} else {
|
||||||
r = source_set_pending(s, false);
|
r = source_set_pending(s, false);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->type != SOURCE_POST) {
|
if (s->type != SOURCE_POST) {
|
||||||
sd_event_source *z;
|
|
||||||
|
|
||||||
/* If we execute a non-post source, let's mark all post sources as pending. */
|
/* If we execute a non-post source, let's mark all post sources as pending. */
|
||||||
|
r = mark_post_sources_pending(s->event);
|
||||||
SET_FOREACH(z, s->event->post_sources) {
|
|
||||||
if (event_source_is_offline(z))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
r = source_set_pending(z, true);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (s->type == SOURCE_MEMORY_PRESSURE) {
|
if (s->type == SOURCE_MEMORY_PRESSURE) {
|
||||||
r = source_memory_pressure_initiate_dispatch(s);
|
r = source_memory_pressure_initiate_dispatch(s);
|
||||||
@ -4172,9 +4180,10 @@ static int source_dispatch(sd_event_source *s) {
|
|||||||
|
|
||||||
r = s->child.callback(s, &s->child.siginfo, s->userdata);
|
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) {
|
if (zombie) {
|
||||||
(void) waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo, WNOHANG|WEXITED);
|
(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;
|
s->child.waited = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4237,6 +4246,14 @@ static int source_dispatch(sd_event_source *s) {
|
|||||||
|
|
||||||
s->dispatching = false;
|
s->dispatching = false;
|
||||||
|
|
||||||
|
if (saved_type != SOURCE_POST) {
|
||||||
|
/* More post sources might have been added while executing the callback, let's make sure
|
||||||
|
* those are marked pending as well. */
|
||||||
|
r = mark_post_sources_pending(saved_event);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_debug_errno(r, "Event source %s (type %s) returned error, %s: %m",
|
log_debug_errno(r, "Event source %s (type %s) returned error, %s: %m",
|
||||||
@ -4412,6 +4429,28 @@ static int event_memory_pressure_write_list(sd_event *e) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool event_loop_idle(sd_event *e) {
|
||||||
|
assert(e);
|
||||||
|
|
||||||
|
LIST_FOREACH(sources, s, e->sources) {
|
||||||
|
/* Exit sources only trigger on exit, so whether they're enabled or not doesn't matter when
|
||||||
|
* we're deciding if the event loop is idle or not. */
|
||||||
|
if (s->type == SOURCE_EXIT)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (s->enabled == SD_EVENT_OFF)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Post event sources always need another active event source to become pending. */
|
||||||
|
if (s->type == SOURCE_POST && !s->pending)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
_public_ int sd_event_prepare(sd_event *e) {
|
_public_ int sd_event_prepare(sd_event *e) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -4429,6 +4468,9 @@ _public_ int sd_event_prepare(sd_event *e) {
|
|||||||
/* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */
|
/* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */
|
||||||
PROTECT_EVENT(e);
|
PROTECT_EVENT(e);
|
||||||
|
|
||||||
|
if (!e->exit_requested && e->exit_on_idle && event_loop_idle(e))
|
||||||
|
(void) sd_event_exit(e, 0);
|
||||||
|
|
||||||
if (e->exit_requested)
|
if (e->exit_requested)
|
||||||
goto pending;
|
goto pending;
|
||||||
|
|
||||||
@ -5233,6 +5275,22 @@ _public_ int sd_event_set_signal_exit(sd_event *e, int b) {
|
|||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_public_ int sd_event_set_exit_on_idle(sd_event *e, int b) {
|
||||||
|
assert_return(e, -EINVAL);
|
||||||
|
assert_return(e = event_resolve(e), -ENOPKG);
|
||||||
|
assert_return(!event_origin_changed(e), -ECHILD);
|
||||||
|
|
||||||
|
return e->exit_on_idle = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
_public_ int sd_event_get_exit_on_idle(sd_event *e) {
|
||||||
|
assert_return(e, -EINVAL);
|
||||||
|
assert_return(e = event_resolve(e), -ENOPKG);
|
||||||
|
assert_return(!event_origin_changed(e), -ECHILD);
|
||||||
|
|
||||||
|
return e->exit_on_idle;
|
||||||
|
}
|
||||||
|
|
||||||
_public_ int sd_event_source_set_memory_pressure_type(sd_event_source *s, const char *ty) {
|
_public_ int sd_event_source_set_memory_pressure_type(sd_event_source *s, const char *ty) {
|
||||||
_cleanup_free_ char *b = NULL;
|
_cleanup_free_ char *b = NULL;
|
||||||
_cleanup_free_ void *w = NULL;
|
_cleanup_free_ void *w = NULL;
|
||||||
|
|||||||
@ -946,4 +946,225 @@ TEST(leave_ratelimit) {
|
|||||||
ASSERT_TRUE(manually_left_ratelimit);
|
ASSERT_TRUE(manually_left_ratelimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int defer_post_handler(sd_event_source *s, void *userdata) {
|
||||||
|
bool *dispatched_post = ASSERT_PTR(userdata);
|
||||||
|
|
||||||
|
*dispatched_post = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int defer_adds_post_handler(sd_event_source *s, void *userdata) {
|
||||||
|
sd_event *e = sd_event_source_get_event(s);
|
||||||
|
|
||||||
|
/* Add a post event source from within the defer handler */
|
||||||
|
ASSERT_OK(sd_event_add_post(e, NULL, defer_post_handler, userdata));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(defer_add_post) {
|
||||||
|
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
|
||||||
|
bool dispatched_post = false;
|
||||||
|
|
||||||
|
ASSERT_OK(sd_event_default(&e));
|
||||||
|
|
||||||
|
/* Add a oneshot defer event source that will add a post event source */
|
||||||
|
ASSERT_OK(sd_event_add_defer(e, NULL, defer_adds_post_handler, &dispatched_post));
|
||||||
|
|
||||||
|
/* Run one iteration - this should dispatch the defer handler */
|
||||||
|
ASSERT_OK_POSITIVE(sd_event_run(e, UINT64_MAX));
|
||||||
|
|
||||||
|
/* The post handler should have been added but not yet dispatched */
|
||||||
|
ASSERT_FALSE(dispatched_post);
|
||||||
|
|
||||||
|
/* Run another iteration - this should dispatch the post handler */
|
||||||
|
ASSERT_OK_POSITIVE(sd_event_run(e, 0));
|
||||||
|
|
||||||
|
/* Now the post handler should have been dispatched */
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int exit_on_idle_defer_handler(sd_event_source *s, void *userdata) {
|
||||||
|
unsigned *c = ASSERT_PTR(userdata);
|
||||||
|
|
||||||
|
/* Should not be reached on third call because the event loop should exit before */
|
||||||
|
ASSERT_LT(*c, 2u);
|
||||||
|
|
||||||
|
(*c)++;
|
||||||
|
|
||||||
|
/* Disable ourselves, which should trigger exit-on-idle after the second iteration */
|
||||||
|
if (*c == 2)
|
||||||
|
sd_event_source_set_enabled(s, SD_EVENT_OFF);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int exit_on_idle_post_handler(sd_event_source *s, void *userdata) {
|
||||||
|
unsigned *c = ASSERT_PTR(userdata);
|
||||||
|
|
||||||
|
/* Should not be reached on third call because the event loop should exit before */
|
||||||
|
ASSERT_LT(*c, 2u);
|
||||||
|
|
||||||
|
(*c)++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int exit_on_idle_exit_handler(sd_event_source *s, void *userdata) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(exit_on_idle) {
|
||||||
|
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
|
||||||
|
ASSERT_OK(sd_event_new(&e));
|
||||||
|
ASSERT_OK(sd_event_set_exit_on_idle(e, true));
|
||||||
|
ASSERT_OK_POSITIVE(sd_event_get_exit_on_idle(e));
|
||||||
|
|
||||||
|
/* Create a recurring defer event source. */
|
||||||
|
_cleanup_(sd_event_source_unrefp) sd_event_source *d = NULL;
|
||||||
|
unsigned dc = 0;
|
||||||
|
ASSERT_OK(sd_event_add_defer(e, &d, exit_on_idle_defer_handler, &dc));
|
||||||
|
ASSERT_OK(sd_event_source_set_enabled(d, SD_EVENT_ON));
|
||||||
|
|
||||||
|
/* This post event source should not keep the event loop running after the defer source is disabled. */
|
||||||
|
_cleanup_(sd_event_source_unrefp) sd_event_source *p = NULL;
|
||||||
|
unsigned pc = 0;
|
||||||
|
ASSERT_OK(sd_event_add_post(e, &p, exit_on_idle_post_handler, &pc));
|
||||||
|
ASSERT_OK(sd_event_source_set_enabled(p, SD_EVENT_ON));
|
||||||
|
ASSERT_OK(sd_event_source_set_priority(p, SD_EVENT_PRIORITY_IMPORTANT));
|
||||||
|
|
||||||
|
/* And neither should this exit event source. */
|
||||||
|
ASSERT_OK(sd_event_add_exit(e, NULL, exit_on_idle_exit_handler, NULL));
|
||||||
|
|
||||||
|
/* Run the event loop - it should exit after we disable the event source */
|
||||||
|
ASSERT_OK(sd_event_loop(e));
|
||||||
|
ASSERT_EQ(dc, 2u);
|
||||||
|
ASSERT_EQ(pc, 2u);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(exit_on_idle_no_sources) {
|
||||||
|
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
|
||||||
|
ASSERT_OK(sd_event_new(&e));
|
||||||
|
ASSERT_OK(sd_event_set_exit_on_idle(e, true));
|
||||||
|
|
||||||
|
/* Running loop with no sources should return immediately with success */
|
||||||
|
ASSERT_OK(sd_event_loop(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int defer_fair_handler(sd_event_source *s, void *userdata) {
|
||||||
|
unsigned *counter = ASSERT_PTR(userdata);
|
||||||
|
|
||||||
|
/* If we're about to increment above 5, exit the event loop */
|
||||||
|
if (*counter >= 5)
|
||||||
|
return sd_event_exit(sd_event_source_get_event(s), 0);
|
||||||
|
|
||||||
|
(*counter)++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(defer_fair_scheduling) {
|
||||||
|
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
|
||||||
|
sd_event_source *sources[5] = {};
|
||||||
|
unsigned counters[5] = {};
|
||||||
|
|
||||||
|
ASSERT_OK(sd_event_new(&e));
|
||||||
|
ASSERT_OK(sd_event_set_exit_on_idle(e, true));
|
||||||
|
|
||||||
|
/* Create 5 defer sources with equal priority */
|
||||||
|
for (unsigned i = 0; i < 5; i++) {
|
||||||
|
ASSERT_OK(sd_event_add_defer(e, &sources[i], defer_fair_handler, &counters[i]));
|
||||||
|
ASSERT_OK(sd_event_source_set_enabled(sources[i], SD_EVENT_ON));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Run the event loop until one of the handlers exits */
|
||||||
|
ASSERT_OK(sd_event_loop(e));
|
||||||
|
|
||||||
|
/* All counters should be equal to 5, demonstrating fair scheduling */
|
||||||
|
for (unsigned i = 0; i < 5; i++) {
|
||||||
|
ASSERT_EQ(counters[i], 5u);
|
||||||
|
sd_event_source_unref(sources[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||||
|
|||||||
@ -899,6 +899,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
|||||||
ARG_AREA,
|
ARG_AREA,
|
||||||
ARG_VIA_SHELL,
|
ARG_VIA_SHELL,
|
||||||
ARG_EMPOWER,
|
ARG_EMPOWER,
|
||||||
|
ARG_SAME_ROOT_DIR,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions
|
/* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions
|
||||||
@ -929,6 +930,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
|||||||
{ "lightweight", required_argument, NULL, ARG_LIGHTWEIGHT },
|
{ "lightweight", required_argument, NULL, ARG_LIGHTWEIGHT },
|
||||||
{ "area", required_argument, NULL, ARG_AREA },
|
{ "area", required_argument, NULL, ARG_AREA },
|
||||||
{ "empower", no_argument, NULL, ARG_EMPOWER },
|
{ "empower", no_argument, NULL, ARG_EMPOWER },
|
||||||
|
{ "same-root-dir", no_argument, NULL, ARG_SAME_ROOT_DIR },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1072,6 +1074,13 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
|||||||
arg_empower = true;
|
arg_empower = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_SAME_ROOT_DIR:
|
||||||
|
r = free_and_strdup_warn(&arg_root_directory, "/");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
|||||||
@ -116,6 +116,8 @@ int sd_event_set_watchdog(sd_event *e, int b);
|
|||||||
int sd_event_get_watchdog(sd_event *e);
|
int sd_event_get_watchdog(sd_event *e);
|
||||||
int sd_event_get_iteration(sd_event *e, uint64_t *ret);
|
int sd_event_get_iteration(sd_event *e, uint64_t *ret);
|
||||||
int sd_event_set_signal_exit(sd_event *e, int b);
|
int sd_event_set_signal_exit(sd_event *e, int b);
|
||||||
|
int sd_event_set_exit_on_idle(sd_event *e, int b);
|
||||||
|
int sd_event_get_exit_on_idle(sd_event *e);
|
||||||
|
|
||||||
sd_event_source* sd_event_source_ref(sd_event_source *s);
|
sd_event_source* sd_event_source_ref(sd_event_source *s);
|
||||||
sd_event_source* sd_event_source_unref(sd_event_source *s);
|
sd_event_source* sd_event_source_unref(sd_event_source *s);
|
||||||
|
|||||||
@ -527,7 +527,9 @@ TEST(cgroupid) {
|
|||||||
|
|
||||||
fd2 = cg_cgroupid_open(fd, id);
|
fd2 = cg_cgroupid_open(fd, id);
|
||||||
|
|
||||||
if (ERRNO_IS_NEG_PRIVILEGE(fd2))
|
/* The kernel converts a bunch of errors to ESTALE in the open_by_handle_at() codepath so we treat
|
||||||
|
* it as missing privs but it could be absolutely anything really. */
|
||||||
|
if (ERRNO_IS_NEG_PRIVILEGE(fd2) || fd2 == -ESTALE)
|
||||||
log_notice("Skipping open-by-cgroup-id test because lacking privs.");
|
log_notice("Skipping open-by-cgroup-id test because lacking privs.");
|
||||||
else if (ERRNO_IS_NEG_NOT_SUPPORTED(fd2))
|
else if (ERRNO_IS_NEG_NOT_SUPPORTED(fd2))
|
||||||
log_notice("Skipping open-by-cgroup-id test because syscall is missing or blocked.");
|
log_notice("Skipping open-by-cgroup-id test because syscall is missing or blocked.");
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
#include "sd-id128.h"
|
#include "sd-id128.h"
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
|
#include "capability-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "id128-util.h"
|
#include "id128-util.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
@ -278,7 +279,7 @@ TEST(id128_at) {
|
|||||||
ASSERT_OK(sd_id128_randomize(&id));
|
ASSERT_OK(sd_id128_randomize(&id));
|
||||||
|
|
||||||
ASSERT_OK(id128_write_at(tfd, "etc/machine-id", ID128_FORMAT_PLAIN, id));
|
ASSERT_OK(id128_write_at(tfd, "etc/machine-id", ID128_FORMAT_PLAIN, id));
|
||||||
if (geteuid() == 0)
|
if (have_effective_cap(CAP_DAC_OVERRIDE))
|
||||||
ASSERT_OK(id128_write_at(tfd, "etc/machine-id", ID128_FORMAT_PLAIN, id));
|
ASSERT_OK(id128_write_at(tfd, "etc/machine-id", ID128_FORMAT_PLAIN, id));
|
||||||
else
|
else
|
||||||
ASSERT_ERROR(id128_write_at(tfd, "etc/machine-id", ID128_FORMAT_PLAIN, id), EACCES);
|
ASSERT_ERROR(id128_write_at(tfd, "etc/machine-id", ID128_FORMAT_PLAIN, id), EACCES);
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "capability-util.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "rm-rf.h"
|
#include "rm-rf.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
@ -29,6 +30,7 @@ static void test_rm_rf_chmod_inner(void) {
|
|||||||
ASSERT_OK_ERRNO(chmod(x, 0500));
|
ASSERT_OK_ERRNO(chmod(x, 0500));
|
||||||
ASSERT_OK_ERRNO(chmod(d, 0500));
|
ASSERT_OK_ERRNO(chmod(d, 0500));
|
||||||
|
|
||||||
|
if (!have_effective_cap(CAP_DAC_OVERRIDE))
|
||||||
ASSERT_ERROR(rm_rf(d, REMOVE_PHYSICAL), EACCES);
|
ASSERT_ERROR(rm_rf(d, REMOVE_PHYSICAL), EACCES);
|
||||||
|
|
||||||
ASSERT_OK_ERRNO(access(d, F_OK));
|
ASSERT_OK_ERRNO(access(d, F_OK));
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user