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();