mirror of https://github.com/joan2937/pigpio
Improve signal handling. (#532)
This commit is contained in:
parent
27b5ea9c58
commit
3e0a5085f1
230
pigpio.c
230
pigpio.c
|
@ -984,6 +984,10 @@ typedef struct
|
|||
callbk_t func;
|
||||
unsigned ex;
|
||||
void *userdata;
|
||||
struct sigaction old;
|
||||
unsigned set;
|
||||
unsigned dfl;
|
||||
unsigned skip; // preset || SIG_IGN
|
||||
} gpioSignal_t;
|
||||
|
||||
typedef struct
|
||||
|
@ -1232,6 +1236,7 @@ static volatile uint32_t hw_clk_max_freq = PI_HW_CLK_MAX_FREQ;
|
|||
|
||||
static int libInitialised = 0;
|
||||
|
||||
|
||||
/* initialise every gpioInitialise */
|
||||
|
||||
static struct timespec libStarted;
|
||||
|
@ -1313,6 +1318,7 @@ static spiInfo_t spiInfo [PI_SPI_SLOTS];
|
|||
static gpioScript_t gpioScript [PI_MAX_SCRIPTS];
|
||||
|
||||
static gpioSignal_t gpioSignal [PI_MAX_SIGNUM+1];
|
||||
static struct sigaction defaultSigaction;
|
||||
|
||||
static gpioTimer_t gpioTimer [PI_MAX_TIMER+1];
|
||||
|
||||
|
@ -1515,6 +1521,12 @@ int gpioWaveTxStart(unsigned wave_mode); /* deprecated */
|
|||
|
||||
static void closeOrphanedNotifications(int slot, int fd);
|
||||
|
||||
static void signalInstaller(void);
|
||||
static int setSignalInstaller(unsigned signum);
|
||||
static void defaultSigHandler(int signum);
|
||||
static void customSigHandler(int signum);
|
||||
|
||||
static void initKillDMA(volatile uint32_t *dmaAddr);
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
|
@ -5582,6 +5594,40 @@ static void dmaInitCbs(void)
|
|||
|
||||
/* ======================================================================= */
|
||||
|
||||
static void defaultSigHandler(int signum)
|
||||
{
|
||||
/* kill DMA channels & unlink pid file */
|
||||
if (dmaReg != MAP_FAILED)
|
||||
{
|
||||
initKillDMA(dmaIn);
|
||||
initKillDMA(dmaOut);
|
||||
dmaReg = MAP_FAILED; // OS will munmap on termination
|
||||
}
|
||||
|
||||
if (fdLock != -1)
|
||||
{
|
||||
close(fdLock);
|
||||
unlink(PI_LOCKFILE);
|
||||
fdLock = -1;
|
||||
}
|
||||
|
||||
/* raise signal again, this time using *system* default action */
|
||||
sigaction(signum, &gpioSignal[signum].old, NULL);
|
||||
raise(signum);
|
||||
}
|
||||
|
||||
static void customSigHandler(int signum)
|
||||
{
|
||||
if (signum == SIGUSR1)
|
||||
gpioCfg.dbgLevel = (gpioCfg.dbgLevel > DBG_MIN_LEVEL) ?
|
||||
--gpioCfg.dbgLevel :
|
||||
DBG_MIN_LEVEL;
|
||||
|
||||
if (signum == SIGUSR2)
|
||||
gpioCfg.dbgLevel = (gpioCfg.dbgLevel < DBG_MAX_LEVEL) ?
|
||||
++gpioCfg.dbgLevel :
|
||||
DBG_MAX_LEVEL;
|
||||
}
|
||||
|
||||
static void sigHandler(int signum)
|
||||
{
|
||||
|
@ -5643,21 +5689,105 @@ static void sigHandler(int signum)
|
|||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static void sigSetHandler(void)
|
||||
static void signalInstaller(void)
|
||||
{
|
||||
int i;
|
||||
struct sigaction new;
|
||||
int signum;
|
||||
struct sigaction new, tmp;
|
||||
gpioSignal_t *sig;
|
||||
|
||||
for (i=PI_MIN_SIGNUM; i<=PI_MAX_SIGNUM; i++)
|
||||
if (gpioCfg.internals & PI_CFG_NOSIGHANDLER)
|
||||
{
|
||||
DBG(DBG_USER, "Signal installer disabled, PI_CFG_NOSIGHANDLER")
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&new, 0, sizeof(new));
|
||||
new.sa_handler = sigHandler;
|
||||
sigemptyset(&new.sa_mask);
|
||||
new.sa_flags = 0;
|
||||
|
||||
sigaction(i, &new, NULL);
|
||||
for (signum=PI_MIN_SIGNUM; signum<=PI_MAX_SIGNUM; signum++)
|
||||
{
|
||||
sig = &gpioSignal[signum];
|
||||
|
||||
/* skip if invalid */
|
||||
if (sigaction(signum, NULL, &tmp) < 0)
|
||||
{
|
||||
sig->skip = 1;
|
||||
DBG(DBG_INTERNAL, "Signal %d: invalid\n", signum);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip if not system default handler */
|
||||
if (tmp.sa_handler != SIG_DFL)
|
||||
{
|
||||
sig->skip = 1;
|
||||
DBG(DBG_INTERNAL, "Signal %d: !SIG_DFL\n", signum);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(signum)
|
||||
{
|
||||
/* job control signals - allow gpioSetSignalFunc*/
|
||||
case SIGCONT:
|
||||
case SIGTSTP:
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
break;
|
||||
|
||||
/* ignore signals - skip gpioSetSignalFunc */
|
||||
case SIGPIPE:
|
||||
case SIGWINCH:
|
||||
case SIGCHLD:
|
||||
new.sa_handler = SIG_IGN;
|
||||
sigaction(signum, &new, &sig->old);
|
||||
sig->set = 1;
|
||||
sig->skip = 1; // protect from cancellation
|
||||
DBG(DBG_INTERNAL, "Signal %d: skip=1, ignored\n", signum);
|
||||
break;
|
||||
|
||||
/* install custom handler */
|
||||
case SIGUSR1:
|
||||
case SIGUSR2:
|
||||
sigaddset(&new.sa_mask, SIGUSR1);
|
||||
sigaddset(&new.sa_mask, SIGUSR2);
|
||||
new.sa_handler = customSigHandler;
|
||||
sigaction(signum, &new, &sig->old);
|
||||
sig->set = 1;
|
||||
|
||||
// restore defaultSigaction if canceled
|
||||
sig->dfl = 1;
|
||||
|
||||
DBG(DBG_INTERNAL, "Signal %d: set=1, customSigHandler installed\n", signum);
|
||||
break;
|
||||
|
||||
default:
|
||||
sigaction(signum, &defaultSigaction, &sig->old);
|
||||
sig->dfl = 1;
|
||||
DBG(DBG_INTERNAL, "Signal %d: dfl=1, defaultSigHandler installed\n", signum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void signalUninstaller(void)
|
||||
{
|
||||
int signum;
|
||||
gpioSignal_t *sig;
|
||||
|
||||
for (signum=PI_MIN_SIGNUM; signum<=PI_MAX_SIGNUM; signum++)
|
||||
{
|
||||
sig = &gpioSignal[signum];
|
||||
|
||||
if (sig->set || sig->dfl)
|
||||
{
|
||||
sigaction(signum, &sig->old, NULL);
|
||||
sig->set = 0;
|
||||
sig->dfl = 0;
|
||||
DBG(DBG_INTERNAL, "Signal %d: Restored, system default handler\n", signum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/*
|
||||
freq mics net
|
||||
0 1000 1000 900
|
||||
|
@ -8021,8 +8151,15 @@ static void initClearGlobals(void)
|
|||
gpioSignal[i].func = NULL;
|
||||
gpioSignal[i].ex = 0;
|
||||
gpioSignal[i].userdata = NULL;
|
||||
gpioSignal[i].set = 0;
|
||||
gpioSignal[i].dfl = 0;
|
||||
memset(&gpioSignal[i].old, 0, sizeof(gpioSignal[i].old));
|
||||
}
|
||||
|
||||
defaultSigaction.sa_handler = defaultSigHandler;
|
||||
defaultSigaction.sa_flags = 0;
|
||||
sigfillset(&defaultSigaction.sa_mask);
|
||||
|
||||
for (i=0; i<=PI_MAX_TIMER; i++)
|
||||
{
|
||||
gpioTimer[i].running = 0;
|
||||
|
@ -8324,7 +8461,7 @@ int initInitialise(void)
|
|||
|
||||
#ifndef EMBEDDED_IN_VM
|
||||
if (!(gpioCfg.internals & PI_CFG_NOSIGHANDLER))
|
||||
sigSetHandler();
|
||||
signalInstaller();
|
||||
#endif
|
||||
|
||||
if (initPeripherals() < 0) return PI_INIT_FAILED;
|
||||
|
@ -8767,8 +8904,10 @@ void gpioTerminate(void)
|
|||
fprintf(stderr,
|
||||
"\n#####################################################\n\n\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
signalUninstaller();
|
||||
|
||||
initReleaseResources();
|
||||
|
||||
fflush(NULL);
|
||||
|
@ -12845,24 +12984,79 @@ int gpioDeleteScript(unsigned script_id)
|
|||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
static int setSignalInstaller(unsigned signum)
|
||||
{
|
||||
gpioSignal_t *sig = &gpioSignal[signum];
|
||||
struct sigaction new;
|
||||
|
||||
if (sig->skip)
|
||||
return PI_SIG_SKIPPED;
|
||||
|
||||
/* set: save old signal action and set new */
|
||||
|
||||
if (sig->func)
|
||||
{
|
||||
if (sig->set == 0)
|
||||
{
|
||||
DBG(DBG_INTERNAL, "Set new handler for signal %d" ,signum);
|
||||
memset(&new, 0, sizeof(new));
|
||||
new.sa_handler = sigHandler;
|
||||
sigfillset(&new.sa_mask);
|
||||
sig->set = 1;
|
||||
|
||||
if (sig->dfl == 0)
|
||||
return sigaction(signum, &new, &sig->old);
|
||||
|
||||
else
|
||||
return sigaction(signum, &new, NULL);
|
||||
}
|
||||
|
||||
return PI_SIGNUM_SET;
|
||||
}
|
||||
|
||||
/* cancel and restore old signal action */
|
||||
else
|
||||
{
|
||||
if (sig->set)
|
||||
{
|
||||
DBG(DBG_INTERNAL, "Cancel and restore handler for signal %d" ,signum);
|
||||
sig->set = 0;
|
||||
|
||||
if (sig->dfl == 0)
|
||||
return sigaction(signum, &sig->old, NULL);
|
||||
|
||||
else
|
||||
return sigaction(signum, &defaultSigaction, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return PI_SIG_UNK_ACTION;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
int gpioSetSignalFunc(unsigned signum, gpioSignalFunc_t f)
|
||||
{
|
||||
int rv;
|
||||
|
||||
DBG(DBG_USER, "signum=%d function=%08"PRIXPTR, signum, (uintptr_t)f);
|
||||
|
||||
CHECK_INITED;
|
||||
|
||||
if (gpioCfg.internals & PI_CFG_NOSIGHANDLER)
|
||||
return PI_NOSIGHANDLER;
|
||||
|
||||
if (signum > PI_MAX_SIGNUM)
|
||||
SOFT_ERROR(PI_BAD_SIGNUM, "bad signum (%d)", signum);
|
||||
|
||||
gpioSignal[signum].ex = 0;
|
||||
gpioSignal[signum].userdata = NULL;
|
||||
|
||||
gpioSignal[signum].func = f;
|
||||
|
||||
return 0;
|
||||
rv = setSignalInstaller(signum);
|
||||
return (rv == -1) ? PI_SIG_UNK_ACTION : rv;
|
||||
}
|
||||
|
||||
|
||||
|
@ -12871,20 +13065,25 @@ int gpioSetSignalFunc(unsigned signum, gpioSignalFunc_t f)
|
|||
int gpioSetSignalFuncEx(unsigned signum, gpioSignalFuncEx_t f,
|
||||
void *userdata)
|
||||
{
|
||||
int rv;
|
||||
|
||||
DBG(DBG_USER, "signum=%d function=%08"PRIXPTR" userdata=%08"PRIXPTR,
|
||||
signum, (uintptr_t)f, (uintptr_t)userdata);
|
||||
|
||||
CHECK_INITED;
|
||||
|
||||
if (gpioCfg.internals & PI_CFG_NOSIGHANDLER)
|
||||
return PI_NOSIGHANDLER;
|
||||
|
||||
if (signum > PI_MAX_SIGNUM)
|
||||
SOFT_ERROR(PI_BAD_SIGNUM, "bad signum (%d)", signum);
|
||||
|
||||
gpioSignal[signum].ex = 1;
|
||||
gpioSignal[signum].userdata = userdata;
|
||||
|
||||
gpioSignal[signum].func = f;
|
||||
|
||||
return 0;
|
||||
rv = setSignalInstaller(signum);
|
||||
return (rv == -1) ? PI_SIG_UNK_ACTION : rv;
|
||||
}
|
||||
|
||||
|
||||
|
@ -14025,7 +14224,9 @@ int gpioCfgNetAddr(int numSockAddr, uint32_t *sockAddr)
|
|||
|
||||
uint32_t gpioCfgGetInternals(void)
|
||||
{
|
||||
return gpioCfg.internals;
|
||||
return ((gpioCfg.internals & 0xffffff00)
|
||||
| gpioCfg.alertFreq << 4
|
||||
| gpioCfg.dbgLevel);
|
||||
}
|
||||
|
||||
int gpioCfgSetInternals(uint32_t cfgVal)
|
||||
|
@ -14041,4 +14242,3 @@ int gpioCfgSetInternals(uint32_t cfgVal)
|
|||
/* include any user customisations */
|
||||
|
||||
#include "custom.cext"
|
||||
|
||||
|
|
5
pigpio.h
5
pigpio.h
|
@ -6528,6 +6528,11 @@ after this command is issued.
|
|||
#define PI_CMD_INTERRUPTED -144 // Used by Python
|
||||
#define PI_NOT_ON_BCM2711 -145 // not available on BCM2711
|
||||
#define PI_ONLY_ON_BCM2711 -146 // only available on BCM2711
|
||||
#define PI_NOSIGHANDLER -147 // signal handling is disabled (gpioCfg.internals)
|
||||
#define PI_SIGNUM_INVALID -148 // invalid signal number requested (signal.h)
|
||||
#define PI_SIGNUM_SET -149 // handler for signal is already installed
|
||||
#define PI_SIG_UNK_ACTION -150 // default signal handler is not installed
|
||||
#define PI_SIG_SKIPPED -151 // set/cancel signal handler is not allowed
|
||||
|
||||
#define PI_PIGIF_ERR_0 -2000
|
||||
#define PI_PIGIF_ERR_99 -2099
|
||||
|
|
110
x_pigpio.c
110
x_pigpio.c
|
@ -22,6 +22,7 @@ sudo ./x_pigpio
|
|||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "pigpio.h"
|
||||
|
||||
|
@ -900,6 +901,114 @@ void tc()
|
|||
CHECK(12, 99, e, 0, 0, "spiClose");
|
||||
}
|
||||
|
||||
int signum;
|
||||
enum signalType {Invalid, Default, Ignore, Catch};
|
||||
typedef struct
|
||||
{
|
||||
enum signalType type;
|
||||
struct sigaction action;
|
||||
} sigArr_t;
|
||||
sigArr_t sigArr[PI_MAX_SIGNUM+1];
|
||||
struct sigaction query, preset;
|
||||
void voidHandler(int signum) {}
|
||||
|
||||
void td(void)
|
||||
{
|
||||
/* Categorize all handlers */
|
||||
|
||||
for (signum = 0; signum<=PI_MAX_SIGNUM; signum++)
|
||||
{
|
||||
if (sigaction(signum, NULL, &sigArr[signum].action) < 0)
|
||||
sigArr[signum].type = Invalid;
|
||||
|
||||
else if (sigArr[signum].action.sa_handler == SIG_DFL)
|
||||
sigArr[signum].type = Default;
|
||||
|
||||
else if (sigArr[signum].action.sa_handler == SIG_IGN)
|
||||
sigArr[signum].type = Ignore;
|
||||
|
||||
else sigArr[signum].type = Catch; // Preset, Set or Dfl
|
||||
}
|
||||
|
||||
/* Check signals affected by default installer. */
|
||||
|
||||
CHECK(13,1, sigArr[SIGCHLD].type, Ignore, 0, "SIGCHLD ignored");
|
||||
CHECK(13,2, sigArr[SIGPIPE].type, Ignore, 0, "SIGPIPE Ignored");
|
||||
CHECK(13,3, sigArr[SIGWINCH].type, Ignore, 0, "SIGWINCH ignored");
|
||||
CHECK(13,4, sigArr[SIGUSR1].type, Catch, 0, "SIGUSR1 installed");
|
||||
CHECK(13,5, sigArr[SIGUSR2].type, Catch, 0, "SIGUSR2 installed");
|
||||
|
||||
/* Set and restore handler on cancellation. */
|
||||
|
||||
CHECK(13,6, gpioSetSignalFunc(SIGSEGV, voidHandler), 0, 0, "set signal");
|
||||
CHECK(13,7, gpioSetSignalFunc(SIGSEGV, NULL), 0, 0, "cancel signal");
|
||||
CHECK(13,8, sigaction(SIGSEGV, NULL, &query), 0, 0, "query sigaction");
|
||||
CHECK(13,9, (intptr_t)query.sa_handler, (intptr_t)sigArr[SIGSEGV].action.sa_handler, 0, "gpioSetSignalFunc");
|
||||
|
||||
|
||||
/* check custom handler function */
|
||||
|
||||
raise(SIGUSR2); // increment dgbLevel
|
||||
time_sleep(0.1);
|
||||
CHECK(13,10, gpioCfgGetInternals() & 0x0f, 1, 0, "SIGUSR2");
|
||||
|
||||
raise(SIGUSR1); // decrement dgbLevel
|
||||
time_sleep(0.1);
|
||||
CHECK(13,11, gpioCfgGetInternals() & 0x0f, 0, 0, "SIGUSR1");
|
||||
|
||||
|
||||
/* check gpioTermination restores all signal handlers to their pre-initialise state. */
|
||||
|
||||
gpioTerminate();
|
||||
|
||||
unsigned catchNotRestored = 0;
|
||||
unsigned ignoreNotRestored = 0;
|
||||
for (signum = 0; signum<=PI_MAX_SIGNUM; signum++)
|
||||
{
|
||||
if (sigArr[signum].type == Catch)
|
||||
if (sigaction(signum, NULL, &query) == 0)
|
||||
if (query.sa_handler != SIG_DFL)
|
||||
{
|
||||
fprintf(stderr, "signal %d not restored\n", signum);
|
||||
catchNotRestored++;
|
||||
}
|
||||
|
||||
if (sigArr[signum].type == Ignore)
|
||||
if (sigaction(signum, NULL, &query) == 0)
|
||||
if (query.sa_handler != SIG_DFL)
|
||||
{
|
||||
fprintf(stderr, "signal %d not restored\n", signum);
|
||||
ignoreNotRestored++;
|
||||
}
|
||||
}
|
||||
CHECK(13,12, catchNotRestored, 0, 0, "caught signals not restored");
|
||||
CHECK(13,13, ignoreNotRestored, 0, 0, "ignored signals not restored");
|
||||
|
||||
/* check handlers prior to gpioInitialise are preserved */
|
||||
|
||||
preset = sigArr[SIGINT].action;
|
||||
memset(&preset, 0, sizeof(preset));
|
||||
preset.sa_handler = voidHandler;
|
||||
CHECK(13,14, sigaction(SIGINT, &preset, &query), 0, 0, "preset action");
|
||||
|
||||
CHECK(13,15, gpioInitialise(), 79, 0, "gpioInitialise"); // FIX version dependency
|
||||
CHECK(13,16, gpioSetSignalFunc(SIGINT, voidHandler), PI_SIG_SKIPPED, 0, "preset override");
|
||||
|
||||
// can not set ignored signals
|
||||
CHECK(13,17, gpioSetSignalFunc(SIGPIPE, voidHandler), PI_SIG_SKIPPED, 0, "set ignore");
|
||||
|
||||
|
||||
/* Test signal handlers disabled */
|
||||
|
||||
gpioTerminate();
|
||||
gpioCfgSetInternals(gpioCfgGetInternals() | PI_CFG_NOSIGHANDLER);
|
||||
gpioInitialise();
|
||||
|
||||
sigaction(SIGHUP, NULL, &query);
|
||||
CHECK(13,18, (intptr_t)query.sa_handler, (intptr_t)SIG_DFL, 0, "default disabled");
|
||||
CHECK(13,19, gpioSetSignalFunc(SIGHUP, NULL), PI_NOSIGHANDLER, 0, "set disabled");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, t, c, status;
|
||||
|
@ -944,6 +1053,7 @@ int main(int argc, char *argv[])
|
|||
if (strchr(test, 'a')) ta();
|
||||
if (strchr(test, 'b')) tb();
|
||||
if (strchr(test, 'c')) tc();
|
||||
if (strchr(test, 'd')) td();
|
||||
|
||||
gpioTerminate();
|
||||
|
||||
|
|
Loading…
Reference in New Issue