lwp: Rewrite signal wait code for portability and safety
LWP's use of sigset_t is problematic. To iterate over a sigset_t, it uses NSIG, which is not portable: BSD and System V provide it, but it's not POSIX. To record signals caught, it updates a sigset_t variable from a signal handler. The variable isn't volatile, because we'd have to cast away volatile for sigaddset(). Replace sigset_t by an array of signal numbers terminated with 0. Since lwpInitSigWait() needs to store the signal set for lwpCatchAwaitedSig() anyway, there is no need to pass it to lwpSigWait(). Drop its parameter. Signed-off-by: Markus Armbruster <armbru@pond.sub.org>
This commit is contained in:
parent
460cc9e2ee
commit
2e4793408c
5 changed files with 68 additions and 60 deletions
|
@ -28,7 +28,7 @@
|
||||||
* lwp.h -- prototypes and structures for lightweight processes
|
* lwp.h -- prototypes and structures for lightweight processes
|
||||||
*
|
*
|
||||||
* Known contributors to this file:
|
* Known contributors to this file:
|
||||||
* Markus Armbruster, 2004-2013
|
* Markus Armbruster, 2004-2020
|
||||||
* Ron Koenderink, 2007-2009
|
* Ron Koenderink, 2007-2009
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -41,7 +41,6 @@
|
||||||
#ifndef LWP_H
|
#ifndef LWP_H
|
||||||
#define LWP_H
|
#define LWP_H
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#define LWP_STACKCHECK 0x1
|
#define LWP_STACKCHECK 0x1
|
||||||
|
@ -55,7 +54,7 @@ struct lwp_rwlock;
|
||||||
|
|
||||||
#define LWP_MAX_PRIO 8
|
#define LWP_MAX_PRIO 8
|
||||||
|
|
||||||
struct lwpProc *lwpInitSystem(int prio, void **ctxp, int flags, sigset_t *);
|
struct lwpProc *lwpInitSystem(int prio, void **ctxp, int flags, int[]);
|
||||||
struct lwpProc *lwpCreate(int prio, void (*)(void *), int size,
|
struct lwpProc *lwpCreate(int prio, void (*)(void *), int size,
|
||||||
int flags, char *name,
|
int flags, char *name,
|
||||||
int argc, char **argv, void *ud);
|
int argc, char **argv, void *ud);
|
||||||
|
@ -65,7 +64,7 @@ void lwpYield(void);
|
||||||
int lwpSleepFd(int fd, int flags, struct timeval *timeout);
|
int lwpSleepFd(int fd, int flags, struct timeval *timeout);
|
||||||
int lwpSleepUntil(time_t until);
|
int lwpSleepUntil(time_t until);
|
||||||
void lwpWakeup(struct lwpProc *);
|
void lwpWakeup(struct lwpProc *);
|
||||||
int lwpSigWait(sigset_t *set, int *sig);
|
int lwpSigWait(int *sig);
|
||||||
void *lwpGetUD(struct lwpProc *);
|
void *lwpGetUD(struct lwpProc *);
|
||||||
void lwpSetUD(struct lwpProc *, char *ud);
|
void lwpSetUD(struct lwpProc *, char *ud);
|
||||||
int lwpSetPriority(int prio);
|
int lwpSetPriority(int prio);
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
*
|
*
|
||||||
* Known contributors to this file:
|
* Known contributors to this file:
|
||||||
* Sasha Mikheev
|
* Sasha Mikheev
|
||||||
* Markus Armbruster, 2006-2009
|
* Markus Armbruster, 2006-2020
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
@ -42,23 +42,16 @@
|
||||||
/* Flags that were passed to empth_init() */
|
/* Flags that were passed to empth_init() */
|
||||||
static int empth_flags;
|
static int empth_flags;
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
empth_init(void **ctx, int flags)
|
empth_init(void **ctx, int flags)
|
||||||
{
|
{
|
||||||
sigset_t set;
|
static int sig[] = { SIGHUP, SIGINT, SIGTERM, 0 };
|
||||||
|
|
||||||
empth_flags = flags;
|
empth_flags = flags;
|
||||||
empth_init_signals();
|
empth_init_signals();
|
||||||
sigemptyset(&set);
|
lwpInitSystem(1, ctx, flags, sig);
|
||||||
sigaddset(&set, SIGHUP);
|
|
||||||
sigaddset(&set, SIGINT);
|
|
||||||
sigaddset(&set, SIGTERM);
|
|
||||||
lwpInitSystem(1, ctx, flags, &set);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
empth_t *
|
empth_t *
|
||||||
empth_create(void (*entry)(void *), int size, int flags,
|
empth_create(void (*entry)(void *), int size, int flags,
|
||||||
char *name, void *ud)
|
char *name, void *ud)
|
||||||
|
@ -124,17 +117,12 @@ empth_sleep(time_t until)
|
||||||
int
|
int
|
||||||
empth_wait_for_signal(void)
|
empth_wait_for_signal(void)
|
||||||
{
|
{
|
||||||
sigset_t set;
|
|
||||||
int sig, err;
|
int sig, err;
|
||||||
time_t now;
|
time_t now;
|
||||||
|
|
||||||
ef_make_stale();
|
ef_make_stale();
|
||||||
sigemptyset(&set);
|
|
||||||
sigaddset(&set, SIGHUP);
|
|
||||||
sigaddset(&set, SIGINT);
|
|
||||||
sigaddset(&set, SIGTERM);
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
err = lwpSigWait(&set, &sig);
|
err = lwpSigWait(&sig);
|
||||||
if (CANT_HAPPEN(err)) {
|
if (CANT_HAPPEN(err)) {
|
||||||
time(&now);
|
time(&now);
|
||||||
lwpSleepUntil(now + 60);
|
lwpSleepUntil(now + 60);
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
* lwp.c: lightweight process creation, destruction and manipulation
|
* lwp.c: lightweight process creation, destruction and manipulation
|
||||||
*
|
*
|
||||||
* Known contributors to this file:
|
* Known contributors to this file:
|
||||||
* Markus Armbruster, 2004-2017
|
* Markus Armbruster, 2004-2020
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
@ -296,7 +296,7 @@ lwpSetPriority(int new)
|
||||||
* initialise the coroutine structures
|
* initialise the coroutine structures
|
||||||
*/
|
*/
|
||||||
struct lwpProc *
|
struct lwpProc *
|
||||||
lwpInitSystem(int pri, void **ctxptr, int flags, sigset_t *waitset)
|
lwpInitSystem(int pri, void **ctxptr, int flags, int sig[])
|
||||||
{
|
{
|
||||||
struct lwpQueue *q;
|
struct lwpQueue *q;
|
||||||
int i, *stack, marker;
|
int i, *stack, marker;
|
||||||
|
@ -323,7 +323,7 @@ lwpInitSystem(int pri, void **ctxptr, int flags, sigset_t *waitset)
|
||||||
for (i = LWP_MAX_PRIO, q = LwpSchedQ; i--; q++)
|
for (i = LWP_MAX_PRIO, q = LwpSchedQ; i--; q++)
|
||||||
q->head = q->tail = NULL;
|
q->head = q->tail = NULL;
|
||||||
LwpDeadQ.head = LwpDeadQ.tail = NULL;
|
LwpDeadQ.head = LwpDeadQ.tail = NULL;
|
||||||
lwpInitSigWait(waitset);
|
lwpInitSigWait(sig);
|
||||||
/* must be lower in priority than us for this to work right */
|
/* must be lower in priority than us for this to work right */
|
||||||
sel = lwpCreate(0, lwpSelect, 65536, flags, "EventHandler", 0,
|
sel = lwpCreate(0, lwpSelect, 65536, flags, "EventHandler", 0,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
|
@ -28,13 +28,12 @@
|
||||||
* lwpint.h: lwp internal structures
|
* lwpint.h: lwp internal structures
|
||||||
*
|
*
|
||||||
* Known contributors to this file:
|
* Known contributors to this file:
|
||||||
* Markus Armbruster, 2004-2009
|
* Markus Armbruster, 2004-2020
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LWPINT_H
|
#ifndef LWPINT_H
|
||||||
#define LWPINT_H
|
#define LWPINT_H
|
||||||
|
|
||||||
#include <signal.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <ucontext.h>
|
#include <ucontext.h>
|
||||||
|
|
||||||
|
@ -82,7 +81,7 @@ void lwpEntryPoint(void);
|
||||||
void lwpInitSelect(struct lwpProc *);
|
void lwpInitSelect(struct lwpProc *);
|
||||||
void lwpWakeupSleep(void);
|
void lwpWakeupSleep(void);
|
||||||
void lwpSelect(void *);
|
void lwpSelect(void *);
|
||||||
void lwpInitSigWait(sigset_t *);
|
void lwpInitSigWait(int[]);
|
||||||
void lwpSigWakeup(void);
|
void lwpSigWakeup(void);
|
||||||
void lwpStatus(struct lwpProc *, char *, ...)
|
void lwpStatus(struct lwpProc *, char *, ...)
|
||||||
ATTRIBUTE((format (printf, 2, 3)));
|
ATTRIBUTE((format (printf, 2, 3)));
|
||||||
|
|
|
@ -34,20 +34,26 @@
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include "lwp.h"
|
#include "lwp.h"
|
||||||
#include "lwpint.h"
|
#include "lwpint.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Signals caught so far.
|
* Awaited signal numbers, terminated with 0.
|
||||||
* Access only with signals blocked!
|
|
||||||
*/
|
*/
|
||||||
static sigset_t LwpSigCaught;
|
static int *LwpAwaitedSig;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* LwpSigCaught changed since last
|
* Pending awaited signals.
|
||||||
|
* Access only with signals blocked!
|
||||||
*/
|
*/
|
||||||
static sig_atomic_t LwpSigCheck;
|
static volatile int *LwpSigCaught;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is there anything in LwpSigCaught[]?
|
||||||
|
*/
|
||||||
|
static volatile sig_atomic_t LwpSigCheck;
|
||||||
|
|
||||||
/* The thread waiting for signals in lwpSigWait() */
|
/* The thread waiting for signals in lwpSigWait() */
|
||||||
static struct lwpProc *LwpSigWaiter;
|
static struct lwpProc *LwpSigWaiter;
|
||||||
|
@ -55,80 +61,96 @@ static struct lwpProc *LwpSigWaiter;
|
||||||
static void lwpCatchAwaitedSig(int);
|
static void lwpCatchAwaitedSig(int);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize waiting for signals in @set.
|
* Initialize waiting for signals in @sig[].
|
||||||
|
* @sig[] contains signal numbers, terminated with 0. It must have
|
||||||
|
* static storage duration.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
lwpInitSigWait(sigset_t *set)
|
lwpInitSigWait(int sig[])
|
||||||
{
|
{
|
||||||
struct sigaction act;
|
struct sigaction act;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
sigemptyset(&LwpSigCaught);
|
LwpAwaitedSig = sig;
|
||||||
|
|
||||||
act.sa_flags = 0;
|
act.sa_flags = 0;
|
||||||
act.sa_mask = *set;
|
|
||||||
act.sa_handler = lwpCatchAwaitedSig;
|
act.sa_handler = lwpCatchAwaitedSig;
|
||||||
for (i = 0; i < NSIG; i++) {
|
sigemptyset(&act.sa_mask);
|
||||||
if (sigismember(set, i) > 0)
|
for (i = 0; sig[i]; i++)
|
||||||
sigaction(i, &act, NULL);
|
sigaddset(&act.sa_mask, sig[i]);
|
||||||
}
|
|
||||||
|
LwpSigCaught = calloc(i, sizeof(*LwpSigCaught));
|
||||||
|
|
||||||
|
for (i = 0; sig[i]; i++)
|
||||||
|
sigaction(sig[i], &act, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Signal handler for awaited signals.
|
||||||
|
* Set @LwpSigCaught[] for @sig, and set @LwpSigCheck.
|
||||||
|
* Not reentrant; lwpInitSigWait() guards.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
lwpCatchAwaitedSig(int sig)
|
lwpCatchAwaitedSig(int sig)
|
||||||
{
|
{
|
||||||
sigaddset(&LwpSigCaught, sig);
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; LwpAwaitedSig[i]; i++) {
|
||||||
|
if (sig == LwpAwaitedSig[i])
|
||||||
|
LwpSigCaught[i] = 1;
|
||||||
|
}
|
||||||
LwpSigCheck = 1;
|
LwpSigCheck = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test whether a signal from @set has been caught.
|
* Test whether an awaited signal is pending.
|
||||||
* If yes, delete that signal from the set of caught signals, and
|
* If yes, remove that signal from the set of pending signals, and
|
||||||
* return its number.
|
* return its number.
|
||||||
* Else return 0.
|
* Else return 0.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
lwpGetSig(sigset_t *set)
|
lwpGetSig(void)
|
||||||
{
|
{
|
||||||
sigset_t save;
|
int ret = 0;
|
||||||
int i, j;
|
sigset_t set, save;
|
||||||
|
int i;
|
||||||
|
|
||||||
sigprocmask(SIG_BLOCK, set, &save);
|
sigemptyset(&set);
|
||||||
|
for (i = 0; LwpAwaitedSig[i]; i++)
|
||||||
|
sigaddset(&set, LwpAwaitedSig[i]);
|
||||||
|
sigprocmask(SIG_BLOCK, &set, &save);
|
||||||
|
|
||||||
for (i = NSIG - 1; i > 0; i--) {
|
for (i = 0; LwpAwaitedSig[i]; i++) {
|
||||||
if (sigismember(set, i) > 0 && sigismember(&LwpSigCaught, i) > 0) {
|
if (LwpSigCaught[i]) {
|
||||||
lwpStatus(LwpCurrent, "Got awaited signal %d", i);
|
lwpStatus(LwpCurrent, "Got awaited signal %d", LwpSigCaught[i]);
|
||||||
sigdelset(&LwpSigCaught, i);
|
ret = LwpAwaitedSig[i];
|
||||||
break;
|
LwpSigCaught[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = i;
|
for (; LwpAwaitedSig[i] && LwpSigCaught[i]; i++) ;
|
||||||
sigismember(set, i) > 0 && sigismember(&LwpSigCaught, i) > 0;
|
if (!LwpSigCaught[i])
|
||||||
j--)
|
|
||||||
;
|
|
||||||
if (!j)
|
|
||||||
LwpSigCheck = 0;
|
LwpSigCheck = 0;
|
||||||
|
|
||||||
sigprocmask(SIG_SETMASK, &save, NULL);
|
sigprocmask(SIG_SETMASK, &save, NULL);
|
||||||
return i;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait until a signal from @set arrives.
|
* Wait until one of the signals passed to lwpInitSigWait() arrives.
|
||||||
* Assign its number to *@sig and return 0.
|
* Assign its number to *@sig and return 0.
|
||||||
* If another thread is already waiting for signals, return EBUSY
|
* If another thread is already waiting for signals, return EBUSY
|
||||||
* without waiting.
|
* without waiting.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
lwpSigWait(sigset_t *set, int *sig)
|
lwpSigWait(int *sig)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (LwpSigWaiter)
|
if (LwpSigWaiter)
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
res = lwpGetSig(set);
|
res = lwpGetSig();
|
||||||
if (res > 0)
|
if (res > 0)
|
||||||
break;
|
break;
|
||||||
lwpStatus(LwpCurrent, "Waiting for signals");
|
lwpStatus(LwpCurrent, "Waiting for signals");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue