#include "signals.h"
#include "log.h"
#define _GNU_SOURCE
#include <string.h>
#include <signal.h>
#include <stdlib.h>
#include <assert.h>
struct signals {
/** The libevent base to use */
struct event_base *ev_base;
/** Information about up to MAX_SIGNALS signals */
struct signal {
/** The event we use to handle the signal */
struct event *ev;
} sig_list[MAX_SIGNALS];
/** Number of used sig_list slots */
int sig_count;
};
void signals_loopexit (int signal, short event, void *arg)
{
struct signals *signals = arg;
(void) event;
log_info("caught %s: exiting", /* strsignal(signal) */ "xxx");
if (event_base_loopexit(signals->ev_base, NULL))
FATAL("event_base_loopexit");
}
void signals_ignore (int signal, short event, void *arg)
{
struct signals *signals = arg;
(void) signal;
(void) event;
(void) arg;
(void) signals;
/* ignore */
}
err_t signals_create (struct signals **signals_ptr, struct event_base *ev_base)
{
struct signals *signals;
if ((signals = calloc(1, sizeof(*signals))) == NULL)
return ERR_CALLOC;
// simple attributes
signals->ev_base = ev_base;
// done
*signals_ptr = signals;
return SUCCESS;
}
err_t signals_add (struct signals *signals, int sigval, void (*sig_handler)(evutil_socket_t, short, void *), void *arg)
{
struct signal *sig_info;
// find our sig_info
assert(signals->sig_count < MAX_SIGNALS);
sig_info = signals->sig_list + (signals->sig_count++);
// set up the libevent signal events
if ((sig_info->ev = evsignal_new(signals->ev_base, sigval, sig_handler, arg)) == NULL)
return ERR_EVENT_NEW;
if (evsignal_add(sig_info->ev, NULL))
return ERR_EVENT_ADD;
// ok
return SUCCESS;
}
err_t signal_ignore (int signum, struct error_info *err)
{
struct sigaction act = {
.sa_handler = SIG_IGN,
};
// signall the handler
if (sigaction(signum, &act, NULL))
RETURN_SET_ERROR_ERRNO(err, ERR_SIGACTION);
// ok
return SUCCESS;
}
struct signals *signals_default (struct event_base *ev_base)
{
struct signals *signals = NULL;
struct error_info err;
// alloc signals
if (signals_create(&signals, ev_base))
return NULL;
// add the set of default signals
if (signal_ignore(SIGPIPE, &err))
log_error(&err, "signal_ignore(SIGPIPE)");
if ((ERROR_CODE(&err) = signals_add(signals, SIGINT, &signals_loopexit, signals))) {
log_error(&err, "signals_add(SIGINT)");
goto error;
}
// ok
return signals;
error:
signals_free(signals);
return NULL;
}
void signals_free (struct signals *signals)
{
int i;
// free all events
for (i = 0; i < signals->sig_count; i++) {
event_free(signals->sig_list[i].ev);
}
// free the info itself
free(signals);
}