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 #if defined(HAVE_PTHREAD_H)
00126
00127 #include <pthread.h>
00128
00129
00130
00131 static pthread_mutex_t rpmsigTbl_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
00132
00133
00134 #define DO_LOCK() pthread_mutex_lock(&rpmsigTbl_lock);
00135 #define DO_UNLOCK() pthread_mutex_unlock(&rpmsigTbl_lock);
00136 #define INIT_LOCK() \
00137 { pthread_mutexattr_t attr; \
00138 (void) pthread_mutexattr_init(&attr); \
00139 (void) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
00140 (void) pthread_mutex_init (&rpmsigTbl_lock, &attr); \
00141 (void) pthread_mutexattr_destroy(&attr); \
00142 rpmsigTbl_sigchld->active = 0; \
00143 }
00144 #define ADD_REF(__tbl) (__tbl)->active++
00145 #define SUB_REF(__tbl) --(__tbl)->active
00146 #define CLEANUP_HANDLER(__handler, __arg, __oldtypeptr) \
00147 (void) pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, (__oldtypeptr));\
00148 pthread_cleanup_push((__handler), (__arg));
00149 #define CLEANUP_RESET(__execute, __oldtype) \
00150 (void) pthread_cleanup_pop(__execute); \
00151 (void) pthread_setcanceltype ((__oldtype), &(__oldtype));
00152
00153 #define SAME_THREAD(_a, _b) pthread_equal(((pthread_t)_a), ((pthread_t)_b))
00154
00155 #define ME() ((void *)pthread_self())
00156
00157 #else
00158
00159 #define DO_LOCK()
00160 #define DO_UNLOCK()
00161 #define INIT_LOCK()
00162 #define ADD_REF(__tbl) (0)
00163 #define SUB_REF(__tbl) (0)
00164 #define CLEANUP_HANDLER(__handler, __arg, __oldtypeptr)
00165 #define CLEANUP_RESET(__execute, __oldtype)
00166
00167 #define SAME_THREAD(_a, _b) (42)
00168
00169 #define ME() (((void *)getpid()))
00170
00171 #endif
00172
00173 #include <rpmsq.h>
00174
00175 #include "debug.h"
00176
00177 #define _RPMSQ_DEBUG 0
00178
00179 int _rpmsq_debug = _RPMSQ_DEBUG;
00180
00181
00182 static struct rpmsqElem rpmsqRock;
00183
00184
00185
00186 rpmsq rpmsqQueue = &rpmsqRock;
00187
00188
00189 int rpmsqInsert(void * elem, void * prev)
00190 {
00191 rpmsq sq = (rpmsq) elem;
00192 int ret = -1;
00193
00194 if (sq != NULL) {
00195 #ifdef _RPMSQ_DEBUG
00196 if (_rpmsq_debug)
00197 fprintf(stderr, " Insert(%p): %p\n", ME(), sq);
00198 #endif
00199 ret = sighold(SIGCHLD);
00200 if (ret == 0) {
00201 sq->child = 0;
00202 sq->reaped = 0;
00203 sq->status = 0;
00204 sq->reaper = 1;
00205
00206 sq->pipes[0] = sq->pipes[1] = -1;
00207
00208
00209 sq->id = ME();
00210 ret = pthread_mutex_init(&sq->mutex, NULL);
00211 ret = pthread_cond_init(&sq->cond, NULL);
00212 insque(elem, (prev != NULL ? prev : rpmsqQueue));
00213 ret = sigrelse(SIGCHLD);
00214 }
00215 }
00216 return ret;
00217 }
00218
00219 int rpmsqRemove(void * elem)
00220 {
00221 rpmsq sq = (rpmsq) elem;
00222 int ret = -1;
00223
00224 if (elem != NULL) {
00225
00226 #ifdef _RPMSQ_DEBUG
00227 if (_rpmsq_debug)
00228 fprintf(stderr, " Remove(%p): %p\n", ME(), sq);
00229 #endif
00230 ret = sighold (SIGCHLD);
00231 if (ret == 0) {
00232 remque(elem);
00233 ret = pthread_cond_destroy(&sq->cond);
00234 ret = pthread_mutex_destroy(&sq->mutex);
00235 sq->id = NULL;
00236
00237 if (sq->pipes[1]) ret = close(sq->pipes[1]);
00238 if (sq->pipes[0]) ret = close(sq->pipes[0]);
00239 sq->pipes[0] = sq->pipes[1] = -1;
00240
00241 #ifdef NOTYET
00242 sq->reaper = 1;
00243 sq->status = 0;
00244 sq->reaped = 0;
00245 sq->child = 0;
00246 #endif
00247 ret = sigrelse(SIGCHLD);
00248 }
00249 }
00250 return ret;
00251 }
00252
00253
00254 sigset_t rpmsqCaught;
00255
00256
00257
00258 static struct rpmsig_s {
00259 int signum;
00260 void (*handler) (int signum, void * info, void * context);
00261 int active;
00262 struct sigaction oact;
00263 } rpmsigTbl[] = {
00264 { SIGINT, rpmsqAction },
00265 #define rpmsigTbl_sigint (&rpmsigTbl[0])
00266 { SIGQUIT, rpmsqAction },
00267 #define rpmsigTbl_sigquit (&rpmsigTbl[1])
00268 { SIGCHLD, rpmsqAction },
00269 #define rpmsigTbl_sigchld (&rpmsigTbl[2])
00270 { SIGHUP, rpmsqAction },
00271 #define rpmsigTbl_sighup (&rpmsigTbl[3])
00272 { SIGTERM, rpmsqAction },
00273 #define rpmsigTbl_sigterm (&rpmsigTbl[4])
00274 { SIGPIPE, rpmsqAction },
00275 #define rpmsigTbl_sigpipe (&rpmsigTbl[5])
00276 { -1, NULL },
00277 };
00278
00279
00280 void rpmsqAction(int signum,
00281 void * info, void * context)
00282 {
00283 int save = errno;
00284 rpmsig tbl;
00285
00286 for (tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
00287 if (tbl->signum != signum)
00288 continue;
00289
00290 (void) sigaddset(&rpmsqCaught, signum);
00291
00292 switch (signum) {
00293 case SIGCHLD:
00294 while (1) {
00295 rpmsq sq;
00296 int status = 0;
00297 pid_t reaped = waitpid(0, &status, WNOHANG);
00298
00299
00300 if (reaped <= 0)
00301 break;
00302
00303
00304 for (sq = rpmsqQueue->q_forw;
00305 sq != NULL && sq != rpmsqQueue;
00306 sq = sq->q_forw)
00307 {
00308 if (sq->child != reaped)
00309 continue;
00310 sq->reaped = reaped;
00311 sq->status = status;
00312 (void) pthread_cond_signal(&sq->cond);
00313 break;
00314 }
00315 }
00316 break;
00317 default:
00318 break;
00319 }
00320 break;
00321 }
00322 errno = save;
00323 }
00324
00325 int rpmsqEnable(int signum, rpmsqAction_t handler)
00326
00327
00328 {
00329 int tblsignum = (signum >= 0 ? signum : -signum);
00330 struct sigaction sa;
00331 rpmsig tbl;
00332 int ret = -1;
00333
00334 (void) DO_LOCK ();
00335 if (rpmsqQueue->id == NULL)
00336 rpmsqQueue->id = ME();
00337 for (tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
00338 if (tblsignum != tbl->signum)
00339 continue;
00340
00341 if (signum >= 0) {
00342 if (ADD_REF(tbl) <= 0) {
00343 (void) sigdelset(&rpmsqCaught, tbl->signum);
00344
00345
00346 (void) sigaction(tbl->signum, NULL, &tbl->oact);
00347 if (tbl->oact.sa_handler == SIG_IGN)
00348 continue;
00349
00350 (void) sigemptyset (&sa.sa_mask);
00351 sa.sa_flags = SA_SIGINFO;
00352 #if defined(__LCLINT__)
00353 sa.sa_handler = (handler != NULL ? handler : tbl->handler);
00354 #else
00355 sa.sa_sigaction = (handler != NULL ? handler : tbl->handler);
00356 #endif
00357 if (sigaction(tbl->signum, &sa, &tbl->oact) < 0) {
00358 SUB_REF(tbl);
00359 break;
00360 }
00361 tbl->active = 1;
00362 if (handler != NULL)
00363 tbl->handler = handler;
00364 }
00365 } else {
00366 if (SUB_REF(tbl) <= 0) {
00367 if (sigaction(tbl->signum, &tbl->oact, NULL) < 0)
00368 break;
00369 tbl->active = 0;
00370 tbl->handler = (handler != NULL ? handler : rpmsqAction);
00371 }
00372 }
00373 ret = tbl->active;
00374 break;
00375 }
00376 (void) DO_UNLOCK ();
00377 return ret;
00378 }
00379
00380 pid_t rpmsqFork(rpmsq sq)
00381 {
00382 pid_t pid;
00383 int xx;
00384
00385 if (sq->reaper) {
00386 xx = rpmsqInsert(sq, NULL);
00387 #ifdef _RPMSQ_DEBUG
00388 if (_rpmsq_debug)
00389 fprintf(stderr, " Enable(%p): %p\n", ME(), sq);
00390 #endif
00391 xx = rpmsqEnable(SIGCHLD, NULL);
00392 }
00393
00394 xx = pipe(sq->pipes);
00395
00396 xx = sighold(SIGCHLD);
00397
00398 pid = fork();
00399 if (pid < (pid_t) 0) {
00400
00401 xx = close(sq->pipes[0]);
00402 xx = close(sq->pipes[1]);
00403 sq->pipes[0] = sq->pipes[1] = -1;
00404
00405 goto out;
00406 } else if (pid == (pid_t) 0) {
00407 int yy;
00408
00409
00410
00411 xx = close(sq->pipes[1]);
00412 xx = read(sq->pipes[0], &yy, sizeof(yy));
00413 xx = close(sq->pipes[0]);
00414 sq->pipes[0] = sq->pipes[1] = -1;
00415
00416
00417 #ifdef _RPMSQ_DEBUG
00418 if (_rpmsq_debug)
00419 fprintf(stderr, " Child(%p): %p child %d\n", ME(), sq, getpid());
00420 #endif
00421
00422 } else {
00423
00424 sq->child = pid;
00425
00426 #ifdef _RPMSQ_DEBUG
00427 if (_rpmsq_debug)
00428 fprintf(stderr, " Parent(%p): %p child %d\n", ME(), sq, sq->child);
00429 #endif
00430
00431 }
00432
00433 out:
00434 xx = sigrelse(SIGCHLD);
00435 return sq->child;
00436 }
00437
00444 static int rpmsqWaitUnregister(rpmsq sq)
00445
00446
00447 {
00448 int nothreads = 0;
00449 int ret = 0;
00450 int xx;
00451
00452
00453 ret = sighold(SIGCHLD);
00454
00455
00456 if (!nothreads)
00457 ret = pthread_mutex_lock(&sq->mutex);
00458
00459
00460
00461 if (sq->pipes[0] >= 0)
00462 xx = close(sq->pipes[0]);
00463 if (sq->pipes[1] >= 0)
00464 xx = close(sq->pipes[1]);
00465 sq->pipes[0] = sq->pipes[1] = -1;
00466
00467
00468
00469 (void) rpmswEnter(&sq->op, -1);
00470
00471
00472
00473 while (ret == 0 && sq->reaped != sq->child) {
00474 if (nothreads)
00475
00476 ret = sigpause(SIGCHLD);
00477 else {
00478 xx = sigrelse(SIGCHLD);
00479 ret = pthread_cond_wait(&sq->cond, &sq->mutex);
00480 xx = sighold(SIGCHLD);
00481 }
00482 }
00483
00484
00485
00486 sq->ms_scriptlets += rpmswExit(&sq->op, -1)/1000;
00487
00488
00489 if (!nothreads)
00490 xx = pthread_mutex_unlock(&sq->mutex);
00491 xx = sigrelse(SIGCHLD);
00492
00493 #ifdef _RPMSQ_DEBUG
00494 if (_rpmsq_debug)
00495 fprintf(stderr, " Wake(%p): %p child %d reaper %d ret %d\n", ME(), sq, sq->child, sq->reaper, ret);
00496 #endif
00497
00498
00499 xx = rpmsqRemove(sq);
00500
00501
00502 xx = rpmsqEnable(-SIGCHLD, NULL);
00503 #ifdef _RPMSQ_DEBUG
00504 if (_rpmsq_debug)
00505 fprintf(stderr, " Disable(%p): %p\n", ME(), sq);
00506 #endif
00507
00508 return ret;
00509 }
00510
00511 pid_t rpmsqWait(rpmsq sq)
00512 {
00513
00514 #ifdef _RPMSQ_DEBUG
00515 if (_rpmsq_debug)
00516 fprintf(stderr, " Wait(%p): %p child %d reaper %d\n", ME(), sq, sq->child, sq->reaper);
00517 #endif
00518
00519 if (sq->reaper) {
00520 (void) rpmsqWaitUnregister(sq);
00521 } else {
00522 pid_t reaped;
00523 int status;
00524 do {
00525 reaped = waitpid(sq->child, &status, 0);
00526 } while (reaped >= 0 && reaped != sq->child);
00527 sq->reaped = reaped;
00528 sq->status = status;
00529 #ifdef _RPMSQ_DEBUG
00530 if (_rpmsq_debug)
00531 fprintf(stderr, " Waitpid(%p): %p child %d reaped %d\n", ME(), sq, sq->child, sq->reaped);
00532 #endif
00533 }
00534
00535 #ifdef _RPMSQ_DEBUG
00536 if (_rpmsq_debug)
00537 fprintf(stderr, " Fini(%p): %p child %d status 0x%x\n", ME(), sq, sq->child, sq->status);
00538 #endif
00539
00540 return sq->reaped;
00541 }
00542
00543 void * rpmsqThread(void * (*start) (void * arg), void * arg)
00544 {
00545 pthread_t pth;
00546 int ret;
00547
00548 ret = pthread_create(&pth, NULL, start, arg);
00549 return (ret == 0 ? (void *)pth : NULL);
00550 }
00551
00552 int rpmsqJoin(void * thread)
00553 {
00554 pthread_t pth = (pthread_t) thread;
00555 if (thread == NULL)
00556 return EINVAL;
00557 return pthread_join(pth, NULL);
00558 }
00559
00560 int rpmsqThreadEqual(void * thread)
00561 {
00562 pthread_t t1 = (pthread_t) thread;
00563 pthread_t t2 = pthread_self();
00564 return pthread_equal(t1, t2);
00565 }
00566
00570 static void
00571 sigchld_cancel (void *arg)
00572
00573
00574 {
00575 pid_t child = *(pid_t *) arg;
00576 pid_t result;
00577
00578 (void) kill(child, SIGKILL);
00579
00580 do {
00581 result = waitpid(child, NULL, 0);
00582 } while (result == (pid_t)-1 && errno == EINTR);
00583
00584 (void) DO_LOCK ();
00585 if (SUB_REF (rpmsigTbl_sigchld) == 0) {
00586 (void) rpmsqEnable(-SIGQUIT, NULL);
00587 (void) rpmsqEnable(-SIGINT, NULL);
00588 }
00589 (void) DO_UNLOCK ();
00590 }
00591
00595 int
00596 rpmsqExecve (const char ** argv)
00597
00598
00599 {
00600 int oldtype;
00601 int status = -1;
00602 pid_t pid = 0;
00603 pid_t result;
00604 sigset_t newMask, oldMask;
00605 rpmsq sq = memset(alloca(sizeof(*sq)), 0, sizeof(*sq));
00606
00607 (void) DO_LOCK ();
00608 if (ADD_REF (rpmsigTbl_sigchld) == 0) {
00609 if (rpmsqEnable(SIGINT, NULL) < 0) {
00610 SUB_REF (rpmsigTbl_sigchld);
00611 goto out;
00612 }
00613 if (rpmsqEnable(SIGQUIT, NULL) < 0) {
00614 SUB_REF (rpmsigTbl_sigchld);
00615 goto out_restore_sigint;
00616 }
00617 }
00618 (void) DO_UNLOCK ();
00619
00620 (void) sigemptyset (&newMask);
00621 (void) sigaddset (&newMask, SIGCHLD);
00622 if (sigprocmask (SIG_BLOCK, &newMask, &oldMask) < 0) {
00623 (void) DO_LOCK ();
00624 if (SUB_REF (rpmsigTbl_sigchld) == 0)
00625 goto out_restore_sigquit_and_sigint;
00626 goto out;
00627 }
00628
00629 CLEANUP_HANDLER(sigchld_cancel, &pid, &oldtype);
00630
00631 pid = fork ();
00632 if (pid < (pid_t) 0) {
00633 goto out;
00634 } else if (pid == (pid_t) 0) {
00635
00636
00637 (void) sigaction (SIGINT, &rpmsigTbl_sigint->oact, NULL);
00638 (void) sigaction (SIGQUIT, &rpmsigTbl_sigquit->oact, NULL);
00639 (void) sigprocmask (SIG_SETMASK, &oldMask, NULL);
00640
00641
00642 INIT_LOCK ();
00643
00644 #if defined(__GLIBC__)
00645
00649 {
00650 char* bypassVar = (char*) malloc(1024*sizeof(char));
00651 if (bypassVar != NULL)
00652 {
00653 snprintf(bypassVar,1024*sizeof(char), "__PASSTHROUGH_LD_ASSUME_KERNEL_%d", getppid());
00654 bypassVar[1023] = '\0';
00655 if (getenv(bypassVar) != NULL)
00656 {
00657 char* bypassVal = (char*) malloc(1024*sizeof(char));
00658 if (bypassVal != NULL)
00659 {
00660 snprintf(bypassVal, 1024*sizeof(char), "%s", getenv(bypassVar));
00661 unsetenv(bypassVar);
00662 snprintf(bypassVar, 1024*sizeof(char), "LD_ASSUME_KERNEL=%s", bypassVal);
00663 bypassVar[1023] = '\0';
00664 putenv(bypassVar);
00665 free(bypassVal);
00666 }
00667 else
00668 {
00669 free(bypassVar);
00670 }
00671 }
00672 }
00673 }
00674 #endif
00675
00676 (void) execve (argv[0], (char *const *) argv, environ);
00677 _exit (127);
00678 } else {
00679 do {
00680 result = waitpid(pid, &status, 0);
00681 } while (result == (pid_t)-1 && errno == EINTR);
00682 if (result != pid)
00683 status = -1;
00684 }
00685
00686 CLEANUP_RESET(0, oldtype);
00687
00688 (void) DO_LOCK ();
00689 if ((SUB_REF (rpmsigTbl_sigchld) == 0 &&
00690 (rpmsqEnable(-SIGINT, NULL) < 0 || rpmsqEnable (-SIGQUIT, NULL) < 0))
00691 || sigprocmask (SIG_SETMASK, &oldMask, NULL) != 0)
00692 {
00693 status = -1;
00694 }
00695 goto out;
00696
00697 out_restore_sigquit_and_sigint:
00698 (void) rpmsqEnable(-SIGQUIT, NULL);
00699 out_restore_sigint:
00700 (void) rpmsqEnable(-SIGINT, NULL);
00701 out:
00702 (void) DO_UNLOCK ();
00703 return status;
00704 }