#if defined(__LCLINT__)
#define _BITS_SIGTHREAD_H /* XXX avoid __sigset_t heartburn. */
+/*@-incondefs -protoparammatch@*/
/*@-exportheader@*/
/*@constant int SA_SIGINFO@*/
extern int sighold(int sig)
/*@modifies internalState @*/;
extern int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
- /*@modifies *attr @*/;
+ /*@globals errno, internalState @*/
+ /*@modifies *attr, errno, internalState @*/;
extern int pthread_mutexattr_init(/*@out@*/ pthread_mutexattr_t *attr)
- /*@modifies *attr @*/;
+ /*@globals errno, internalState @*/
+ /*@modifies *attr, errno, internalState @*/;
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr,
/*@out@*/ int *restrict type)
/*@modifies *type @*/;
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
- /*@modifies *attr @*/;
+ /*@globals errno, internalState @*/
+ /*@modifies *attr, errno, internalState @*/;
extern int pthread_mutex_destroy(pthread_mutex_t *mutex)
/*@modifies *mutex @*/;
extern int pthread_mutex_init(/*@out@*/ pthread_mutex_t *restrict mutex,
/*@null@*/ const pthread_mutexattr_t *restrict attr)
- /*@modifies *mutex @*/;
+ /*@globals errno, internalState @*/
+ /*@modifies *mutex, errno, internalState @*/;
extern int pthread_mutex_lock(pthread_mutex_t *mutex)
- /*@modifies *mutex @*/;
+ /*@globals errno @*/
+ /*@modifies *mutex, errno @*/;
extern int pthread_mutex_trylock(pthread_mutex_t *mutex)
- /*@modifies *mutex @*/;
+ /*@globals errno @*/
+ /*@modifies *mutex, errno @*/;
extern int pthread_mutex_unlock(pthread_mutex_t *mutex)
- /*@modifies *mutex @*/;
+ /*@globals errno @*/
+ /*@modifies *mutex, errno @*/;
extern int pthread_cond_destroy(pthread_cond_t *cond)
/*@modifies *cond @*/;
extern int pthread_cond_init(/*@out@*/ pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr)
- /*@modifies *cond @*/;
+ /*@globals errno, internalState @*/
+ /*@modifies *cond, errno, internalState @*/;
extern int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
pthread_mutex_t *restrict mutex)
/*@modifies *cond, *mutex @*/;
extern int pthread_cond_broadcast(pthread_cond_t *cond)
- /*@modifies *cond @*/;
+ /*@globals errno, internalState @*/
+ /*@modifies *cond, errno, internalState @*/;
extern int pthread_cond_signal(pthread_cond_t *cond)
- /*@modifies *cond @*/;
+ /*@globals errno, internalState @*/
+ /*@modifies *cond, errno, internalState @*/;
/*@=exportheader@*/
+/*@=incondefs =protoparammatch@*/
#endif
#include <signal.h>
#include <pthread.h>
+#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
+/*@unchecked@*/
+static pthread_mutex_t rpmsigTbl_lock = PTHREAD_MUTEX_INITIALIZER;
+#else
/*@unchecked@*/
/*@-type@*/
static pthread_mutex_t rpmsigTbl_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
/*@=type@*/
+#endif
#define DO_LOCK() pthread_mutex_lock(&rpmsigTbl_lock);
#define DO_UNLOCK() pthread_mutex_unlock(&rpmsigTbl_lock);
(void) pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, (__oldtypeptr));\
pthread_cleanup_push((__handler), (__arg));
#define CLEANUP_RESET(__execute, __oldtype) \
- (void) pthread_cleanup_pop(__execute); \
+ pthread_cleanup_pop(__execute); \
(void) pthread_setcanceltype ((__oldtype), &(__oldtype));
#define SAME_THREAD(_a, _b) pthread_equal(((pthread_t)_a), ((pthread_t)_b))
sq->child = 0;
sq->reaped = 0;
sq->status = 0;
- sq->reaper = 1;
+ sq->reaper = 0;
/*@-bounds@*/
sq->pipes[0] = sq->pipes[1] = -1;
/*@=bounds@*/
if (signum >= 0) { /* Enable. */
if (ADD_REF(tbl) <= 0) {
(void) sigdelset(&rpmsqCaught, tbl->signum);
+
+ /* XXX Don't set a signal handler if already SIG_IGN */
+ (void) sigaction(tbl->signum, NULL, &tbl->oact);
+ if (tbl->oact.sa_handler == SIG_IGN)
+ continue;
+
(void) sigemptyset (&sa.sa_mask);
-/*@-compdef -type @*/
sa.sa_flags = SA_SIGINFO;
+#if defined(__LCLINT__) /* XXX glibc has union to track handler prototype. */
+ sa.sa_handler = (handler != NULL ? handler : tbl->handler);
+#else
sa.sa_sigaction = (handler != NULL ? handler : tbl->handler);
+#endif
if (sigaction(tbl->signum, &sa, &tbl->oact) < 0) {
SUB_REF(tbl);
break;
}
-/*@=compdef =type @*/
tbl->active = 1; /* XXX just in case */
if (handler != NULL)
tbl->handler = handler;
} else if (pid == (pid_t) 0) { /* Child. */
int yy;
- /* Block to permit parent to wait. */
+ /* Block to permit parent time to wait. */
/*@-bounds@*/
xx = close(sq->pipes[1]);
xx = read(sq->pipes[0], &yy, sizeof(yy));
/**
* Wait for child process to be reaped, and unregister SIGCHLD handler.
+ * @todo Rewrite to use waitpid on helper thread.
* @param sq scriptlet queue element
* @return 0 on success
*/
/*@globals fileSystem, internalState @*/
/*@modifies sq, fileSystem, internalState @*/
{
- int same_thread = 0;
+ int nothreads = 0;
int ret = 0;
int xx;
- if (same_thread)
- ret = sighold(SIGCHLD);
- else
+ /* Protect sq->reaped from handler changes. */
+ ret = sighold(SIGCHLD);
+
+ /* Initialize the cond var mutex. */
+ if (!nothreads)
ret = pthread_mutex_lock(&sq->mutex);
- /* Start the child. */
+ /* Start the child, linux often runs child before parent. */
/*@-bounds@*/
if (sq->pipes[0] >= 0)
xx = close(sq->pipes[0]);
sq->pipes[0] = sq->pipes[1] = -1;
/*@=bounds@*/
+ /* Put a stopwatch on the time spent waiting to measure performance gain. */
(void) rpmswEnter(&sq->op, -1);
+ /* Wait for handler to receive SIGCHLD. */
/*@-infloops@*/
while (ret == 0 && sq->reaped != sq->child) {
- if (same_thread)
+ if (nothreads)
+ /* Note that sigpause re-enables SIGCHLD. */
ret = sigpause(SIGCHLD);
- else
+ else {
+ xx = sigrelse(SIGCHLD);
ret = pthread_cond_wait(&sq->cond, &sq->mutex);
+ xx = sighold(SIGCHLD);
+ }
}
/*@=infloops@*/
+ /* Accumulate stopwatch time spent waiting, potential performance gain. */
sq->ms_scriptlets += rpmswExit(&sq->op, -1)/1000;
- if (same_thread)
- xx = sigrelse(SIGCHLD);
- else
+ /* Tear down cond var mutex, our child has been reaped. */
+ if (!nothreads)
xx = pthread_mutex_unlock(&sq->mutex);
+ xx = sigrelse(SIGCHLD);
#ifdef _RPMSQ_DEBUG
if (_rpmsq_debug)
fprintf(stderr, " Wake(%p): %p child %d reaper %d ret %d\n", ME(), sq, sq->child, sq->reaper, ret);
#endif
+ /* Remove processed SIGCHLD item from queue. */
xx = rpmsqRemove(sq);
+
+ /* Disable SIGCHLD handler on refcount == 0. */
xx = rpmsqEnable(-SIGCHLD, NULL);
#ifdef _RPMSQ_DEBUG
if (_rpmsq_debug)
sigset_t newMask, oldMask;
rpmsq sq = memset(alloca(sizeof(*sq)), 0, sizeof(*sq));
+#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
+ INIT_LOCK ();
+#endif
+
(void) DO_LOCK ();
if (ADD_REF (rpmsigTbl_sigchld) == 0) {
if (rpmsqEnable(SIGINT, NULL) < 0) {