From 20f54a28cab83846e10251176d394d8d060adf29 Mon Sep 17 00:00:00 2001 From: Panu Matilainen Date: Thu, 15 Dec 2016 14:02:56 +0200 Subject: Add an shortcut API for blocking/unblocking signals For rpm's purposes blocking all signals and restoring to previous status is the only necessary operation, make this part of the official API to make it available everywhere and replace rpmdb internal signal handling code with it. Noteworthy points: - The block/unblock operation is reference counted so these can be nested to arbitrary level without messing up things, much like the internal chroot API. - The rpmdb code used to remove rpmsq signals from the blocked mask, but blocked should really mean blocked, really. The pending signals will be delivered when unblocked and there's no need for us to mess with it. - Unlike the rpmdb variant, we now Run rpmsqPoll() *after* unblocking the signals. This actually matters now because rpmsqPoll() honors blocked signals since commit 07620f4ae7b626e6e02d743b1e933cf909ad0eb2. --- lib/rpmdb.c | 14 ++------------ rpmio/rpmsq.c | 27 +++++++++++++++++++++++++++ rpmio/rpmsq.h | 9 +++++++++ 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/lib/rpmdb.c b/lib/rpmdb.c index e9ab15c5e..8104dcae5 100644 --- a/lib/rpmdb.c +++ b/lib/rpmdb.c @@ -332,16 +332,7 @@ void rpmAtExit(void) */ static int blockSignals(sigset_t * oldMask) { - sigset_t newMask; - - (void) sigfillset(&newMask); /* block all signals */ - (void) sigprocmask(SIG_BLOCK, &newMask, oldMask); - (void) sigdelset(&newMask, SIGINT); - (void) sigdelset(&newMask, SIGQUIT); - (void) sigdelset(&newMask, SIGHUP); - (void) sigdelset(&newMask, SIGTERM); - (void) sigdelset(&newMask, SIGPIPE); - return sigprocmask(SIG_BLOCK, &newMask, NULL); + return rpmsqBlock(SIG_BLOCK); } /** @@ -349,8 +340,7 @@ static int blockSignals(sigset_t * oldMask) */ static int unblockSignals(sigset_t * oldMask) { - (void) rpmsqPoll(); - return sigprocmask(SIG_SETMASK, oldMask, NULL); + return rpmsqBlock(SIG_UNBLOCK); } rpmop rpmdbOp(rpmdb rpmdb, rpmdbOpX opx) diff --git a/rpmio/rpmsq.c b/rpmio/rpmsq.c index 1d0e73a6c..6dacd77bf 100644 --- a/rpmio/rpmsq.c +++ b/rpmio/rpmsq.c @@ -162,6 +162,33 @@ int rpmsqPoll(void) return n; } +int rpmsqBlock(int op) +{ + static sigset_t oldMask; + static int blocked = 0; + sigset_t newMask; + int ret = 0; + + if (op == SIG_BLOCK) { + blocked++; + if (blocked == 1) { + sigfillset(&newMask); + ret = sigprocmask(SIG_BLOCK, &newMask, &oldMask); + } + } else if (op == SIG_UNBLOCK) { + blocked--; + if (blocked == 0) { + ret = sigprocmask(SIG_SETMASK, &oldMask, NULL); + rpmsqPoll(); + } else if (blocked < 0) { + blocked = 0; + ret = -1; + } + } + + return ret; +} + /** \ingroup rpmio * * By default, librpm will trap various unix signals such as SIGINT and SIGTERM, diff --git a/rpmio/rpmsq.h b/rpmio/rpmsq.h index 7a2cd8ba1..8cb2dc324 100644 --- a/rpmio/rpmsq.h +++ b/rpmio/rpmsq.h @@ -44,6 +44,15 @@ int rpmsqActivate(int state); */ rpmsqAction_t rpmsqSetAction(int signum, rpmsqAction_t handler); +/** \ingroup rpmsq + * Block or unblock (all) signals. + * The operation is "reference counted" so the calls can be nested, + * and signals are only unblocked when the reference count falls to zero. + * @param op SIG_BLOCK/SIG_UNBLOCK + * @return 0 on success, -1 on error + */ +int rpmsqBlock(int op); + /** \ingroup rpmsq * Poll for caught signals, executing their handlers. * @return no. active signals found -- cgit v1.2.1