7 #if defined(HAVE_PTHREAD_H) && !defined(__LCLINT__)
16 static struct rpmsqElem rpmsqRock;
18 rpmsq rpmsqQueue = &rpmsqRock;
20 void Insque(void * elem, void * prev)
23 insque(elem, (prev ? prev : rpmsqQueue));
26 void Remque(void * elem)
36 static pthread_mutex_t rpmsigTbl_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
40 static struct rpmsig_s {
42 void (*handler) (int signum);
44 struct sigaction oact;
46 { SIGINT, rpmsqHandler },
47 #define rpmsigTbl_sigint (&rpmsigTbl[0])
48 { SIGQUIT, rpmsqHandler },
49 #define rpmsigTbl_sigquit (&rpmsigTbl[1])
50 { SIGCHLD, rpmsqHandler },
51 #define rpmsigTbl_sigchld (&rpmsigTbl[2])
53 #define DO_LOCK() pthread_mutex_lock(&rpmsigTbl_lock);
54 #define DO_UNLOCK() pthread_mutex_unlock(&rpmsigTbl_lock);
56 { pthread_mutexattr_t attr; \
57 pthread_mutexattr_init(&attr); \
58 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
59 pthread_mutex_init (&rpmsigTbl_lock, &attr); \
60 pthread_mutexattr_destroy(&attr); \
61 rpmsigTbl_sigchld->active = 0; \
63 #define ADD_REF(__tbl) (__tbl)->active++
64 #define SUB_REF(__tbl) --(__tbl)->active
66 #define CLEANUP_HANDLER(__handler, __arg, __oldtypeptr) \
67 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, (__oldtypeptr)); \
68 pthread_cleanup_push((__handler), (__arg));
69 #define CLEANUP_RESET(__execute, __oldtype) \
70 pthread_cleanup_pop(__execute); \
71 pthread_setcanceltype ((__oldtype), &(__oldtype));
73 { SIGHUP, rpmsqHandler },
74 #define rpmsigTbl_sighup (&rpmsigTbl[3])
75 { SIGTERM, rpmsqHandler },
76 #define rpmsigTbl_sigterm (&rpmsigTbl[4])
77 { SIGPIPE, rpmsqHandler },
78 #define rpmsigTbl_sigpipe (&rpmsigTbl[5])
86 void rpmsqHandler(int signum)
90 for (tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
91 if (tbl->signum != signum)
94 (void) sigaddset(&rpmsqCaught, signum);
101 pid_t reaped = waitpid(0, &status, WNOHANG);
104 /*@innerbreak@*/ break;
106 for (sq = rpmsqQueue->q_forw;
107 sq != NULL && sq != rpmsqQueue;
110 if (sq->child != reaped)
111 /*@innercontinue@*/ continue;
114 /*@innerbreak@*/ break;
117 /*@switchbreak@*/ break;
119 /*@switchbreak@*/ break;
127 * Enable or disable a signal handler.
128 * @param signum signal to enable (or disable if negative)
129 * @param handler signal handler (or NULL to use rpmsqHandler())
130 * @return no. of refs, -1 on error
132 int rpmsqEnable(int signum, /*@null@*/ sighandler_t handler)
133 /*@globals rpmsqCaught, rpmsigTbl @*/
134 /*@modifies rpmsqCaught, rpmsigTbl @*/
136 int tblsignum = (signum >= 0 ? signum : -signum);
142 for (tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
143 if (tblsignum != tbl->signum)
146 if (signum >= 0) { /* Enable. */
147 if (ADD_REF(tbl) <= 0) {
148 tbl->active = 1; /* XXX just in case */
149 (void) sigdelset(&rpmsqCaught, tbl->signum);
151 sigemptyset (&sa.sa_mask);
152 sa.sa_handler = (handler != NULL ? handler : tbl->handler);
153 if (sigaction(tbl->signum, &sa, &tbl->oact) < 0) {
158 } else { /* Disable. */
159 if (SUB_REF(tbl) <= 0) {
160 tbl->active = 0; /* XXX just in case */
161 if (sigaction(tbl->signum, &tbl->oact, NULL) < 0)
173 * SIGCHLD cancellation handler.
176 sigchld_cancel (void *arg)
178 pid_t child = *(pid_t *) arg;
181 (void) kill(child, SIGKILL);
184 result = waitpid(child, NULL, 0);
185 } while (result == (pid_t)-1 && errno == EINTR);
188 if (SUB_REF (rpmsigTbl_sigchld) == 0) {
189 (void) rpmsqEnable(-SIGQUIT, NULL);
190 (void) rpmsqEnable(-SIGINT, NULL);
196 * Execute a command, returning its status.
199 rpmsqExecve (const char ** argv)
205 sigset_t newMask, oldMask;
208 if (ADD_REF (rpmsigTbl_sigchld) == 0) {
209 if (rpmsqEnable(SIGINT, NULL) < 0) {
210 SUB_REF (rpmsigTbl_sigchld);
213 if (rpmsqEnable(SIGQUIT, NULL) < 0) {
214 SUB_REF (rpmsigTbl_sigchld);
215 goto out_restore_sigint;
220 sigemptyset (&newMask);
221 sigaddset (&newMask, SIGCHLD);
222 if (sigprocmask (SIG_BLOCK, &newMask, &oldMask) < 0) {
224 if (SUB_REF (rpmsigTbl_sigchld) == 0)
225 goto out_restore_sigquit_and_sigint;
229 CLEANUP_HANDLER(sigchld_cancel, &pid, &oldtype);
232 if (pid < (pid_t) 0) { /* fork failed. */
234 } else if (pid == (pid_t) 0) { /* Child. */
236 /* Restore the signals. */
237 (void) sigaction (SIGINT, &rpmsigTbl_sigint->oact, NULL);
238 (void) sigaction (SIGQUIT, &rpmsigTbl_sigquit->oact, NULL);
239 (void) sigprocmask (SIG_SETMASK, &oldMask, NULL);
241 /* Reset rpmsigTbl lock and refcnt. */
244 (void) execve (argv[0], (char *const *) argv, environ);
246 } else { /* Parent. */
248 result = waitpid(pid, &status, 0);
249 } while (result == (pid_t)-1 && errno == EINTR);
254 CLEANUP_RESET(0, oldtype);
257 if ((SUB_REF (rpmsigTbl_sigchld) == 0 &&
258 (rpmsqEnable(-SIGINT, NULL) < 0 || rpmsqEnable (-SIGQUIT, NULL) < 0))
259 || sigprocmask (SIG_SETMASK, &oldMask, (sigset_t *) NULL) != 0)
265 out_restore_sigquit_and_sigint:
266 (void) rpmsqEnable(-SIGQUIT, NULL);
268 (void) rpmsqEnable(-SIGINT, NULL);