rpm 5.3.12
|
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 #if !defined(__QNX__) 00122 # include <sys/signal.h> 00123 #endif 00124 #include <sys/wait.h> 00125 #include <search.h> 00126 00127 /* portability fallback for sighold(3) */ 00128 #if !defined(HAVE_SIGHOLD) && defined(HAVE_SIGPROCMASK) && defined(HAVE_SIGADDSET) 00129 static int __RPM_sighold(int sig) 00130 { 00131 sigset_t set; 00132 if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) 00133 return -1; 00134 if (sigaddset(&set, sig) < 0) 00135 return -1; 00136 return sigprocmask(SIG_SETMASK, &set, NULL); 00137 } 00138 #define sighold(sig) __RPM_sighold(sig) 00139 #endif 00140 00141 /* portability fallback for sigrelse(3) */ 00142 #if !defined(HAVE_SIGRELSE) && defined(HAVE_SIGPROCMASK) && defined(HAVE_SIGDELSET) 00143 static int __RPM_sigrelse(int sig) 00144 { 00145 sigset_t set; 00146 if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) 00147 return -1; 00148 if (sigdelset(&set, sig) < 0) 00149 return -1; 00150 return sigprocmask(SIG_SETMASK, &set, NULL); 00151 } 00152 #define sigrelse(sig) __RPM_sigrelse(sig) 00153 #endif 00154 00155 /* portability fallback for sigpause(3) */ 00156 #if !defined(HAVE_SIGPAUSE) && defined(HAVE_SIGEMPTYSET) && defined(HAVE_SIGADDSET) && defined(HAVE_SIGSUSPEND) 00157 static int __RPM_sigpause(int sig) 00158 { 00159 sigset_t set; 00160 if (sigemptyset(&set) < 0) 00161 return -1; 00162 if (sigaddset(&set, sig) < 0) 00163 return -1; 00164 return sigsuspend(&set); 00165 } 00166 #define sigpause(sig) __RPM_sigpause(sig) 00167 #endif 00168 00169 /* portability fallback for insque(3)/remque(3) */ 00170 #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__QNX__) 00171 struct qelem { 00172 struct qelem *q_forw; 00173 struct qelem *q_back; 00174 }; 00175 00176 static void __insque(struct qelem * elem, struct qelem * pred) 00177 { 00178 elem -> q_forw = pred -> q_forw; 00179 pred -> q_forw -> q_back = elem; 00180 elem -> q_back = pred; 00181 pred -> q_forw = elem; 00182 } 00183 #define insque(_e, _p) __insque((_e), (_p)) 00184 00185 static void __remque(struct qelem * elem) 00186 { 00187 elem -> q_forw -> q_back = elem -> q_back; 00188 elem -> q_back -> q_forw = elem -> q_forw; 00189 } 00190 #define remque(_e) __remque(_e) 00191 #endif 00192 00193 #if defined(WITH_PTHREADS) 00194 00195 # if !defined(__QNX__) 00196 /* XXX suggested in bugzilla #159024 */ 00197 # if PTHREAD_MUTEX_DEFAULT != PTHREAD_MUTEX_NORMAL 00198 # error RPM expects PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL 00199 # endif 00200 # endif 00201 00202 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 00203 /*@unchecked@*/ 00204 static pthread_mutex_t rpmsigTbl_lock = PTHREAD_MUTEX_INITIALIZER; 00205 #else 00206 /*@unchecked@*/ 00207 /*@-type@*/ 00208 static pthread_mutex_t rpmsigTbl_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; 00209 /*@=type@*/ 00210 #endif 00211 00212 /*@-macromatchname@*/ 00213 #define DO_LOCK() /*@-retvalint@*/pthread_mutex_lock(&rpmsigTbl_lock)/*@=retvalint@*/; 00214 #define DO_UNLOCK() pthread_mutex_unlock(&rpmsigTbl_lock); 00215 #define INIT_LOCK() \ 00216 { pthread_mutexattr_t attr; \ 00217 (void) pthread_mutexattr_init(&attr); \ 00218 (void) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \ 00219 (void) pthread_mutex_init (&rpmsigTbl_lock, &attr); \ 00220 (void) pthread_mutexattr_destroy(&attr); \ 00221 rpmsigTbl_sigchld->active = 0; \ 00222 } 00223 #define ADD_REF(__tbl) (__tbl)->active++ 00224 #define SUB_REF(__tbl) --(__tbl)->active 00225 #define CLEANUP_HANDLER(__handler, __arg, __oldtypeptr) \ 00226 (void) pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, (__oldtypeptr));\ 00227 pthread_cleanup_push((__handler), (__arg)); 00228 #define CLEANUP_RESET(__execute, __oldtype) \ 00229 pthread_cleanup_pop(__execute); \ 00230 (void) pthread_setcanceltype ((__oldtype), &(__oldtype)); 00231 00232 #define SAME_THREAD(_a, _b) pthread_equal(((pthread_t)_a), ((pthread_t)_b)) 00233 /*@-macromatchname@*/ 00234 00235 #define ME() __tid2vp(pthread_self()) 00236 /*@shared@*/ 00237 static void *__tid2vp(pthread_t tid) 00238 /*@*/ 00239 { 00240 union { pthread_t tid; /*@shared@*/ void *vp; } u; 00241 u.tid = tid; 00242 return u.vp; 00243 } 00244 00245 #else 00246 00247 /*@-macromatchname@*/ 00248 #define DO_LOCK() (0) 00249 #define DO_UNLOCK() (0) 00250 #define INIT_LOCK() 00251 #define ADD_REF(__tbl) /*@-noeffect@*/ (0) /*@=noeffect@*/ 00252 #define SUB_REF(__tbl) /*@-noeffect@*/ (0) /*@=noeffect@*/ 00253 #define CLEANUP_HANDLER(__handler, __arg, __oldtypeptr) 00254 #define CLEANUP_RESET(__execute, __oldtype) 00255 00256 #define SAME_THREAD(_a, _b) (42) 00257 /*@=macromatchname@*/ 00258 00259 #define ME() __pid2vp(getpid()) 00260 /*@shared@*/ 00261 static void *__pid2vp(pid_t pid) 00262 /*@*/ 00263 { 00264 union { pid_t pid; /*@shared@*/ void *vp; } u; 00265 u.pid = pid; 00266 return u.vp; 00267 } 00268 00269 #endif /* WITH_PTHREADS */ 00270 00271 #define _RPMSQ_INTERNAL 00272 #include <rpmsq.h> 00273 00274 #include "debug.h" 00275 00276 #define _RPMSQ_DEBUG 0 00277 /*@unchecked@*/ 00278 int _rpmsq_debug = _RPMSQ_DEBUG; 00279 00280 /* XXX __OpenBSD__ insque(3) needs rock->q_forw initialized. */ 00281 /*@unchecked@*/ 00282 /*@-fullinitblock @*/ 00283 static struct rpmsqElem rpmsqRock = { .q_forw = &rpmsqRock }; 00284 /*@=fullinitblock @*/ 00285 00286 /*@-compmempass@*/ 00287 /*@unchecked@*/ 00288 rpmsq rpmsqQueue = &rpmsqRock; 00289 /*@=compmempass@*/ 00290 00291 int rpmsqInsert(void * elem, void * prev) 00292 { 00293 rpmsq sq = (rpmsq) elem; 00294 int ret = -1; 00295 00296 if (sq != NULL) { 00297 #ifdef _RPMSQ_DEBUG 00298 if (_rpmsq_debug) 00299 fprintf(stderr, " Insert(%p): %p\n", ME(), sq); 00300 #endif 00301 ret = sighold(SIGCHLD); 00302 if (ret == 0) { 00303 sq->child = 0; 00304 sq->reaped = 0; 00305 sq->status = 0; 00306 /* ==> Set to 1 to catch SIGCHLD, set to 0 to use waitpid(2). */ 00307 sq->reaper = 1; 00308 sq->pipes[0] = sq->pipes[1] = -1; 00309 00310 sq->id = ME(); 00311 /*@-noeffect@*/ 00312 insque(elem, (prev != NULL ? prev : rpmsqQueue)); 00313 /*@=noeffect@*/ 00314 ret = sigrelse(SIGCHLD); 00315 } 00316 } 00317 return ret; 00318 } 00319 00320 int rpmsqRemove(void * elem) 00321 { 00322 rpmsq sq = (rpmsq) elem; 00323 int ret = -1; 00324 00325 if (elem != NULL) { 00326 00327 #ifdef _RPMSQ_DEBUG 00328 if (_rpmsq_debug) 00329 fprintf(stderr, " Remove(%p): %p\n", ME(), sq); 00330 #endif 00331 ret = sighold (SIGCHLD); 00332 if (ret == 0) { 00333 /*@-noeffect@*/ 00334 remque(elem); 00335 /*@=noeffect@*/ 00336 sq->id = NULL; 00337 if (sq->pipes[1] > 0) ret = close(sq->pipes[1]); 00338 if (sq->pipes[0] > 0) ret = close(sq->pipes[0]); 00339 sq->pipes[0] = sq->pipes[1] = -1; 00340 #ifdef NOTYET /* rpmpsmWait debugging message needs */ 00341 sq->status = 0; 00342 sq->reaped = 0; 00343 sq->child = 0; 00344 #endif 00345 ret = sigrelse(SIGCHLD); 00346 } 00347 } 00348 return ret; 00349 } 00350 00351 /*@unchecked@*/ 00352 sigset_t rpmsqCaught; 00353 00354 /*@unchecked@*/ 00355 /*@-fullinitblock@*/ 00356 static struct rpmsig_s { 00357 int signum; 00358 void (*handler) (int signum, void * info, void * context); 00359 int active; 00360 struct sigaction oact; 00361 } rpmsigTbl[] = { 00362 { SIGINT, rpmsqAction }, 00363 #define rpmsigTbl_sigint (&rpmsigTbl[0]) 00364 { SIGQUIT, rpmsqAction }, 00365 #define rpmsigTbl_sigquit (&rpmsigTbl[1]) 00366 { SIGCHLD, rpmsqAction }, 00367 #define rpmsigTbl_sigchld (&rpmsigTbl[2]) 00368 { SIGHUP, rpmsqAction }, 00369 #define rpmsigTbl_sighup (&rpmsigTbl[3]) /* XXX unused */ 00370 { SIGTERM, rpmsqAction }, 00371 #define rpmsigTbl_sigterm (&rpmsigTbl[4]) /* XXX unused */ 00372 { SIGPIPE, rpmsqAction }, 00373 #define rpmsigTbl_sigpipe (&rpmsigTbl[5]) /* XXX unused */ 00374 00375 #ifdef NOTYET /* XXX todo++ */ 00376 #if defined(SIGXCPU) 00377 { SIGXCPU, rpmsqAction }, 00378 #define rpmsigTbl_sigxcpu (&rpmsigTbl[6]) /* XXX unused */ 00379 #endif 00380 #if defined(SIGXFSZ) 00381 { SIGXFSZ, rpmsqAction }, 00382 #define rpmsigTbl_sigxfsz (&rpmsigTbl[7]) /* XXX unused */ 00383 #endif 00384 #endif 00385 00386 { -1, NULL }, 00387 }; 00388 /*@=fullinitblock@*/ 00389 00390 void rpmsqAction(int signum, /*@unused@*/ void * info, 00391 /*@unused@*/ void * context) 00392 { 00393 int save = errno; 00394 rpmsig tbl; 00395 00396 for (tbl = rpmsigTbl; tbl->signum >= 0; tbl++) { 00397 if (tbl->signum != signum) 00398 continue; 00399 00400 (void) sigaddset(&rpmsqCaught, signum); 00401 00402 switch (signum) { 00403 case SIGCHLD: 00404 while (1) { 00405 rpmsq sq; 00406 int status = 0; 00407 pid_t reaped = waitpid(0, &status, WNOHANG); 00408 00409 /* XXX errno set to ECHILD/EINVAL/EINTR. */ 00410 if (reaped <= 0) 00411 /*@innerbreak@*/ break; 00412 00413 /* XXX insque(3)/remque(3) are dequeue, not ring. */ 00414 for (sq = rpmsqQueue->q_forw; 00415 sq != NULL && sq != rpmsqQueue; 00416 sq = sq->q_forw) 00417 { 00418 int ret; 00419 00420 if (sq->child != reaped) 00421 /*@innercontinue@*/ continue; 00422 sq->reaped = reaped; 00423 sq->status = status; 00424 00425 ret = close(sq->pipes[1]); sq->pipes[1] = -1; 00426 00427 /*@innerbreak@*/ break; 00428 } 00429 } 00430 /*@switchbreak@*/ break; 00431 default: 00432 /*@switchbreak@*/ break; 00433 } 00434 break; 00435 } 00436 errno = save; 00437 } 00438 00439 int rpmsqEnable(int signum, /*@null@*/ rpmsqAction_t handler) 00440 /*@globals rpmsigTbl @*/ 00441 /*@modifies rpmsigTbl @*/ 00442 { 00443 int tblsignum = (signum >= 0 ? signum : -signum); 00444 struct sigaction sa; 00445 rpmsig tbl; 00446 int ret = -1; 00447 int xx; 00448 00449 xx = DO_LOCK (); 00450 if (rpmsqQueue->id == NULL) 00451 rpmsqQueue->id = ME(); 00452 for (tbl = rpmsigTbl; tbl->signum >= 0; tbl++) { 00453 if (tblsignum != tbl->signum) 00454 continue; 00455 00456 if (signum >= 0) { /* Enable. */ 00457 if (ADD_REF(tbl) <= 0) { 00458 (void) sigdelset(&rpmsqCaught, tbl->signum); 00459 00460 /* XXX Don't set a signal handler if already SIG_IGN */ 00461 (void) sigaction(tbl->signum, NULL, &tbl->oact); 00462 if (tbl->oact.sa_handler == SIG_IGN) 00463 continue; 00464 00465 (void) sigemptyset (&sa.sa_mask); 00466 sa.sa_flags = SA_SIGINFO; 00467 #if defined(__LCLINT__) /* XXX glibc has union to track handler prototype. */ 00468 sa.sa_handler = (handler != NULL ? handler : tbl->handler); 00469 #else 00470 sa.sa_sigaction = (void *) (handler != NULL ? handler : tbl->handler); 00471 #endif 00472 if (sigaction(tbl->signum, &sa, &tbl->oact) < 0) { 00473 xx = SUB_REF(tbl); 00474 break; 00475 } 00476 tbl->active = 1; /* XXX just in case */ 00477 if (handler != NULL) 00478 tbl->handler = handler; 00479 } 00480 } else { /* Disable. */ 00481 if (SUB_REF(tbl) <= 0) { 00482 if (sigaction(tbl->signum, &tbl->oact, NULL) < 0) 00483 break; 00484 tbl->active = 0; /* XXX just in case */ 00485 tbl->handler = (handler != NULL ? handler : rpmsqAction); 00486 } 00487 } 00488 ret = tbl->active; 00489 break; 00490 } 00491 xx = DO_UNLOCK (); 00492 return ret; 00493 } 00494 00495 pid_t rpmsqFork(rpmsq sq) 00496 { 00497 pid_t pid; 00498 int xx; 00499 00500 if (sq->reaper) { 00501 xx = rpmsqInsert(sq, NULL); 00502 #ifdef _RPMSQ_DEBUG 00503 if (_rpmsq_debug) 00504 fprintf(stderr, " Enable(%p): %p\n", ME(), sq); 00505 #endif 00506 xx = rpmsqEnable(SIGCHLD, NULL); 00507 } 00508 00509 xx = pipe(sq->pipes); 00510 00511 xx = sighold(SIGCHLD); 00512 00513 pid = fork(); 00514 if (pid < (pid_t) 0) { /* fork failed. */ 00515 sq->child = (pid_t)-1; 00516 xx = close(sq->pipes[0]); 00517 xx = close(sq->pipes[1]); 00518 sq->pipes[0] = sq->pipes[1] = -1; 00519 goto out; 00520 } else if (pid == (pid_t) 0) { /* Child. */ 00521 int yy; 00522 00523 /* Block to permit parent time to wait. */ 00524 xx = close(sq->pipes[1]); 00525 if (sq->reaper) 00526 xx = (int)read(sq->pipes[0], &yy, sizeof(yy)); 00527 xx = close(sq->pipes[0]); 00528 sq->pipes[0] = sq->pipes[1] = -1; 00529 00530 #ifdef _RPMSQ_DEBUG 00531 if (_rpmsq_debug) 00532 fprintf(stderr, " Child(%p): %p child %d\n", ME(), sq, (int)getpid()); 00533 #endif 00534 00535 } else { /* Parent. */ 00536 00537 sq->child = pid; 00538 00539 #ifdef _RPMSQ_DEBUG 00540 if (_rpmsq_debug) 00541 fprintf(stderr, " Parent(%p): %p child %d\n", ME(), sq, (int)sq->child); 00542 #endif 00543 00544 } 00545 00546 out: 00547 xx = sigrelse(SIGCHLD); 00548 return sq->child; 00549 } 00550 00557 static int rpmsqWaitUnregister(rpmsq sq) 00558 /*@globals fileSystem, internalState @*/ 00559 /*@modifies sq, fileSystem, internalState @*/ 00560 { 00561 int nothreads = 0; 00562 int ret = 0; 00563 int xx; 00564 00565 assert(sq->reaper); 00566 /* Protect sq->reaped from handler changes. */ 00567 ret = sighold(SIGCHLD); 00568 00569 /* Start the child, linux often runs child before parent. */ 00570 if (sq->pipes[0] >= 0) 00571 xx = close(sq->pipes[0]); 00572 if (sq->pipes[1] >= 0) 00573 xx = close(sq->pipes[1]); 00574 00575 /* Re-initialize the pipe to receive SIGCHLD receipt confirmation. */ 00576 xx = pipe(sq->pipes); 00577 00578 /* Put a stopwatch on the time spent waiting to measure performance gain. */ 00579 (void) rpmswEnter(&sq->op, -1); 00580 00581 /* Wait for handler to receive SIGCHLD. */ 00582 /*@-infloops@*/ 00583 while (ret == 0 && sq->reaped != sq->child) { 00584 if (nothreads) 00585 /* Note that sigpause re-enables SIGCHLD. */ 00586 ret = sigpause(SIGCHLD); 00587 else { 00588 xx = sigrelse(SIGCHLD); 00589 00590 /* Signal handler does close(sq->pipes[1]) triggering 0b EOF read */ 00591 if (read(sq->pipes[0], &xx, sizeof(xx)) == 0) { 00592 xx = close(sq->pipes[0]); sq->pipes[0] = -1; 00593 ret = 1; 00594 } 00595 00596 xx = sighold(SIGCHLD); 00597 } 00598 } 00599 /*@=infloops@*/ 00600 00601 /* Accumulate stopwatch time spent waiting, potential performance gain. */ 00602 sq->ms_scriptlets += rpmswExit(&sq->op, -1)/1000; 00603 00604 xx = sigrelse(SIGCHLD); 00605 00606 #ifdef _RPMSQ_DEBUG 00607 if (_rpmsq_debug) 00608 fprintf(stderr, " Wake(%p): %p child %d reaper %d ret %d\n", ME(), sq, (int)sq->child, sq->reaper, ret); 00609 #endif 00610 00611 /* Remove processed SIGCHLD item from queue. */ 00612 xx = rpmsqRemove(sq); 00613 00614 /* Disable SIGCHLD handler on refcount == 0. */ 00615 xx = rpmsqEnable(-SIGCHLD, NULL); 00616 #ifdef _RPMSQ_DEBUG 00617 if (_rpmsq_debug) 00618 fprintf(stderr, " Disable(%p): %p\n", ME(), sq); 00619 #endif 00620 00621 return ret; 00622 } 00623 00624 pid_t rpmsqWait(rpmsq sq) 00625 { 00626 00627 #ifdef _RPMSQ_DEBUG 00628 if (_rpmsq_debug) 00629 fprintf(stderr, " Wait(%p): %p child %d reaper %d\n", ME(), sq, (int)sq->child, sq->reaper); 00630 #endif 00631 00632 if (sq->reaper) { 00633 (void) rpmsqWaitUnregister(sq); 00634 } else { 00635 pid_t reaped; 00636 int status; 00637 do { 00638 reaped = waitpid(sq->child, &status, 0); 00639 } while (reaped >= 0 && reaped != sq->child); 00640 sq->reaped = reaped; 00641 sq->status = status; 00642 #ifdef _RPMSQ_DEBUG 00643 if (_rpmsq_debug) 00644 fprintf(stderr, " Waitpid(%p): %p child %d reaped %d\n", ME(), sq, (int)sq->child, (int)sq->reaped); 00645 #endif 00646 } 00647 00648 #ifdef _RPMSQ_DEBUG 00649 if (_rpmsq_debug) 00650 fprintf(stderr, " Fini(%p): %p child %d status 0x%x\n", ME(), sq, (int)sq->child, sq->status); 00651 #endif 00652 00653 return sq->reaped; 00654 } 00655 00656 void * rpmsqThread(void * (*start) (void * arg), void * arg) 00657 { 00658 #if defined(WITH_PTHREADS) 00659 pthread_t pth; 00660 int ret; 00661 00662 ret = pthread_create(&pth, NULL, start, arg); 00663 return (ret == 0 ? (void *)pth : NULL); 00664 #else 00665 (void) start; 00666 (void) arg; 00667 return NULL; 00668 #endif 00669 } 00670 00671 int rpmsqJoin(void * thread) 00672 { 00673 #if defined(WITH_PTHREADS) 00674 pthread_t pth = (pthread_t) thread; 00675 if (thread == NULL) 00676 return EINVAL; 00677 return pthread_join(pth, NULL); 00678 #else 00679 (void) thread; 00680 return EINVAL; 00681 #endif 00682 } 00683 00684 int rpmsqThreadEqual(void * thread) 00685 { 00686 #if defined(WITH_PTHREADS) 00687 pthread_t t1 = (pthread_t) thread; 00688 pthread_t t2 = pthread_self(); 00689 return pthread_equal(t1, t2); 00690 #else 00691 (void) thread; 00692 return 0; 00693 #endif 00694 } 00695 00699 #if defined(WITH_PTHREADS) 00700 static void 00701 sigchld_cancel (void *arg) 00702 /*@globals rpmsigTbl, fileSystem, internalState @*/ 00703 /*@modifies rpmsigTbl, fileSystem, internalState @*/ 00704 { 00705 pid_t child = *(pid_t *) arg; 00706 pid_t result; 00707 int xx; 00708 00709 xx = kill(child, SIGKILL); 00710 00711 do { 00712 result = waitpid(child, NULL, 0); 00713 } while (result == (pid_t)-1 && errno == EINTR); 00714 00715 xx = DO_LOCK (); 00716 if (SUB_REF (rpmsigTbl_sigchld) == 0) { 00717 xx = rpmsqEnable(-SIGQUIT, NULL); 00718 xx = rpmsqEnable(-SIGINT, NULL); 00719 } 00720 xx = DO_UNLOCK (); 00721 } 00722 #endif 00723 00727 int 00728 rpmsqExecve (const char ** argv) 00729 /*@globals rpmsigTbl @*/ 00730 /*@modifies rpmsigTbl @*/ 00731 { 00732 #if defined(WITH_PTHREADS) 00733 int oldtype; 00734 #endif 00735 int status = -1; 00736 pid_t pid = 0; 00737 pid_t result; 00738 sigset_t newMask, oldMask; 00739 rpmsq sq = memset(alloca(sizeof(*sq)), 0, sizeof(*sq)); 00740 int xx; 00741 00742 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP 00743 INIT_LOCK (); 00744 #endif 00745 00746 xx = DO_LOCK (); 00747 if (ADD_REF (rpmsigTbl_sigchld) == 0) { 00748 if (rpmsqEnable(SIGINT, NULL) < 0) { 00749 xx = SUB_REF (rpmsigTbl_sigchld); 00750 goto out; 00751 } 00752 if (rpmsqEnable(SIGQUIT, NULL) < 0) { 00753 xx = SUB_REF (rpmsigTbl_sigchld); 00754 goto out_restore_sigint; 00755 } 00756 } 00757 xx = DO_UNLOCK (); 00758 00759 (void) sigemptyset (&newMask); 00760 (void) sigaddset (&newMask, SIGCHLD); 00761 if (sigprocmask (SIG_BLOCK, &newMask, &oldMask) < 0) { 00762 xx = DO_LOCK (); 00763 if (SUB_REF (rpmsigTbl_sigchld) == 0) 00764 goto out_restore_sigquit_and_sigint; 00765 goto out; 00766 } 00767 00768 /*@-sysunrecog@*/ 00769 CLEANUP_HANDLER(sigchld_cancel, &pid, &oldtype); 00770 /*@=sysunrecog@*/ 00771 00772 pid = fork (); 00773 if (pid < (pid_t) 0) { /* fork failed. */ 00774 goto out; 00775 } else if (pid == (pid_t) 0) { /* Child. */ 00776 00777 /* Restore the signals. */ 00778 (void) sigaction (SIGINT, &rpmsigTbl_sigint->oact, NULL); 00779 (void) sigaction (SIGQUIT, &rpmsigTbl_sigquit->oact, NULL); 00780 (void) sigprocmask (SIG_SETMASK, &oldMask, NULL); 00781 00782 /* Reset rpmsigTbl lock and refcnt. */ 00783 INIT_LOCK (); 00784 00785 (void) execve (argv[0], (char *const *) argv, environ); 00786 _exit (127); 00787 } else { /* Parent. */ 00788 do { 00789 result = waitpid(pid, &status, 0); 00790 } while (result == (pid_t)-1 && errno == EINTR); 00791 if (result != pid) 00792 status = -1; 00793 } 00794 00795 CLEANUP_RESET(0, oldtype); 00796 00797 xx = DO_LOCK (); 00798 if ((SUB_REF (rpmsigTbl_sigchld) == 0 && 00799 (rpmsqEnable(-SIGINT, NULL) < 0 || rpmsqEnable (-SIGQUIT, NULL) < 0)) 00800 || sigprocmask (SIG_SETMASK, &oldMask, NULL) != 0) 00801 { 00802 status = -1; 00803 } 00804 goto out; 00805 00806 out_restore_sigquit_and_sigint: 00807 xx = rpmsqEnable(-SIGQUIT, NULL); 00808 out_restore_sigint: 00809 xx = rpmsqEnable(-SIGINT, NULL); 00810 out: 00811 xx = DO_UNLOCK (); 00812 return status; 00813 }