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