summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPanu Matilainen <pmatilai@redhat.com>2016-12-15 10:49:09 +0200
committerPanu Matilainen <pmatilai@redhat.com>2016-12-15 10:59:02 +0200
commitb275b940619bd8add69f89dc2cb55920c3915a7a (patch)
treedf48191931a9b48f101ffa9f3f801f81d8032157
parent3ecd11318e699d4e7a4a5adb33eafb4dc2dc7b53 (diff)
downloadrpm-b275b940619bd8add69f89dc2cb55920c3915a7a.tar.gz
Make signal queue on/off a global atomic state
We always want the signal queue either enabled for the certain set of signals or completely disabled, make the API reflect that and make the switch "atomic", ie signal delivery is disabled while changing state. Perhaps more importantly, this allows changing signal handlers "offline", so an application can set its own signal handler for, say, SIGINT *in case* the signal queue is activated.
-rw-r--r--lib/rpmdb.c12
-rw-r--r--rpmio/rpmsq.c89
-rw-r--r--rpmio/rpmsq.h17
3 files changed, 63 insertions, 55 deletions
diff --git a/lib/rpmdb.c b/lib/rpmdb.c
index 82b083e00..e9ab15c5e 100644
--- a/lib/rpmdb.c
+++ b/lib/rpmdb.c
@@ -451,11 +451,7 @@ int rpmdbClose(rpmdb db)
db = _free(db);
if (rpmdbRock == NULL) {
- (void) rpmsqEnable(-SIGHUP, NULL);
- (void) rpmsqEnable(-SIGINT, NULL);
- (void) rpmsqEnable(-SIGTERM, NULL);
- (void) rpmsqEnable(-SIGQUIT, NULL);
- (void) rpmsqEnable(-SIGPIPE, NULL);
+ rpmsqActivate(0);
}
exit:
return rc;
@@ -536,11 +532,7 @@ static int openDatabase(const char * prefix,
rc = rpmioMkpath(rpmdbHome(db), 0755, getuid(), getgid());
if (rc == 0) {
if (rpmdbRock == NULL) {
- (void) rpmsqEnable(SIGHUP, NULL);
- (void) rpmsqEnable(SIGINT, NULL);
- (void) rpmsqEnable(SIGTERM, NULL);
- (void) rpmsqEnable(SIGQUIT, NULL);
- (void) rpmsqEnable(SIGPIPE, NULL);
+ rpmsqActivate(1);
}
/* Just the primary Packages database opened here */
diff --git a/rpmio/rpmsq.c b/rpmio/rpmsq.c
index 74dc24ce7..c2efb4714 100644
--- a/rpmio/rpmsq.c
+++ b/rpmio/rpmsq.c
@@ -79,49 +79,58 @@ static void rpmsqHandler(int signum, siginfo_t * info, void * context)
errno = save;
}
-int rpmsqEnable(int signum, rpmsqAction_t handler)
+rpmsqAction_t rpmsqSetAction(int signum, rpmsqAction_t handler)
{
- int tblsignum = abs(signum);
- struct sigaction sa;
- rpmsig tbl;
- int ret = -1;
+ rpmsig sig = NULL;
+ rpmsqAction_t oh = NULL;
+
+ if (rpmsigGet(signum, &sig)) {
+ oh = sig->handler;
+ sig->handler = handler;
+ }
+ return oh;
+}
+
+int rpmsqActivate(int state)
+{
+ sigset_t newMask, oldMask;
if (disableInterruptSafety)
return 0;
- for (tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
- if (tblsignum != tbl->signum)
- continue;
-
- if (signum >= 0) { /* Enable. */
- if (!sigismember(&rpmsqActive, tblsignum)) {
- (void) sigdelset(&rpmsqCaught, tbl->signum);
-
- /* XXX Don't set a signal handler if already SIG_IGN */
- (void) sigaction(tbl->signum, NULL, &tbl->oact);
- if (tbl->oact.sa_handler == SIG_IGN)
- continue;
-
- (void) sigemptyset (&sa.sa_mask);
- sa.sa_flags = SA_SIGINFO;
- sa.sa_sigaction = rpmsqHandler;
- if (sigaction(tbl->signum, &sa, &tbl->oact) < 0)
- break;
- sigaddset(&rpmsqActive, tblsignum);
- tbl->handler = (handler != NULL) ? handler : tbl->defhandler;
- }
- } else { /* Disable. */
- if (sigismember(&rpmsqActive, tblsignum)) {
- if (sigaction(tbl->signum, &tbl->oact, NULL) < 0)
- break;
- sigdelset(&rpmsqActive, tblsignum);
- tbl->handler = NULL;
+ (void) sigfillset(&newMask);
+ (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
+
+ if (state) {
+ struct sigaction sa;
+ for (rpmsig tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
+ sigdelset(&rpmsqCaught, tbl->signum);
+ memset(&tbl->siginfo, 0, sizeof(tbl->siginfo));
+
+ /* XXX Don't set a signal handler if already SIG_IGN */
+ sigaction(tbl->signum, NULL, &tbl->oact);
+ if (tbl->oact.sa_handler == SIG_IGN)
+ continue;
+
+ sigemptyset (&sa.sa_mask);
+ sa.sa_flags = SA_SIGINFO;
+ sa.sa_sigaction = rpmsqHandler;
+ if (sigaction(tbl->signum, &sa, &tbl->oact) == 0)
+ sigaddset(&rpmsqActive, tbl->signum);
+ }
+ } else {
+ for (rpmsig tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
+ if (!sigismember(&rpmsqActive, tbl->signum))
+ continue;
+ if (sigaction(tbl->signum, &tbl->oact, NULL) == 0) {
+ sigdelset(&rpmsqActive, tbl->signum);
+ sigdelset(&rpmsqCaught, tbl->signum);
+ memset(&tbl->siginfo, 0, sizeof(tbl->siginfo));
}
}
- ret = sigismember(&rpmsqActive, tblsignum);
- break;
}
- return ret;
+ sigprocmask(SIG_SETMASK, &oldMask, NULL);
+ return 0;
}
int rpmsqPoll(void)
@@ -135,13 +144,13 @@ int rpmsqPoll(void)
for (rpmsig tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
if (sigismember(&rpmsqCaught, tbl->signum)) {
- n++;
+ rpmsqAction_t handler = (tbl->handler != NULL) ? tbl->handler :
+ tbl->defhandler;
/* delete signal before running handler to prevent recursing */
sigdelset(&rpmsqCaught, tbl->signum);
- if (tbl->handler) {
- tbl->handler(tbl->signum, &tbl->siginfo, NULL);
- memset(&tbl->siginfo, 0, sizeof(tbl->siginfo));
- }
+ handler(tbl->signum, &tbl->siginfo, NULL);
+ memset(&tbl->siginfo, 0, sizeof(tbl->siginfo));
+ n++;
}
}
sigprocmask(SIG_SETMASK, &oldMask, NULL);
diff --git a/rpmio/rpmsq.h b/rpmio/rpmsq.h
index f22c8f525..7a2cd8ba1 100644
--- a/rpmio/rpmsq.h
+++ b/rpmio/rpmsq.h
@@ -30,12 +30,19 @@ typedef void (*rpmsqAction_t) (int signum, siginfo_t * info, void * context);
int rpmsqIsCaught(int signum);
/** \ingroup rpmsq
- * Enable or disable a signal handler.
- * @param signum signal to enable (or disable if negative)
- * @param handler signal handler (or NULL to use default)
- * @return no. of refs, -1 on error
+ * Activate (or disable) the signal queue.
+ * @param state 1 to enable, 0 to disable
+ * @return 0 on success, negative on error
*/
-int rpmsqEnable(int signum, rpmsqAction_t handler);
+int rpmsqActivate(int state);
+
+/** \ingroup rpmsq
+ * Set or delete a signal handler for a signal.
+ * @param signum signal number
+ * @param handler signal handler or NULL to delete
+ * @return previous non-default handler (possibly NULL)
+ */
+rpmsqAction_t rpmsqSetAction(int signum, rpmsqAction_t handler);
/** \ingroup rpmsq
* Poll for caught signals, executing their handlers.