diff --git a/CMakeLists.txt b/CMakeLists.txt
index 383c445c..1410edb1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -53,8 +53,8 @@ generate_export_header(${PROJECT_NAME})
install(TARGETS pigpio pigpiod_if pigpiod_if2 pig2vcd pigpiod pigs
EXPORT ${PROJECT_NAME}Targets
- LIBRARY DESTINATION lib
- ARCHIVE DESTINATION lib
+ LIBRARY DESTINATION lib${LIB_SUFFIX}
+ ARCHIVE DESTINATION lib${LIB_SUFFIX}
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)
@@ -124,4 +124,4 @@ endif()
# package project
-include (CPack)
\ No newline at end of file
+include (CPack)
diff --git a/DOC/bin/cmakdoc.py b/DOC/bin/cmakdoc.py
index dd1bd52a..683e5288 100755
--- a/DOC/bin/cmakdoc.py
+++ b/DOC/bin/cmakdoc.py
@@ -6,7 +6,7 @@
.\" Process this file with
.\" groff -man -Tascii pigpio.3
.\"
-.TH pigpio 3 2012-2020 Linux "pigpio archive"
+.TH pigpio 3 2012-2023 Linux "pigpio archive"
.SH NAME
pigpio - A C library to manipulate the Pi's GPIO.\n
.SH SYNOPSIS\n
@@ -21,7 +21,7 @@
.\" Process this file with
.\" groff -man -Tascii pigpiod_if.3
.\"
-.TH pigpiod_if 3 2012-2020 Linux "pigpio archive"
+.TH pigpiod_if 3 2012-2023 Linux "pigpio archive"
.SH NAME
pigpiod_if - A C library to interface to the pigpio daemon.\n
.SH SYNOPSIS\n
@@ -36,7 +36,7 @@
.\" Process this file with
.\" groff -man -Tascii pigpiod_if2.3
.\"
-.TH pigpiod_if2 3 2012-2020 Linux "pigpio archive"
+.TH pigpiod_if2 3 2012-2023 Linux "pigpio archive"
.SH NAME
pigpiod_if2 - A C library to interface to the pigpio daemon.\n
.SH SYNOPSIS\n
@@ -51,7 +51,7 @@
.\" Process this file with
.\" groff -man -Tascii pigpiod.1
.\"
-.TH pigpiod 1 2012-2020 Linux "pigpio archive"
+.TH pigpiod 1 2012-2023 Linux "pigpio archive"
.SH NAME
pigpiod - A utility to start the pigpio library as a daemon.\n
.SH SYNOPSIS\n
@@ -63,7 +63,7 @@
.\" Process this file with
.\" groff -man -Tascii pig2vcd.1
.\"
-.TH pig2vcd 1 2012-2020 Linux "pigpio archive"
+.TH pig2vcd 1 2012-2023 Linux "pigpio archive"
.SH NAME
pig2vd - A utility to convert pigpio notifications to VCD.\n
.SH SYNOPSIS\n
@@ -228,44 +228,67 @@ def nostar(k):
elif line == "/*F*/\n":
in_code = False
- fdef=""
+ func_def=""
line = get_line(f)
at = FUNC
elif line == "/*D\n":
# Function definition should be complete.
- fdef = fdef.replace("\n", " ")
+ func_def = func_def.replace("\n", " ")
- while fdef.find(" ") != -1:
- fdef = fdef.replace(" ", " ")
+ # Function definition should be complete. Normalise definition
- fdef = fdef.replace("( ", "(")
+ func_def = func_def.replace("\n", " ")
- (rf, sep1, end1) = fdef.partition("(")
+ while func_def.find(" ") != -1:
+ func_def = func_def.replace(" ", " ")
+
+ func_def = func_def.replace("( ", "(")
+ func_def = func_def.replace(" (", "(")
+
+ (rf, sep1, end1) = func_def.partition("(")
(parl, sep2, end2) = end1.partition(")")
tps = parl.split(",")
rf = rf.split(" ")
- ret = rf[0]
- func = rf[1]
+
+ if len(rf) > 2: # const
+ const = rf[0]+" "
+ ret = rf[1]
+ func = rf[2]
+ else:
+ const = ""
+ ret = rf[0]
+ func = rf[1]
if ret not in param_used:
param_used.append(ret)
if man:
- t = "\\fB" + ret + " " + func + "(" + parl + ")\\fP"
+ t = "\\fB" + const + ret + " " + func + "(" + parl + ")\\fP"
emit("\n.IP \"{}\"\n.IP \"\" 4\n".format(t))
else:
emit("
{} {}".
- format(nostar(func), ret, ret,func))
+ format(nostar(func), ret, const + ret, func))
emit("(")
x = 0
for tp in tps:
tp = tp.strip()
- (t, sep3, p) = tp.partition(" ")
- t = t.strip()
- p = p.strip()
- if (p != ""):
+ tp = tp.split()
+
+ if len(tp) < 2:
+ t=tp[0]
+ p=""
+ elif len(tp) == 2:
+ t = tp[0]
+ tf = tp[0]
+ p = tp[1]
+ else:
+ t = tp[-2]
+ tf = tp[-3] + " "+ tp[-2]
+ p = tp[-1]
+
+ if p != "":
if p not in param_used:
param_used.append(p)
if t not in param_used:
@@ -284,7 +307,7 @@ def nostar(k):
else:
emit("{} {}".
- format(t, t, p, p))
+ format(t, tf, p, p))
else:
@@ -499,7 +522,7 @@ def nostar(k):
format(func.replace("_", " ")))
elif at == FUNC:
- fdef += line
+ func_def += line
elif at == DESC:
emit(line)
diff --git a/DOC/bin/html.py b/DOC/bin/html.py
index 1259430b..f9b9de00 100755
--- a/DOC/bin/html.py
+++ b/DOC/bin/html.py
@@ -38,7 +38,7 @@
header = 'pigpio library'
-footer1 = "© 2012-2020";
+footer1 = "© 2012-2023";
footer2 = "e-mail: pigpio @ abyz.me.uk";
footer3 = "Updated: " + time.strftime("%d/%m/%Y") + "";
diff --git a/DOC/bin/smakdoc.py b/DOC/bin/smakdoc.py
index a36975f7..c048c19b 100755
--- a/DOC/bin/smakdoc.py
+++ b/DOC/bin/smakdoc.py
@@ -55,7 +55,7 @@ def get_line(f):
.\" Process this file with
.\" groff -man -Tascii foo.1
.\"
-.TH pigs 1 2012-2020 Linux "pigpio archive"
+.TH pigs 1 2012-2023 Linux "pigpio archive"
.SH NAME
pigs - command line socket access to the pigpio daemon.\n
/dev/pigpio - command line pipe access to the pigpio daemon.\n
diff --git a/DOC/dbase/pigpio.sqlite b/DOC/dbase/pigpio.sqlite
index 017dd86e..06351a39 100644
Binary files a/DOC/dbase/pigpio.sqlite and b/DOC/dbase/pigpio.sqlite differ
diff --git a/DOC/makedoc b/DOC/makedoc
index 44942529..7492e37e 100755
--- a/DOC/makedoc
+++ b/DOC/makedoc
@@ -31,7 +31,7 @@ bin/cmakdoc.py pig2vcd src/defs/pig2vcd.def >tmp/body/pig2vcd.body
bin/cmakdoc.py pigpio ../pigpio.h >tmp/body/cif.body
bin/cmakdoc.py pigpiod_if ../pigpiod_if.h >tmp/body/pdif.body
bin/cmakdoc.py pigpiod_if2 ../pigpiod_if2.h >tmp/body/pdif2.body
-pydoc ../pigpio.py >tmp/pydoc/pigpio.pydoc
+python -m pydoc ../pigpio.py >tmp/pydoc/pigpio.pydoc
bin/pymakdoc.py tmp/pydoc/pigpio.pydoc >tmp/body/python.body
bin/examples.py src/defs/examples.def >tmp/body/examples.body
diff --git a/DOC/src/html/sif.html b/DOC/src/html/sif.html
index 67b880bf..b12eb974 100644
--- a/DOC/src/html/sif.html
+++ b/DOC/src/html/sif.html
@@ -25,6 +25,12 @@
call. The pigpio daemon uses this function to provide an
option to change the port number.
+pigpio also listens for connections on "/var/run/pigpio.sock" by
+default. This default may be overridden when pigpio starts
+by the gpioCfgSocketPath
+function call. The pigpio daemon uses this function to provide an
+option to change the socket file name.
+
The pigs utility is an example of using the socket interface from
C.
Request
diff --git a/command.c b/command.c
index ffc34630..d17b5220 100644
--- a/command.c
+++ b/command.c
@@ -567,6 +567,7 @@ static errInfo_t errInfo[]=
{PI_CMD_INTERRUPTED , "command interrupted, Python"},
{PI_NOT_ON_BCM2711 , "not available on BCM2711"},
{PI_ONLY_ON_BCM2711 , "only available on BCM2711"},
+ {PI_BAD_SOCKET_PATH , "socket path empty"},
};
diff --git a/pigpio.3 b/pigpio.3
index 783bc921..0590b347 100644
--- a/pigpio.3
+++ b/pigpio.3
@@ -706,6 +706,8 @@ gpioCfgInterfaces Configure user interfaces
.br
gpioCfgSocketPort Configure socket port
.br
+gpioCfgSocketPath Configure socket path
+.br
gpioCfgMemAlloc Configure DMA memory allocation mode
.br
gpioCfgNetAddr Configure allowed network addresses
@@ -7802,6 +7804,30 @@ port: 1024-32000
.br
The default setting is to use port 8888.
+.IP "\fBint gpioCfgSocketPath(const char*)\fP"
+.IP "" 4
+Configures pigpio to use the specified Unix socket.
+
+.br
+
+.br
+This function is only effective if called before \fBgpioInitialise\fP.
+
+.br
+
+.br
+
+.EX
+path: path to the socket.
+.br
+
+.EE
+
+.br
+
+.br
+The default is "/var/run/pigpio.sock".
+
.IP "\fBint gpioCfgInterfaces(unsigned ifFlags)\fP"
.IP "" 4
Configures pigpio support of the fifo and socket interfaces.
@@ -8945,6 +8971,8 @@ These functions are only effective if called before \fBgpioInitialise\fP.
.br
\fBgpioCfgSocketPort\fP
.br
+\fBgpioCfgSocketPath\fP
+.br
\fBgpioCfgMemAlloc\fP
.br
@@ -11040,6 +11068,8 @@ A 16-bit word value.
.br
#define PI_ONLY_ON_BCM2711 -146 // only available on BCM2711
.br
+#define PI_BAD_SOCKET_PORT -153 // socket path empty
+.br
.br
#define PI_PIGIF_ERR_0 -2000
diff --git a/pigpio.c b/pigpio.c
index 97bfc54b..9cd6f66f 100644
--- a/pigpio.c
+++ b/pigpio.c
@@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to
*/
-/* pigpio version 79 */
+/* pigpio version 80 */
/* include ------------------------------------------------------- */
@@ -58,6 +58,7 @@ For more information, please refer to
#include
#include
#include
+#include
#include
#include
#include
@@ -984,6 +985,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
@@ -1096,6 +1101,7 @@ typedef struct
unsigned DMAprimaryChannel;
unsigned DMAsecondaryChannel;
unsigned socketPort;
+ const char * socketPath;
unsigned ifFlags;
unsigned memAllocMode;
unsigned dbgLevel;
@@ -1232,6 +1238,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;
@@ -1292,6 +1299,7 @@ static volatile int runState = PI_STARTING;
static int pthAlertRunning = PI_THREAD_NONE;
static int pthFifoRunning = PI_THREAD_NONE;
static int pthSocketRunning = PI_THREAD_NONE;
+static int pthUnixRunning = PI_THREAD_NONE;
static gpioAlert_t gpioAlert [PI_MAX_USER_GPIO+1];
@@ -1313,6 +1321,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];
@@ -1328,6 +1337,7 @@ static FILE * outFifo = NULL;
static int fdLock = -1;
static int fdMem = -1;
static int fdSock = -1;
+static int fdUnix = -1;
static int fdPmap = -1;
static int fdMbox = -1;
@@ -1369,6 +1379,7 @@ static volatile gpioCfg_t gpioCfg =
PI_DEFAULT_DMA_NOT_SET, /* primary DMA */
PI_DEFAULT_DMA_NOT_SET, /* secondary DMA */
PI_DEFAULT_SOCKET_PORT,
+ PI_DEFAULT_SOCKET_PATH,
PI_DEFAULT_IF_FLAGS,
PI_DEFAULT_MEM_ALLOC_MODE,
0, /* dbgLevel */
@@ -1384,6 +1395,7 @@ static unsigned bufferCycles; /* number of cycles */
static pthread_t pthAlert;
static pthread_t pthFifo;
static pthread_t pthSocket;
+static pthread_t pthUnix;
static uint32_t spi_dummy;
@@ -1515,6 +1527,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 +5600,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 +5695,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;
+ }
+
+ sigemptyset(&new.sa_mask);
+ new.sa_flags = 0;
- memset(&new, 0, sizeof(new));
- new.sa_handler = sigHandler;
+ for (signum=PI_MIN_SIGNUM; signum<=PI_MAX_SIGNUM; signum++)
+ {
+ sig = &gpioSignal[signum];
- sigaction(i, &new, NULL);
+ /* 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
@@ -7260,6 +7396,61 @@ static void * pthSocketThread(void *x)
return 0;
}
+static void * pthUnixThread(void *x)
+{
+ int fdC=0, c, *sock;
+ struct sockaddr_storage client;
+ pthread_attr_t attr;
+
+ if (pthread_attr_init(&attr))
+ SOFT_ERROR((void*)PI_INIT_FAILED,
+ "pthread_attr_init failed (%m)");
+
+ if (pthread_attr_setstacksize(&attr, STACK_SIZE))
+ SOFT_ERROR((void*)PI_INIT_FAILED,
+ "pthread_attr_setstacksize failed (%m)");
+
+ if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
+ SOFT_ERROR((void*)PI_INIT_FAILED,
+ "pthread_attr_setdetachstate failed (%m)");
+
+ /* fdUnix opened in gpioInitialise so that we can treat
+ failure to bind as fatal. */
+
+ listen(fdUnix, 100);
+
+ c = sizeof(client);
+
+ /* don't start until DMA started */
+
+ spinWhileStarting();
+
+ while (fdC >= 0)
+ {
+ pthread_t thr;
+
+ fdC = accept(fdUnix, (struct sockaddr *)&client, (socklen_t*)&c);
+
+ closeOrphanedNotifications(-1, fdC);
+
+ DBG(DBG_USER, "Connection accepted on socket %d", fdC);
+
+ sock = malloc(sizeof(int));
+
+ *sock = fdC;
+
+ if (pthread_create
+ (&thr, &attr, pthSocketThreadHandler, (void*) sock) < 0)
+ SOFT_ERROR((void*)PI_INIT_FAILED,
+ "socket pthread_create failed (%m)");
+ }
+
+ if (fdC < 0)
+ SOFT_ERROR((void*)PI_INIT_FAILED, "accept failed (%m)");
+
+ return 0;
+}
+
/* ======================================================================= */
static void initCheckLockFile(void)
@@ -7272,6 +7463,8 @@ static void initCheckLockFile(void)
char str[20];
fd = open(PI_LOCKFILE, O_RDONLY);
+ if(errno == ENOENT)
+ errno = 0; // reset if expected error occured
if (fd != -1)
{
@@ -7969,6 +8162,7 @@ static void initClearGlobals(void)
pthAlertRunning = PI_THREAD_NONE;
pthFifoRunning = PI_THREAD_NONE;
pthSocketRunning = PI_THREAD_NONE;
+ pthUnixRunning = PI_THREAD_NONE;
wfc[0] = 0;
wfc[1] = 0;
@@ -8019,8 +8213,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;
@@ -8051,6 +8252,7 @@ static void initClearGlobals(void)
fdLock = -1;
fdMem = -1;
fdSock = -1;
+ fdUnix = -1;
dmaMboxBlk = MAP_FAILED;
dmaPMapBlk = MAP_FAILED;
@@ -8120,6 +8322,13 @@ static void initReleaseResources(void)
pthSocketRunning = PI_THREAD_NONE;
}
+ if (pthUnixRunning != PI_THREAD_NONE)
+ {
+ pthread_cancel(pthUnix);
+ pthread_join(pthUnix, NULL);
+ pthUnixRunning = PI_THREAD_NONE;
+ }
+
/* release mmap'd memory */
if (auxReg != MAP_FAILED) munmap((void *)auxReg, AUX_LEN);
@@ -8224,6 +8433,12 @@ static void initReleaseResources(void)
fdSock = -1;
}
+ if (fdUnix != -1)
+ {
+ close(fdUnix);
+ fdUnix = -1;
+ }
+
if (fdPmap != -1)
{
close(fdPmap);
@@ -8248,7 +8463,9 @@ int initInitialise(void)
unsigned rev, model;
struct sockaddr_in server;
struct sockaddr_in6 server6;
+ struct sockaddr_un serverU;
char * portStr;
+ const char * sockStr;
unsigned port;
struct sched_param param;
pthread_attr_t pthAttr;
@@ -8322,7 +8539,7 @@ int initInitialise(void)
#ifndef EMBEDDED_IN_VM
if (!(gpioCfg.internals & PI_CFG_NOSIGHANDLER))
- sigSetHandler();
+ signalInstaller();
#endif
if (initPeripherals() < 0) return PI_INIT_FAILED;
@@ -8368,6 +8585,29 @@ int initInitialise(void)
pthFifoRunning = PI_THREAD_STARTED;
}
+ if (!(gpioCfg.ifFlags & PI_DISABLE_UNIX_IF))
+ {
+ sockStr = getenv(PI_ENVSOCK);
+ if (! sockStr) sockStr = gpioCfg.socketPath;
+
+ fdUnix = socket(AF_UNIX, SOCK_STREAM , 0);
+
+ if (fdUnix != -1)
+ {
+ bzero((char *)&serverU, sizeof(serverU));
+ serverU.sun_family = AF_UNIX;
+ strncpy (serverU.sun_path, sockStr, sizeof (serverU.sun_path) - 1);
+
+ if (bind(fdUnix,(struct sockaddr *)&serverU, sizeof(serverU)) < 0)
+ SOFT_ERROR(PI_INIT_FAILED, "bind to socket '%s' failed (%m)", sockStr);
+ }
+
+ if (pthread_create(&pthUnix, &pthAttr, pthUnixThread, &i))
+ SOFT_ERROR(PI_INIT_FAILED, "pthread_create unix failed (%m)");
+
+ pthUnixRunning = PI_THREAD_STARTED;
+ }
+
if (!(gpioCfg.ifFlags & PI_DISABLE_SOCK_IF))
{
portStr = getenv(PI_ENVPORT);
@@ -8765,8 +9005,10 @@ void gpioTerminate(void)
fprintf(stderr,
"\n#####################################################\n\n\n");
}
-
#endif
+
+ signalUninstaller();
+
initReleaseResources();
fflush(NULL);
@@ -8826,6 +9068,7 @@ static void stopHardwarePWM(void)
int gpioSetMode(unsigned gpio, unsigned mode)
{
int reg, shift, old_mode;
+ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
DBG(DBG_USER, "gpio=%d mode=%d", gpio, mode);
@@ -8837,6 +9080,8 @@ int gpioSetMode(unsigned gpio, unsigned mode)
if (mode > PI_ALT3)
SOFT_ERROR(PI_BAD_MODE, "gpio %d, bad mode (%d)", gpio, mode);
+ pthread_mutex_lock(&mutex);
+
reg = gpio/10;
shift = (gpio%10) * 3;
@@ -8851,6 +9096,8 @@ int gpioSetMode(unsigned gpio, unsigned mode)
gpioReg[reg] = (gpioReg[reg] & ~(7<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;
}
@@ -12864,20 +13166,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;
}
@@ -13972,6 +14279,21 @@ int gpioCfgSocketPort(unsigned port)
}
+int gpioCfgSocketPath(const char *path)
+{
+ DBG(DBG_USER, "path=%s", path);
+
+ CHECK_NOT_INITED;
+
+ if (!path || !*path)
+ SOFT_ERROR(PI_BAD_SOCKET_PATH, "bad path");
+
+ gpioCfg.socketPath = path;
+
+ return 0;
+}
+
+
/* ----------------------------------------------------------------------- */
int gpioCfgMemAlloc(unsigned memAllocMode)
@@ -14018,11 +14340,14 @@ 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)
{
+ if (libInitialised) return PI_INITIALISED;
gpioCfg.internals = cfgVal;
gpioCfg.dbgLevel = cfgVal & 0xF;
gpioCfg.alertFreq = (cfgVal>>4) & 0xF;
@@ -14033,4 +14358,3 @@ int gpioCfgSetInternals(uint32_t cfgVal)
/* include any user customisations */
#include "custom.cext"
-
diff --git a/pigpio.h b/pigpio.h
index 1b8e51c8..dd11ef03 100644
--- a/pigpio.h
+++ b/pigpio.h
@@ -385,6 +385,7 @@ gpioCfgDMAchannels Configure the DMA channels
gpioCfgPermissions Configure the GPIO access permissions
gpioCfgInterfaces Configure user interfaces
gpioCfgSocketPort Configure socket port
+gpioCfgSocketPath Configure Unix socket path
gpioCfgMemAlloc Configure DMA memory allocation mode
gpioCfgNetAddr Configure allowed network addresses
@@ -415,6 +416,7 @@ OVERVIEW*/
#define PI_ENVPORT "PIGPIO_PORT"
#define PI_ENVADDR "PIGPIO_ADDR"
+#define PI_ENVSOCK "PIGPIO_SOCKET"
#define PI_LOCKFILE "/var/run/pigpio.pid"
@@ -890,6 +892,7 @@ typedef void *(gpioThreadFunc_t) (void *);
#define PI_DISABLE_SOCK_IF 2
#define PI_LOCALHOST_SOCK_IF 4
#define PI_DISABLE_ALERT 8
+#define PI_DISABLE_UNIX_IF 16
/* memAllocMode */
@@ -4919,6 +4922,21 @@ The default setting is to use port 8888.
D*/
+/*F*/
+int gpioCfgSocketPath(const char * path);
+/*D
+Configures pigpio to use the specified Unix socket.
+
+This function is only effective if called before [*gpioInitialise*].
+
+. .
+port: path to the socket file.
+. .
+
+The default is "/var/run/pigpio.sock".
+D*/
+
+
/*F*/
int gpioCfgInterfaces(unsigned ifFlags);
/*D
@@ -5538,6 +5556,7 @@ These functions are only effective if called before [*gpioInitialise*].
[*gpioCfgPermissions*]
[*gpioCfgInterfaces*]
[*gpioCfgSocketPort*]
+[*gpioCfgSocketPath*]
[*gpioCfgMemAlloc*]
gpioGetSamplesFunc_t::
@@ -6528,6 +6547,12 @@ 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_BAD_SOCKET_PATH -152 // socket path empty
#define PI_PIGIF_ERR_0 -2000
#define PI_PIGIF_ERR_99 -2099
@@ -6550,6 +6575,7 @@ after this command is issued.
#define PI_DEFAULT_DMA_PRIMARY_CH_2711 7
#define PI_DEFAULT_DMA_SECONDARY_CH_2711 6
#define PI_DEFAULT_DMA_NOT_SET 15
+#define PI_DEFAULT_SOCKET_PATH "/var/run/pigpio.sock"
#define PI_DEFAULT_SOCKET_PORT 8888
#define PI_DEFAULT_SOCKET_PORT_STR "8888"
#define PI_DEFAULT_SOCKET_ADDR_STR "localhost"
diff --git a/pigpio.py b/pigpio.py
index 20d48e6c..cf01ca35 100644
--- a/pigpio.py
+++ b/pigpio.py
@@ -723,6 +723,7 @@
PI_CMD_INTERRUPTED =-144
PI_NOT_ON_BCM2711 =-145
PI_ONLY_ON_BCM2711 =-146
+_PI_BAD_SOCKET_PATH =-152
# pigpio error text
@@ -871,6 +872,7 @@
[PI_CMD_INTERRUPTED , "pigpio command interrupted"],
[PI_NOT_ON_BCM2711 , "not available on BCM2711"],
[PI_ONLY_ON_BCM2711 , "only available on BCM2711"],
+ [_PI_BAD_SOCKET_PATH , "socket path empty"],
]
_except_a = "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n{}"
@@ -1119,10 +1121,10 @@ def __init__(self, gpio, edge, func):
class _callback_thread(threading.Thread):
"""A class to encapsulate pigpio notification callbacks."""
- def __init__(self, control, host, port):
+ def __init__(self, main):
"""Initialises notifications."""
threading.Thread.__init__(self)
- self.control = control
+ self.control = main.sl
self.sl = _socklock()
self.go = False
self.daemon = True
@@ -1130,7 +1132,11 @@ def __init__(self, control, host, port):
self.event_bits = 0
self.callbacks = []
self.events = []
- self.sl.s = socket.create_connection((host, port), None)
+ if main._sock:
+ self.sl.s = socket.socket(family=socket.AF_UNIX, type=socket.SOCK_STREAM)
+ self.sl.s.connect(main._sock)
+ else:
+ self.sl.s = socket.create_connection((main._host, main._port), None)
self.lastLevel = _pigpio_command(self.sl, _PI_CMD_BR1, 0, 0)
self.handle = _u2i(_pigpio_command(self.sl, _PI_CMD_NOIB, 0, 0))
self.go = True
@@ -5177,6 +5183,7 @@ def wait_for_event(self, event, wait_timeout=60.0):
def __init__(self,
host = os.getenv("PIGPIO_ADDR", 'localhost'),
port = os.getenv("PIGPIO_PORT", 8888),
+ sock = os.getenv("PIGPIO_SOCKET", None),
show_errors = True):
"""
Grants access to a Pi's GPIO.
@@ -5201,6 +5208,7 @@ def __init__(self,
pi = pigio.pi() # use defaults
pi = pigpio.pi('mypi') # specify host, default port
pi = pigpio.pi('mypi', 7777) # specify host and port
+ pi = pigpio.pi(sock='/run/pigpio.sock') # specify a Unix socket
pi = pigpio.pi() # exit script if no connection
if not pi.connected:
@@ -5212,21 +5220,26 @@ def __init__(self,
self.sl = _socklock()
self._notify = None
- port = int(port)
+ self._sock = sock
+ try:
+ if sock:
+ self.sl.s = socket.socket(family=socket.AF_UNIX, type=socket.SOCK_STREAM)
+ self.sl.s.connect(sock)
+ else:
+ port = int(port)
- if host == '':
- host = "localhost"
+ if host == '':
+ host = "localhost"
- self._host = host
- self._port = port
+ self._host = host
+ self._port = port
- try:
- self.sl.s = socket.create_connection((host, port), None)
+ self.sl.s = socket.create_connection((host, port), None)
- # Disable the Nagle algorithm.
- self.sl.s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+ # Disable the Nagle algorithm.
+ self.sl.s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
- self._notify = _callback_thread(self.sl, host, port)
+ self._notify = _callback_thread(self)
except socket.error:
exception = 1
@@ -5264,7 +5277,9 @@ def __init__(self,
print(_except_z)
def __repr__(self):
- return "".format(self._host, self._port)
+ if self._sock is None:
+ return "".format(self._host, self._port)
+ return "".format(self._sock)
def stop(self):
"""Release pigpio resources.
diff --git a/pigpiod.c b/pigpiod.c
index 899ddf8e..86bd14e4 100644
--- a/pigpiod.c
+++ b/pigpiod.c
@@ -59,6 +59,7 @@ static int foreground = PI_DEFAULT_FOREGROUND;
static unsigned DMAprimaryChannel = PI_DEFAULT_DMA_NOT_SET;
static unsigned DMAsecondaryChannel = PI_DEFAULT_DMA_NOT_SET;
static unsigned socketPort = PI_DEFAULT_SOCKET_PORT;
+static char * socketPath = PI_DEFAULT_SOCKET_PATH;
static unsigned memAllocMode = PI_DEFAULT_MEM_ALLOC_MODE;
static uint64_t updateMask = -1;
@@ -67,6 +68,9 @@ static uint32_t cfgInternals = PI_DEFAULT_CFG_INTERNALS;
static int updateMaskSet = 0;
static FILE * errFifo;
+volatile sig_atomic_t hupFlag = 0;
+volatile sig_atomic_t termFlag = 0;
+volatile sig_atomic_t contFlag = 0;
static uint32_t sockNetAddr[MAX_CONNECT_ADDRESSES];
@@ -106,6 +110,7 @@ void usage()
" -n IP addr, allow address, name or dotted, default allow all\n" \
" -p value, socket port, 1024-32000, default 8888\n" \
" -s value, sample rate, 1, 2, 4, 5, 8, or 10, default 5\n" \
+ " -S path, Unix socket file, default /var/run/pigpio.sock\n" \
" -t value, clock peripheral, 0=PWM 1=PCM, default PCM\n" \
" -v, -V, display pigpio version and exit\n" \
" -x mask, GPIO which may be updated, default board GPIO\n" \
@@ -163,7 +168,7 @@ static void initOpts(int argc, char *argv[])
uint32_t addr;
int64_t mask;
- while ((opt = getopt(argc, argv, "a:b:c:d:e:fgkln:mp:s:t:x:vV")) != -1)
+ while ((opt = getopt(argc, argv, "a:b:c:d:e:fgkln:mp:s:S:t:x:vV")) != -1)
{
switch (opt)
{
@@ -256,6 +261,12 @@ static void initOpts(int argc, char *argv[])
}
break;
+ case 'S':
+ if (!*optarg)
+ fatal("invalid -S option (empty string)");
+ socketPath = optarg;
+ break;
+
case 't':
i = getNum(optarg, &err);
if ((i >= PI_CLOCK_PWM) && (i <= PI_CLOCK_PCM))
@@ -286,13 +297,15 @@ static void initOpts(int argc, char *argv[])
}
}
-void terminate(int signum)
+void terminate()
{
- /* only registered for SIGHUP/SIGTERM */
+ /* only registered for SIGHUP/SIGTERM/SIGCONT */
gpioTerminate();
- fprintf(errFifo, "SIGHUP/SIGTERM received\n");
+ if (hupFlag) fprintf(stderr, "SIGHUP received %d times\n", hupFlag);
+ if (termFlag) fprintf(stderr, "SIGTERM received %d times\n", termFlag);
+ if (contFlag) fprintf(stderr, "SIGCONT received %d times\n", contFlag);
fflush(NULL);
@@ -303,6 +316,16 @@ void terminate(int signum)
exit(0);
}
+void mySigHandler(int signum)
+{
+ /* Catch multiple signals - ie systemd issues SIGTERM and SIGCONT */
+ switch (signum)
+ {
+ case SIGHUP: hupFlag++; break;
+ case SIGTERM: termFlag++; break;
+ case SIGCONT: contFlag++; break;
+ }
+}
int main(int argc, char **argv)
{
@@ -313,7 +336,18 @@ int main(int argc, char **argv)
initOpts(argc, argv);
- if (!foreground) {
+ /* create pipe for error reporting & communicate child init is complete */
+
+ unlink(PI_ERRFIFO);
+
+ mkfifo(PI_ERRFIFO, 0664);
+
+ if (chmod(PI_ERRFIFO, 0664) < 0)
+ fatal("chmod %s failed (%m)", PI_ERRFIFO);
+
+
+ if (!foreground)
+ {
/* Fork off the parent process */
pid = fork();
@@ -322,7 +356,16 @@ int main(int argc, char **argv)
/* If we got a good PID, then we can exit the parent process. */
- if (pid > 0) { exit(EXIT_SUCCESS); }
+ if (pid > 0)
+ {
+ FILE *fdFifo = fopen(PI_ERRFIFO, "r"); // block until daemon init'ed
+
+ if (fdFifo == NULL) {
+ perror("parent could not open pipe");
+ exit(EXIT_FAILURE);
+ }
+ else exit(EXIT_SUCCESS);
+ }
/* Change the file mode mask */
@@ -358,6 +401,8 @@ int main(int argc, char **argv)
gpioCfgSocketPort(socketPort);
+ gpioCfgSocketPath(socketPath);
+
gpioCfgMemAlloc(memAllocMode);
if (updateMaskSet) gpioCfgPermissions(updateMask);
@@ -370,16 +415,15 @@ int main(int argc, char **argv)
if (gpioInitialise()< 0) fatal("Can't initialise pigpio library");
- /* create pipe for error reporting */
-
- unlink(PI_ERRFIFO);
-
- mkfifo(PI_ERRFIFO, 0664);
+ /* open errFifo */
- if (chmod(PI_ERRFIFO, 0664) < 0)
- fatal("chmod %s failed (%m)", PI_ERRFIFO);
+ // daemon logs messages to errFifo (normal)
+ if (getenv("PIGPIO_ENV_LOG_STDERR") == NULL)
+ errFifo = freopen(PI_ERRFIFO, "w+", stderr);
- errFifo = freopen(PI_ERRFIFO, "w+", stderr);
+ // daemon logs to stderr
+ else
+ errFifo = fopen(PI_ERRFIFO, "w+");
if (errFifo)
{
@@ -388,21 +432,20 @@ int main(int argc, char **argv)
flags = fcntl(fileno(errFifo), F_GETFL, 0);
fcntl(fileno(errFifo), F_SETFL, flags | O_NONBLOCK);
- /* request SIGHUP/SIGTERM from libarary for termination */
+ /* install handlers for safe exit on SIGHUP/SIGTERM/SIGCONT */
- gpioSetSignalFunc(SIGHUP, terminate);
- gpioSetSignalFunc(SIGTERM, terminate);
+ gpioSetSignalFunc(SIGHUP, mySigHandler);
+ gpioSetSignalFunc(SIGTERM, mySigHandler);
+ gpioSetSignalFunc(SIGCONT, mySigHandler); //systemd along w/SIGTERM
- /* sleep forever */
+ /* sleep until signaled */
- while (1)
+ while (hupFlag==0 && termFlag==0 && contFlag==0)
{
- /* cat /dev/pigerr to view daemon errors */
-
sleep(5);
-
fflush(errFifo);
}
+ terminate();
}
else
{
diff --git a/pigpiod_if2.h b/pigpiod_if2.h
index b6aa6486..ab32573b 100644
--- a/pigpiod_if2.h
+++ b/pigpiod_if2.h
@@ -592,8 +592,8 @@ user_gpio: 0-31.
range: 25-40000.
. .
-Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYRANGE,
-or PI_NOT_PERMITTED.
+Returns the actual range for the current gpio frequency if OK,
+otherwise PI_BAD_USER_GPIO, PI_BAD_DUTYRANGE, or PI_NOT_PERMITTED.
Notes
diff --git a/pigs.c b/pigs.c
index 928afa3d..6b605f59 100644
--- a/pigs.c
+++ b/pigs.c
@@ -37,6 +37,7 @@ This version is for pigpio version 69+
#include
#include
#include
+#include
#include
#include
@@ -109,40 +110,62 @@ static int initOpts(int argc, char *argv[])
static int openSocket(void)
{
- int sock, err;
- struct addrinfo hints, *res, *rp;
- const char *addrStr, *portStr;
+ int sock;
+ const char *sockStr;
- portStr = getenv(PI_ENVPORT);
+ sockStr = getenv(PI_ENVSOCK);
+ if (sockStr && *sockStr)
+ {
+ struct sockaddr_un addr;
+ addr.sun_family = AF_LOCAL;
+ strncpy (addr.sun_path, sockStr, sizeof (addr.sun_path));
+ addr.sun_path[sizeof (addr.sun_path) - 1] = 0;
+ sock = socket (AF_LOCAL, SOCK_STREAM, 0);
+ if (sock > -1)
+ {
+ if (connect (sock, (struct sockaddr *) &addr, sizeof (addr)) == -1)
+ {
+ close(sock);
+ sock = -1;
+ }
+ }
+ }
+ else
+ {
+ int err;
+ struct addrinfo hints, *res, *rp;
+ const char *addrStr, *portStr;
- if (!portStr) portStr = PI_DEFAULT_SOCKET_PORT_STR;
+ portStr = getenv(PI_ENVPORT);
- addrStr = getenv(PI_ENVADDR);
+ if (!portStr) portStr = PI_DEFAULT_SOCKET_PORT_STR;
- if (!addrStr) addrStr = PI_DEFAULT_SOCKET_ADDR_STR;
+ addrStr = getenv(PI_ENVADDR);
- memset (&hints, 0, sizeof (hints));
+ if (!addrStr) addrStr = PI_DEFAULT_SOCKET_ADDR_STR;
- hints.ai_family = PF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags |= AI_CANONNAME;
+ memset (&hints, 0, sizeof (hints));
- err = getaddrinfo(addrStr, portStr, &hints, &res);
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags |= AI_CANONNAME;
- if (err) return SOCKET_OPEN_FAILED;
+ err = getaddrinfo(addrStr, portStr, &hints, &res);
- for (rp=res; rp!=NULL; rp=rp->ai_next)
- {
- sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+ if (err) return SOCKET_OPEN_FAILED;
- if (sock == -1) continue;
+ for (rp=res; rp!=NULL; rp=rp->ai_next)
+ {
+ sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
- if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) break;
- }
+ if (sock == -1) continue;
- freeaddrinfo(res);
+ if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) break;
+ }
- if (rp == NULL) return SOCKET_OPEN_FAILED;
+ freeaddrinfo(res);
+ if (rp == NULL) return SOCKET_OPEN_FAILED;
+ }
return sock;
}
diff --git a/x_pigpio.c b/x_pigpio.c
index 8119d73c..ed0ee381 100644
--- a/x_pigpio.c
+++ b/x_pigpio.c
@@ -22,6 +22,7 @@ sudo ./x_pigpio
#include
#include
#include
+#include
#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();