|
Packit |
5e354d |
/* npth-sigev.c - signal handling interface
|
|
Packit |
5e354d |
* Copyright (C) 2011 g10 Code GmbH
|
|
Packit |
5e354d |
*
|
|
Packit |
5e354d |
* This file is part of nPth.
|
|
Packit |
5e354d |
*
|
|
Packit |
5e354d |
* nPth is free software; you can redistribute it and/or modify
|
|
Packit |
5e354d |
* it under the terms of the GNU Lesser General Public License as
|
|
Packit |
5e354d |
* published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
5e354d |
* the License, or (at your option) any later version.
|
|
Packit |
5e354d |
*
|
|
Packit |
5e354d |
* nPth is distributed in the hope that it will be useful, but
|
|
Packit |
5e354d |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
5e354d |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
|
Packit |
5e354d |
* the GNU Lesser General Public License for more details.
|
|
Packit |
5e354d |
*
|
|
Packit |
5e354d |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
5e354d |
* License along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
Packit |
5e354d |
*/
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
/* This is a support interface to make it easier to handle signals.
|
|
Packit |
5e354d |
*
|
|
Packit |
5e354d |
* The interfaces here support one (and only one) thread (here called
|
|
Packit |
5e354d |
* "main thread") in the application to monitor several signals while
|
|
Packit |
5e354d |
* selecting on filedescriptors.
|
|
Packit |
5e354d |
*
|
|
Packit |
5e354d |
* First, the main thread should call npth_sigev_init. This
|
|
Packit |
5e354d |
* initializes some global data structures used to record interesting
|
|
Packit |
5e354d |
* and pending signals.
|
|
Packit |
5e354d |
*
|
|
Packit |
5e354d |
* Then, the main thread should call npth_sigev_add for every signal
|
|
Packit |
5e354d |
* it is interested in observing, and finally npth_sigev_fini. This
|
|
Packit |
5e354d |
* will block the signal in the main threads sigmask. Note that these
|
|
Packit |
5e354d |
* signals should also be blocked in all other threads. Since they
|
|
Packit |
5e354d |
* are blocked in the main thread after calling npth_sigev_add, it is
|
|
Packit |
5e354d |
* recommended to call npth_sigev_add in the main thread before
|
|
Packit |
5e354d |
* creating any threads.
|
|
Packit |
5e354d |
*
|
|
Packit |
5e354d |
* The function npth_sigev_sigmask is a convenient function that
|
|
Packit |
5e354d |
* returns the sigmask of the thread at time of npth_sigev_init, but
|
|
Packit |
5e354d |
* with all registered signals unblocked. It is recommended to do all
|
|
Packit |
5e354d |
* other changes to the main thread's sigmask before calling
|
|
Packit |
5e354d |
* npth_sigev_init, so that the return value of npth_sigev_sigmask can
|
|
Packit |
5e354d |
* be used in the npth_pselect invocation.
|
|
Packit |
5e354d |
*
|
|
Packit |
5e354d |
* In any case, the main thread should invoke npth_pselect with a
|
|
Packit |
5e354d |
* sigmask that has all signals that should be monitored unblocked.
|
|
Packit |
5e354d |
*
|
|
Packit |
5e354d |
* After npth_pselect returns, npth_sigev_get_pending can be called in
|
|
Packit |
5e354d |
* a loop until it returns 0 to iterate over the list of pending
|
|
Packit |
5e354d |
* signals. Each time a signal is returned by that function, its
|
|
Packit |
5e354d |
* status is reset to non-pending.
|
|
Packit |
5e354d |
*/
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
#ifdef HAVE_CONFIG_H
|
|
Packit |
5e354d |
#include <config.h>
|
|
Packit |
5e354d |
#endif
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
#include <signal.h>
|
|
Packit |
5e354d |
#include <assert.h>
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
#include "npth.h"
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
/* Record events that have been noticed. */
|
|
Packit |
5e354d |
static sigset_t sigev_pending;
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
/* The signal mask during normal operation. */
|
|
Packit |
5e354d |
static sigset_t sigev_block;
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
/* The signal mask during pselect. */
|
|
Packit |
5e354d |
static sigset_t sigev_unblock;
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
/* Registered signal numbers. Needed to iterate over sigset_t.
|
|
Packit |
5e354d |
Bah. */
|
|
Packit |
5e354d |
#define SIGEV_MAX 32
|
|
Packit |
5e354d |
static int sigev_signum[SIGEV_MAX];
|
|
Packit |
5e354d |
static int sigev_signum_cnt;
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
/* The internal handler which just sets a global flag. */
|
|
Packit |
5e354d |
static void
|
|
Packit |
5e354d |
_sigev_handler (int signum)
|
|
Packit |
5e354d |
{
|
|
Packit |
5e354d |
sigaddset (&sigev_pending, signum);
|
|
Packit |
5e354d |
}
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
/* Start setting up signal event handling. */
|
|
Packit |
5e354d |
void
|
|
Packit |
5e354d |
npth_sigev_init (void)
|
|
Packit |
5e354d |
{
|
|
Packit |
5e354d |
sigemptyset (&sigev_pending);
|
|
Packit |
5e354d |
pthread_sigmask (SIG_SETMASK, NULL, &sigev_block);
|
|
Packit |
5e354d |
pthread_sigmask (SIG_SETMASK, NULL, &sigev_unblock);
|
|
Packit |
5e354d |
}
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
/* Add signal SIGNUM to the list of watched signals. */
|
|
Packit |
5e354d |
void
|
|
Packit |
5e354d |
npth_sigev_add (int signum)
|
|
Packit |
5e354d |
{
|
|
Packit |
5e354d |
struct sigaction sa;
|
|
Packit |
5e354d |
sigset_t ss;
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
sigemptyset(&ss);
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
assert (sigev_signum_cnt < SIGEV_MAX);
|
|
Packit |
5e354d |
sigev_signum[sigev_signum_cnt++] = signum;
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
/* Make sure we can receive it. */
|
|
Packit |
5e354d |
sigdelset (&sigev_unblock, signum);
|
|
Packit |
5e354d |
sigaddset (&sigev_block, signum);
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
sa.sa_handler = _sigev_handler;
|
|
Packit |
5e354d |
sa.sa_mask = ss;
|
|
Packit |
5e354d |
sa.sa_flags = 0; /* NOT setting SA_RESTART! */
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
sigaction (signum, &sa, NULL);
|
|
Packit |
5e354d |
}
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
#ifdef HAVE_PTHREAD_ATFORK
|
|
Packit |
5e354d |
/* There is non-POSIX operating system where fork is not available to
|
|
Packit |
5e354d |
applications. There, we have no pthread_atfork either. In such a
|
|
Packit |
5e354d |
case, we don't call pthread_atfork. */
|
|
Packit |
5e354d |
static void
|
|
Packit |
5e354d |
restore_sigmask_for_child_process (void)
|
|
Packit |
5e354d |
{
|
|
Packit |
5e354d |
pthread_sigmask (SIG_SETMASK, &sigev_unblock, NULL);
|
|
Packit |
5e354d |
}
|
|
Packit |
5e354d |
#endif
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
/* Finish the list of watched signals. This starts to block them,
|
|
Packit |
5e354d |
too. */
|
|
Packit |
5e354d |
void
|
|
Packit |
5e354d |
npth_sigev_fini (void)
|
|
Packit |
5e354d |
{
|
|
Packit |
5e354d |
/* Block the interesting signals. */
|
|
Packit |
5e354d |
pthread_sigmask (SIG_SETMASK, &sigev_block, NULL);
|
|
Packit |
5e354d |
#ifdef HAVE_PTHREAD_ATFORK
|
|
Packit |
5e354d |
pthread_atfork (NULL, NULL, restore_sigmask_for_child_process);
|
|
Packit |
5e354d |
#endif
|
|
Packit |
5e354d |
}
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
/* Get the sigmask as needed for pselect. */
|
|
Packit |
5e354d |
sigset_t *
|
|
Packit |
5e354d |
npth_sigev_sigmask (void)
|
|
Packit |
5e354d |
{
|
|
Packit |
5e354d |
return &sigev_unblock;
|
|
Packit |
5e354d |
}
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
|
|
Packit |
5e354d |
/* Return the next signal event that occured. Returns if none are
|
|
Packit |
5e354d |
left, 1 on success. */
|
|
Packit |
5e354d |
int
|
|
Packit |
5e354d |
npth_sigev_get_pending (int *r_signum)
|
|
Packit |
5e354d |
{
|
|
Packit |
5e354d |
int i;
|
|
Packit |
5e354d |
for (i = 0; i < sigev_signum_cnt; i++)
|
|
Packit |
5e354d |
{
|
|
Packit |
5e354d |
int signum = sigev_signum[i];
|
|
Packit |
5e354d |
if (sigismember (&sigev_pending, signum))
|
|
Packit |
5e354d |
{
|
|
Packit |
5e354d |
sigdelset (&sigev_pending, signum);
|
|
Packit |
5e354d |
*r_signum = signum;
|
|
Packit |
5e354d |
return 1;
|
|
Packit |
5e354d |
}
|
|
Packit |
5e354d |
}
|
|
Packit |
5e354d |
return 0;
|
|
Packit |
5e354d |
}
|
|
Packit |
5e354d |
|