<refname>sd_event_add_signal</refname>
<refname>sd_event_source_get_signal</refname>
<refname>sd_event_signal_handler_t</refname>
+ <refname>SD_EVENT_SIGNAL_PROCMASK</refname>
<refpurpose>Add a UNIX process signal event source to an event
loop</refpurpose>
<funcsynopsisinfo><token>typedef</token> struct sd_event_source sd_event_source;</funcsynopsisinfo>
+ <funcsynopsisinfo><constant>SD_EVENT_SIGNAL_PROCMASK</constant></funcsynopsisinfo>
+
<funcprototype>
<funcdef>typedef int (*<function>sd_event_signal_handler_t</function>)</funcdef>
<paramdef>sd_event_source *<parameter>s</parameter></paramdef>
<funcdef>int <function>sd_event_source_get_signal</function></funcdef>
<paramdef>sd_event_source *<parameter>source</parameter></paramdef>
</funcprototype>
-
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
- <para><function>sd_event_add_signal()</function> adds a new UNIX
- process signal event source to an event loop. The event loop
- object is specified in the <parameter>event</parameter> parameter,
- and the event source object is returned in the
- <parameter>source</parameter> parameter. The
- <parameter>signal</parameter> parameter specifies the numeric
- signal to be handled (see <citerefentry
+ <para><function>sd_event_add_signal()</function> adds a new UNIX process signal event source to an event
+ loop. The event loop object is specified in the <parameter>event</parameter> parameter, and the event
+ source object is returned in the <parameter>source</parameter> parameter. The
+ <parameter>signal</parameter> parameter specifies the numeric signal to be handled (see <citerefentry
project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>).</para>
<para>The <parameter>handler</parameter> parameter is a function to call when the signal is received or
<constant>NULL</constant>. The handler function will be passed the <parameter>userdata</parameter>
pointer, which may be chosen freely by the caller. The handler also receives a pointer to a
<structname>signalfd_siginfo</structname> structure containing information about the received signal. See
- <citerefentry project='man-pages'><refentrytitle>signalfd</refentrytitle><manvolnum>2</manvolnum></citerefentry>
- for further information. The handler may return negative to signal an error (see below), other return
- values are ignored. If <parameter>handler</parameter> is <constant>NULL</constant>, a default handler
- that calls
+ <citerefentry
+ project='man-pages'><refentrytitle>signalfd</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
+ further information. The handler may return negative to signal an error (see below), other return values
+ are ignored. If <parameter>handler</parameter> is <constant>NULL</constant>, a default handler that calls
<citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry> will be
used.</para>
threads before this function is called (using <citerefentry
project='man-pages'><refentrytitle>sigprocmask</refentrytitle><manvolnum>2</manvolnum></citerefentry> or
<citerefentry
- project='man-pages'><refentrytitle>pthread_sigmask</refentrytitle><manvolnum>3</manvolnum></citerefentry>).</para>
-
- <para>By default, the event source is enabled permanently
- (<constant>SD_EVENT_ON</constant>), but this may be changed with
+ project='man-pages'><refentrytitle>pthread_sigmask</refentrytitle><manvolnum>3</manvolnum></citerefentry>). For
+ convenience, if the special flag <constant>SD_EVENT_SIGNAL_PROCMASK</constant> is ORed into the specified
+ signal the signal will be automatically masked as necessary, for the calling thread. Note that this only
+ works reliably if the signal is already masked in all other threads of the process, or if there are no
+ other threads at the moment of invocation.</para>
+
+ <para>By default, the event source is enabled permanently (<constant>SD_EVENT_ON</constant>), but this
+ may be changed with
<citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
- If the handler function returns a negative error code, it will either be disabled after the
- invocation, even if the <constant>SD_EVENT_ON</constant> mode was requested before, or it will cause the
- loop to terminate, see
+ If the handler function returns a negative error code, it will either be disabled after the invocation,
+ even if the <constant>SD_EVENT_ON</constant> mode was requested before, or it will cause the loop to
+ terminate, see
<citerefentry><refentrytitle>sd_event_source_set_exit_on_failure</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para>
static void source_disconnect(sd_event_source *s) {
sd_event *event;
+ int r;
assert(s);
s->event->signal_sources[s->signal.sig] = NULL;
event_gc_signal_data(s->event, &s->priority, s->signal.sig);
+
+ if (s->signal.unblock) {
+ sigset_t new_ss;
+
+ if (sigemptyset(&new_ss) < 0)
+ log_debug_errno(errno, "Failed to reset signal set, ignoring: %m");
+ else if (sigaddset(&new_ss, s->signal.sig) < 0)
+ log_debug_errno(errno, "Failed to add signal %i to signal mask, ignoring: %m", s->signal.sig);
+ else {
+ r = pthread_sigmask(SIG_UNBLOCK, &new_ss, NULL);
+ if (r != 0)
+ log_debug_errno(r, "Failed to unblock signal %i, ignoring: %m", s->signal.sig);
+ }
+ }
}
break;
_cleanup_(source_freep) sd_event_source *s = NULL;
struct signal_data *d;
+ sigset_t new_ss;
+ bool block_it;
int r;
assert_return(e, -EINVAL);
assert_return(e = event_resolve(e), -ENOPKG);
- assert_return(SIGNAL_VALID(sig), -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
+ /* Let's make sure our special flag stays outside of the valid signal range */
+ assert_cc(_NSIG < SD_EVENT_SIGNAL_PROCMASK);
+
+ if (sig & SD_EVENT_SIGNAL_PROCMASK) {
+ sig &= ~SD_EVENT_SIGNAL_PROCMASK;
+ assert_return(SIGNAL_VALID(sig), -EINVAL);
+
+ block_it = true;
+ } else {
+ assert_return(SIGNAL_VALID(sig), -EINVAL);
+
+ r = signal_is_blocked(sig);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -EBUSY;
+
+ block_it = false;
+ }
+
if (!callback)
callback = signal_exit_callback;
- r = signal_is_blocked(sig);
- if (r < 0)
- return r;
- if (r == 0)
- return -EBUSY;
-
if (!e->signal_sources) {
e->signal_sources = new0(sd_event_source*, _NSIG);
if (!e->signal_sources)
e->signal_sources[sig] = s;
+ if (block_it) {
+ sigset_t old_ss;
+
+ if (sigemptyset(&new_ss) < 0)
+ return -errno;
+
+ if (sigaddset(&new_ss, sig) < 0)
+ return -errno;
+
+ r = pthread_sigmask(SIG_BLOCK, &new_ss, &old_ss);
+ if (r != 0)
+ return -r;
+
+ r = sigismember(&old_ss, sig);
+ if (r < 0)
+ return -errno;
+
+ s->signal.unblock = !r;
+ } else
+ s->signal.unblock = false;
+
r = event_make_signal_data(e, sig, &d);
- if (r < 0)
+ if (r < 0) {
+ if (s->signal.unblock)
+ (void) pthread_sigmask(SIG_UNBLOCK, &new_ss, NULL);
+
return r;
+ }
/* Use the signal name as description for the event source by default */
(void) sd_event_source_set_description(s, signal_to_string(sig));