rpm
4.5
|
00001 00005 #include "system.h" 00006 00007 #if defined(__LCLINT__) 00008 #define _BITS_SIGTHREAD_H /* XXX avoid __sigset_t heartburn. */ 00009 00010 /*@-incondefs -protoparammatch@*/ 00011 /*@-exportheader@*/ 00012 /*@constant int SA_SIGINFO@*/ 00013 extern int sighold(int sig) 00014 /*@globals errno, systemState @*/; 00015 extern int sigignore(int sig) 00016 /*@globals errno, systemState @*/; 00017 extern int sigpause(int sig) 00018 /*@globals errno, systemState @*/; 00019 extern int sigrelse(int sig) 00020 /*@globals errno, systemState @*/; 00021 extern void (*sigset(int sig, void (*disp)(int)))(int) 00022 /*@globals errno, systemState @*/; 00023 00024 struct qelem; 00025 extern void insque(struct qelem * __elem, struct qelem * __prev) 00026 /*@modifies __elem, __prev @*/; 00027 extern void remque(struct qelem * __elem) 00028 /*@modifies __elem @*/; 00029 00030 extern pthread_t pthread_self(void) 00031 /*@*/; 00032 extern int pthread_equal(pthread_t t1, pthread_t t2) 00033 /*@*/; 00034 00035 extern int pthread_create(/*@out@*/ pthread_t *restrict thread, 00036 const pthread_attr_t *restrict attr, 00037 void *(*start_routine)(void*), void *restrict arg) 00038 /*@modifies *thread @*/; 00039 extern int pthread_join(pthread_t thread, /*@out@*/ void **value_ptr) 00040 /*@modifies *value_ptr @*/; 00041 00042 extern int pthread_setcancelstate(int state, /*@out@*/ int *oldstate) 00043 /*@globals internalState @*/ 00044 /*@modifies *oldstate, internalState @*/; 00045 extern int pthread_setcanceltype(int type, /*@out@*/ int *oldtype) 00046 /*@globals internalState @*/ 00047 /*@modifies *oldtype, internalState @*/; 00048 extern void pthread_testcancel(void) 00049 /*@globals internalState @*/ 00050 /*@modifies internalState @*/; 00051 extern void pthread_cleanup_pop(int execute) 00052 /*@globals internalState @*/ 00053 /*@modifies internalState @*/; 00054 extern void pthread_cleanup_push(void (*routine)(void*), void *arg) 00055 /*@globals internalState @*/ 00056 /*@modifies internalState @*/; 00057 extern void _pthread_cleanup_pop(/*@out@*/ struct _pthread_cleanup_buffer *__buffer, int execute) 00058 /*@globals internalState @*/ 00059 /*@modifies internalState @*/; 00060 extern void _pthread_cleanup_push(/*@out@*/ struct _pthread_cleanup_buffer *__buffer, void (*routine)(void*), /*@out@*/ void *arg) 00061 /*@globals internalState @*/ 00062 /*@modifies internalState @*/; 00063 00064 extern int pthread_mutexattr_destroy(pthread_mutexattr_t *attr) 00065 /*@globals errno, internalState @*/ 00066 /*@modifies *attr, errno, internalState @*/; 00067 extern int pthread_mutexattr_init(/*@out@*/ pthread_mutexattr_t *attr) 00068 /*@globals errno, internalState @*/ 00069 /*@modifies *attr, errno, internalState @*/; 00070 00071 int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr, 00072 /*@out@*/ int *restrict type) 00073 /*@modifies *type @*/; 00074 int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) 00075 /*@globals errno, internalState @*/ 00076 /*@modifies *attr, errno, internalState @*/; 00077 00078 extern int pthread_mutex_destroy(pthread_mutex_t *mutex) 00079 /*@modifies *mutex @*/; 00080 extern int pthread_mutex_init(/*@out@*/ pthread_mutex_t *restrict mutex, 00081 /*@null@*/ const pthread_mutexattr_t *restrict attr) 00082 /*@globals errno, internalState @*/ 00083 /*@modifies *mutex, errno, internalState @*/; 00084 00085 extern int pthread_mutex_lock(pthread_mutex_t *mutex) 00086 /*@globals errno @*/ 00087 /*@modifies *mutex, errno @*/; 00088 extern int pthread_mutex_trylock(pthread_mutex_t *mutex) 00089 /*@globals errno @*/ 00090 /*@modifies *mutex, errno @*/; 00091 extern int pthread_mutex_unlock(pthread_mutex_t *mutex) 00092 /*@globals errno @*/ 00093 /*@modifies *mutex, errno @*/; 00094 00095 extern int pthread_cond_destroy(pthread_cond_t *cond) 00096 /*@modifies *cond @*/; 00097 extern int pthread_cond_init(/*@out@*/ pthread_cond_t *restrict cond, 00098 const pthread_condattr_t *restrict attr) 00099 /*@globals errno, internalState @*/ 00100 /*@modifies *cond, errno, internalState @*/; 00101 00102 extern int pthread_cond_timedwait(pthread_cond_t *restrict cond, 00103 pthread_mutex_t *restrict mutex, 00104 const struct timespec *restrict abstime) 00105 /*@modifies *cond, *mutex @*/; 00106 extern int pthread_cond_wait(pthread_cond_t *restrict cond, 00107 pthread_mutex_t *restrict mutex) 00108 /*@modifies *cond, *mutex @*/; 00109 extern int pthread_cond_broadcast(pthread_cond_t *cond) 00110 /*@globals errno, internalState @*/ 00111 /*@modifies *cond, errno, internalState @*/; 00112 extern int pthread_cond_signal(pthread_cond_t *cond) 00113 /*@globals errno, internalState @*/ 00114 /*@modifies *cond, errno, internalState @*/; 00115 00116 /*@=exportheader@*/ 00117 /*@=incondefs =protoparammatch@*/ 00118 #endif 00119 00120 #include <signal.h> 00121 #include <sys/signal.h> 00122 #include <sys/wait.h> 00123 #include <search.h> 00124 00125 #if defined(HAVE_PTHREAD_H) 00126 00127 #include <pthread.h> 00128 00129 /* XXX suggested in bugzilla #159024 */ 00130 #if PTHREAD_MUTEX_DEFAULT != PTHREAD_MUTEX_NORMAL 00131 #error RPM expects PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL 00132 #endif 00133 00134 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 00135 /*@unchecked@*/ 00136 static pthread_mutex_t rpmsigTbl_lock = PTHREAD_MUTEX_INITIALIZER; 00137 #else 00138 /*@unchecked@*/ 00139 /*@-type@*/ 00140 static pthread_mutex_t rpmsigTbl_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; 00141 /*@=type@*/ 00142 #endif 00143 00144 #define DO_LOCK() pthread_mutex_lock(&rpmsigTbl_lock); 00145 #define DO_UNLOCK() pthread_mutex_unlock(&rpmsigTbl_lock); 00146 #define INIT_LOCK() \ 00147 { pthread_mutexattr_t attr; \ 00148 (void) pthread_mutexattr_init(&attr); \ 00149 (void) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \ 00150 (void) pthread_mutex_init (&rpmsigTbl_lock, &attr); \ 00151 (void) pthread_mutexattr_destroy(&attr); \ 00152 rpmsigTbl_sigchld->active = 0; \ 00153 } 00154 #define ADD_REF(__tbl) (__tbl)->active++ 00155 #define SUB_REF(__tbl) --(__tbl)->active 00156 #define CLEANUP_HANDLER(__handler, __arg, __oldtypeptr) \ 00157 (void) pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, (__oldtypeptr));\ 00158 pthread_cleanup_push((__handler), (__arg)); 00159 #define CLEANUP_RESET(__execute, __oldtype) \ 00160 pthread_cleanup_pop(__execute); \ 00161 (void) pthread_setcanceltype ((__oldtype), &(__oldtype)); 00162 00163 #define SAME_THREAD(_a, _b) pthread_equal(((pthread_t)_a), ((pthread_t)_b)) 00164 00165 #define ME() ((void *)pthread_self()) 00166 00167 #else 00168 00169 #define DO_LOCK() 00170 #define DO_UNLOCK() 00171 #define INIT_LOCK() 00172 #define ADD_REF(__tbl) /*@-noeffect@*/ (0) /*@=noeffect@*/ 00173 #define SUB_REF(__tbl) /*@-noeffect@*/ (0) /*@=noeffect@*/ 00174 #define CLEANUP_HANDLER(__handler, __arg, __oldtypeptr) 00175 #define CLEANUP_RESET(__execute, __oldtype) 00176 00177 #define SAME_THREAD(_a, _b) (42) 00178 00179 #define ME() (((void *)getpid())) 00180 00181 #endif /* HAVE_PTHREAD_H */ 00182 00183 #include <rpmsq.h> 00184 00185 #include "debug.h" 00186 00187 #define _RPMSQ_DEBUG 0 00188 /*@unchecked@*/ 00189 int _rpmsq_debug = _RPMSQ_DEBUG; 00190 00191 /*@unchecked@*/ 00192 static struct rpmsqElem rpmsqRock; 00193 00194 /*@-compmempass@*/ 00195 /*@unchecked@*/ 00196 rpmsq rpmsqQueue = &rpmsqRock; 00197 /*@=compmempass@*/ 00198 00199 int rpmsqInsert(void * elem, void * prev) 00200 { 00201 rpmsq sq = (rpmsq) elem; 00202 int ret = -1; 00203 00204 if (sq != NULL) { 00205 #ifdef _RPMSQ_DEBUG 00206 if (_rpmsq_debug) 00207 fprintf(stderr, " Insert(%p): %p\n", ME(), sq); 00208 #endif 00209 ret = sighold(SIGCHLD); 00210 if (ret == 0) { 00211 sq->child = 0; 00212 sq->reaped = 0; 00213 sq->status = 0; 00214 /* ==> Set to 1 to catch SIGCHLD, set to 0 to use waitpid(2). */ 00215 sq->reaper = 1; 00216 /*@-bounds@*/ 00217 sq->pipes[0] = sq->pipes[1] = -1; 00218 /*@=bounds@*/ 00219 00220 sq->id = ME(); 00221 insque(elem, (prev != NULL ? prev : rpmsqQueue)); 00222 ret = sigrelse(SIGCHLD); 00223 } 00224 } 00225 return ret; 00226 } 00227 00228 int rpmsqRemove(void * elem) 00229 { 00230 rpmsq sq = (rpmsq) elem; 00231 int ret = -1; 00232 00233 if (elem != NULL) { 00234 00235 #ifdef _RPMSQ_DEBUG 00236 if (_rpmsq_debug) 00237 fprintf(stderr, " Remove(%p): %p\n", ME(), sq); 00238 #endif 00239 ret = sighold (SIGCHLD); 00240 if (ret == 0) { 00241 remque(elem); 00242 sq->id = NULL; 00243 /*@-bounds@*/ 00244 if (sq->pipes[1] > 0) ret = close(sq->pipes[1]); 00245 if (sq->pipes[0] > 0) ret = close(sq->pipes[0]); 00246 sq->pipes[0] = sq->pipes[1] = -1; 00247 /*@=bounds@*/ 00248 #ifdef NOTYET /* rpmpsmWait debugging message needs */ 00249 sq->status = 0; 00250 sq->reaped = 0; 00251 sq->child = 0; 00252 #endif 00253 ret = sigrelse(SIGCHLD); 00254 } 00255 } 00256 return ret; 00257 } 00258 00259 /*@unchecked@*/ 00260 sigset_t rpmsqCaught; 00261 00262 /*@unchecked@*/ 00263 /*@-fullinitblock@*/ 00264 static struct rpmsig_s { 00265 int signum; 00266 void (*handler) (int signum, void * info, void * context); 00267 int active; 00268 struct sigaction oact; 00269 } rpmsigTbl[] = { 00270 { SIGINT, rpmsqAction }, 00271 #define rpmsigTbl_sigint (&rpmsigTbl[0]) 00272 { SIGQUIT, rpmsqAction }, 00273 #define rpmsigTbl_sigquit (&rpmsigTbl[1]) 00274 { SIGCHLD, rpmsqAction }, 00275 #define rpmsigTbl_sigchld (&rpmsigTbl[2]) 00276 { SIGHUP, rpmsqAction }, 00277 #define rpmsigTbl_sighup (&rpmsigTbl[3]) 00278 { SIGTERM, rpmsqAction }, 00279 #define rpmsigTbl_sigterm (&rpmsigTbl[4]) 00280 { SIGPIPE, rpmsqAction }, 00281 #define rpmsigTbl_sigpipe (&rpmsigTbl[5]) 00282 { -1, NULL }, 00283 }; 00284 /*@=fullinitblock@*/ 00285 00286 void rpmsqAction(int signum, 00287 /*@unused@*/ void * info, /*@unused@*/ void * context) 00288 { 00289 int save = errno; 00290 rpmsig tbl; 00291 00292 for (tbl = rpmsigTbl; tbl->signum >= 0; tbl++) { 00293 if (tbl->signum != signum) 00294 continue; 00295 00296 (void) sigaddset(&rpmsqCaught, signum); 00297 00298 switch (signum) { 00299 case SIGCHLD: 00300 while (1) { 00301 rpmsq sq; 00302 int status = 0; 00303 pid_t reaped = waitpid(0, &status, WNOHANG); 00304 00305 /* XXX errno set to ECHILD/EINVAL/EINTR. */ 00306 if (reaped <= 0) 00307 /*@innerbreak@*/ break; 00308 00309 /* XXX insque(3)/remque(3) are dequeue, not ring. */ 00310 for (sq = rpmsqQueue->q_forw; 00311 sq != NULL && sq != rpmsqQueue; 00312 sq = sq->q_forw) 00313 { 00314 int ret; 00315 00316 if (sq->child != reaped) 00317 /*@innercontinue@*/ continue; 00318 sq->reaped = reaped; 00319 sq->status = status; 00320 00321 ret = close(sq->pipes[1]); sq->pipes[1] = -1; 00322 00323 /*@innerbreak@*/ break; 00324 } 00325 } 00326 /*@switchbreak@*/ break; 00327 default: 00328 /*@switchbreak@*/ break; 00329 } 00330 break; 00331 } 00332 errno = save; 00333 } 00334 00335 int rpmsqEnable(int signum, /*@null@*/ rpmsqAction_t handler) 00336 /*@globals rpmsigTbl @*/ 00337 /*@modifies rpmsigTbl @*/ 00338 { 00339 int tblsignum = (signum >= 0 ? signum : -signum); 00340 struct sigaction sa; 00341 rpmsig tbl; 00342 int ret = -1; 00343 00344 (void) DO_LOCK (); 00345 if (rpmsqQueue->id == NULL) 00346 rpmsqQueue->id = ME(); 00347 for (tbl = rpmsigTbl; tbl->signum >= 0; tbl++) { 00348 if (tblsignum != tbl->signum) 00349 continue; 00350 00351 if (signum >= 0) { /* Enable. */ 00352 if (ADD_REF(tbl) <= 0) { 00353 (void) sigdelset(&rpmsqCaught, tbl->signum); 00354 00355 /* XXX Don't set a signal handler if already SIG_IGN */ 00356 (void) sigaction(tbl->signum, NULL, &tbl->oact); 00357 if (tbl->oact.sa_handler == SIG_IGN) 00358 continue; 00359 00360 (void) sigemptyset (&sa.sa_mask); 00361 sa.sa_flags = SA_SIGINFO; 00362 #if defined(__LCLINT__) /* XXX glibc has union to track handler prototype. */ 00363 sa.sa_handler = (handler != NULL ? handler : tbl->handler); 00364 #else 00365 sa.sa_sigaction = (handler != NULL ? handler : tbl->handler); 00366 #endif 00367 if (sigaction(tbl->signum, &sa, &tbl->oact) < 0) { 00368 SUB_REF(tbl); 00369 break; 00370 } 00371 tbl->active = 1; /* XXX just in case */ 00372 if (handler != NULL) 00373 tbl->handler = handler; 00374 } 00375 } else { /* Disable. */ 00376 if (SUB_REF(tbl) <= 0) { 00377 if (sigaction(tbl->signum, &tbl->oact, NULL) < 0) 00378 break; 00379 tbl->active = 0; /* XXX just in case */ 00380 tbl->handler = (handler != NULL ? handler : rpmsqAction); 00381 } 00382 } 00383 ret = tbl->active; 00384 break; 00385 } 00386 (void) DO_UNLOCK (); 00387 return ret; 00388 } 00389 00390 pid_t rpmsqFork(rpmsq sq) 00391 { 00392 pid_t pid; 00393 int xx; 00394 00395 if (sq->reaper) { 00396 xx = rpmsqInsert(sq, NULL); 00397 #ifdef _RPMSQ_DEBUG 00398 if (_rpmsq_debug) 00399 fprintf(stderr, " Enable(%p): %p\n", ME(), sq); 00400 #endif 00401 xx = rpmsqEnable(SIGCHLD, NULL); 00402 } 00403 00404 xx = pipe(sq->pipes); 00405 00406 xx = sighold(SIGCHLD); 00407 00408 pid = fork(); 00409 if (pid < (pid_t) 0) { /* fork failed. */ 00410 /*@-bounds@*/ 00411 xx = close(sq->pipes[0]); 00412 xx = close(sq->pipes[1]); 00413 sq->pipes[0] = sq->pipes[1] = -1; 00414 /*@=bounds@*/ 00415 goto out; 00416 } else if (pid == (pid_t) 0) { /* Child. */ 00417 int yy; 00418 00419 /* Block to permit parent time to wait. */ 00420 /*@-bounds@*/ 00421 xx = close(sq->pipes[1]); 00422 if (sq->reaper) 00423 xx = read(sq->pipes[0], &yy, sizeof(yy)); 00424 xx = close(sq->pipes[0]); 00425 sq->pipes[0] = sq->pipes[1] = -1; 00426 /*@=bounds@*/ 00427 00428 #ifdef _RPMSQ_DEBUG 00429 if (_rpmsq_debug) 00430 fprintf(stderr, " Child(%p): %p child %d\n", ME(), sq, getpid()); 00431 #endif 00432 00433 } else { /* Parent. */ 00434 00435 sq->child = pid; 00436 00437 #ifdef _RPMSQ_DEBUG 00438 if (_rpmsq_debug) 00439 fprintf(stderr, " Parent(%p): %p child %d\n", ME(), sq, sq->child); 00440 #endif 00441 00442 } 00443 00444 out: 00445 xx = sigrelse(SIGCHLD); 00446 return sq->child; 00447 } 00448 00455 static int rpmsqWaitUnregister(rpmsq sq) 00456 /*@globals fileSystem, internalState @*/ 00457 /*@modifies sq, fileSystem, internalState @*/ 00458 { 00459 int nothreads = 0; 00460 int ret = 0; 00461 int xx; 00462 00463 assert(sq->reaper); 00464 /* Protect sq->reaped from handler changes. */ 00465 ret = sighold(SIGCHLD); 00466 00467 /* Start the child, linux often runs child before parent. */ 00468 /*@-bounds@*/ 00469 if (sq->pipes[0] >= 0) 00470 xx = close(sq->pipes[0]); 00471 if (sq->pipes[1] >= 0) 00472 xx = close(sq->pipes[1]); 00473 /*@=bounds@*/ 00474 00475 /* Re-initialize the pipe to receive SIGCHLD receipt confirmation. */ 00476 xx = pipe(sq->pipes); 00477 00478 /* Put a stopwatch on the time spent waiting to measure performance gain. */ 00479 (void) rpmswEnter(&sq->op, -1); 00480 00481 /* Wait for handler to receive SIGCHLD. */ 00482 /*@-infloops@*/ 00483 while (ret == 0 && sq->reaped != sq->child) { 00484 if (nothreads) 00485 /* Note that sigpause re-enables SIGCHLD. */ 00486 ret = sigpause(SIGCHLD); 00487 else { 00488 xx = sigrelse(SIGCHLD); 00489 00490 /* Signal handler does close(sq->pipes[1]) triggering 0b EOF read */ 00491 if (read(sq->pipes[0], &xx, sizeof(xx)) == 0) { 00492 xx = close(sq->pipes[0]); sq->pipes[0] = -1; 00493 ret = 1; 00494 } 00495 00496 xx = sighold(SIGCHLD); 00497 } 00498 } 00499 /*@=infloops@*/ 00500 00501 /* Accumulate stopwatch time spent waiting, potential performance gain. */ 00502 sq->ms_scriptlets += rpmswExit(&sq->op, -1)/1000; 00503 00504 xx = sigrelse(SIGCHLD); 00505 00506 #ifdef _RPMSQ_DEBUG 00507 if (_rpmsq_debug) 00508 fprintf(stderr, " Wake(%p): %p child %d reaper %d ret %d\n", ME(), sq, sq->child, sq->reaper, ret); 00509 #endif 00510 00511 /* Remove processed SIGCHLD item from queue. */ 00512 xx = rpmsqRemove(sq); 00513 00514 /* Disable SIGCHLD handler on refcount == 0. */ 00515 xx = rpmsqEnable(-SIGCHLD, NULL); 00516 #ifdef _RPMSQ_DEBUG 00517 if (_rpmsq_debug) 00518 fprintf(stderr, " Disable(%p): %p\n", ME(), sq); 00519 #endif 00520 00521 return ret; 00522 } 00523 00524 pid_t rpmsqWait(rpmsq sq) 00525 { 00526 00527 #ifdef _RPMSQ_DEBUG 00528 if (_rpmsq_debug) 00529 fprintf(stderr, " Wait(%p): %p child %d reaper %d\n", ME(), sq, sq->child, sq->reaper); 00530 #endif 00531 00532 if (sq->reaper) { 00533 (void) rpmsqWaitUnregister(sq); 00534 } else { 00535 pid_t reaped; 00536 int status; 00537 do { 00538 reaped = waitpid(sq->child, &status, 0); 00539 } while (reaped >= 0 && reaped != sq->child); 00540 sq->reaped = reaped; 00541 sq->status = status; 00542 #ifdef _RPMSQ_DEBUG 00543 if (_rpmsq_debug) 00544 fprintf(stderr, " Waitpid(%p): %p child %d reaped %d\n", ME(), sq, sq->child, sq->reaped); 00545 #endif 00546 } 00547 00548 #ifdef _RPMSQ_DEBUG 00549 if (_rpmsq_debug) 00550 fprintf(stderr, " Fini(%p): %p child %d status 0x%x\n", ME(), sq, sq->child, sq->status); 00551 #endif 00552 00553 return sq->reaped; 00554 } 00555 00556 void * rpmsqThread(void * (*start) (void * arg), void * arg) 00557 { 00558 pthread_t pth; 00559 int ret; 00560 00561 ret = pthread_create(&pth, NULL, start, arg); 00562 return (ret == 0 ? (void *)pth : NULL); 00563 } 00564 00565 int rpmsqJoin(void * thread) 00566 { 00567 pthread_t pth = (pthread_t) thread; 00568 if (thread == NULL) 00569 return EINVAL; 00570 return pthread_join(pth, NULL); 00571 } 00572 00573 int rpmsqThreadEqual(void * thread) 00574 { 00575 pthread_t t1 = (pthread_t) thread; 00576 pthread_t t2 = pthread_self(); 00577 return pthread_equal(t1, t2); 00578 } 00579 00583 static void 00584 sigchld_cancel (void *arg) 00585 /*@globals rpmsigTbl, fileSystem, internalState @*/ 00586 /*@modifies rpmsigTbl, fileSystem, internalState @*/ 00587 { 00588 pid_t child = *(pid_t *) arg; 00589 pid_t result; 00590 00591 (void) kill(child, SIGKILL); 00592 00593 do { 00594 result = waitpid(child, NULL, 0); 00595 } while (result == (pid_t)-1 && errno == EINTR); 00596 00597 (void) DO_LOCK (); 00598 if (SUB_REF (rpmsigTbl_sigchld) == 0) { 00599 (void) rpmsqEnable(-SIGQUIT, NULL); 00600 (void) rpmsqEnable(-SIGINT, NULL); 00601 } 00602 (void) DO_UNLOCK (); 00603 } 00604 00608 int 00609 rpmsqExecve (const char ** argv) 00610 /*@globals rpmsigTbl @*/ 00611 /*@modifies rpmsigTbl @*/ 00612 { 00613 int oldtype; 00614 int status = -1; 00615 pid_t pid = 0; 00616 pid_t result; 00617 sigset_t newMask, oldMask; 00618 rpmsq sq = memset(alloca(sizeof(*sq)), 0, sizeof(*sq)); 00619 00620 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 00621 INIT_LOCK (); 00622 #endif 00623 00624 (void) DO_LOCK (); 00625 if (ADD_REF (rpmsigTbl_sigchld) == 0) { 00626 if (rpmsqEnable(SIGINT, NULL) < 0) { 00627 SUB_REF (rpmsigTbl_sigchld); 00628 goto out; 00629 } 00630 if (rpmsqEnable(SIGQUIT, NULL) < 0) { 00631 SUB_REF (rpmsigTbl_sigchld); 00632 goto out_restore_sigint; 00633 } 00634 } 00635 (void) DO_UNLOCK (); 00636 00637 (void) sigemptyset (&newMask); 00638 (void) sigaddset (&newMask, SIGCHLD); 00639 if (sigprocmask (SIG_BLOCK, &newMask, &oldMask) < 0) { 00640 (void) DO_LOCK (); 00641 if (SUB_REF (rpmsigTbl_sigchld) == 0) 00642 goto out_restore_sigquit_and_sigint; 00643 goto out; 00644 } 00645 00646 CLEANUP_HANDLER(sigchld_cancel, &pid, &oldtype); 00647 00648 pid = fork (); 00649 if (pid < (pid_t) 0) { /* fork failed. */ 00650 goto out; 00651 } else if (pid == (pid_t) 0) { /* Child. */ 00652 00653 /* Restore the signals. */ 00654 (void) sigaction (SIGINT, &rpmsigTbl_sigint->oact, NULL); 00655 (void) sigaction (SIGQUIT, &rpmsigTbl_sigquit->oact, NULL); 00656 (void) sigprocmask (SIG_SETMASK, &oldMask, NULL); 00657 00658 /* Reset rpmsigTbl lock and refcnt. */ 00659 INIT_LOCK (); 00660 00661 (void) execve (argv[0], (char *const *) argv, environ); 00662 _exit (127); 00663 } else { /* Parent. */ 00664 do { 00665 result = waitpid(pid, &status, 0); 00666 } while (result == (pid_t)-1 && errno == EINTR); 00667 if (result != pid) 00668 status = -1; 00669 } 00670 00671 CLEANUP_RESET(0, oldtype); 00672 00673 (void) DO_LOCK (); 00674 if ((SUB_REF (rpmsigTbl_sigchld) == 0 && 00675 (rpmsqEnable(-SIGINT, NULL) < 0 || rpmsqEnable (-SIGQUIT, NULL) < 0)) 00676 || sigprocmask (SIG_SETMASK, &oldMask, NULL) != 0) 00677 { 00678 status = -1; 00679 } 00680 goto out; 00681 00682 out_restore_sigquit_and_sigint: 00683 (void) rpmsqEnable(-SIGQUIT, NULL); 00684 out_restore_sigint: 00685 (void) rpmsqEnable(-SIGINT, NULL); 00686 out: 00687 (void) DO_UNLOCK (); 00688 return status; 00689 }