Create rpmsq, combining rpmdb/psm signal handlers.
authorjbj <devnull@localhost>
Sun, 16 Mar 2003 22:36:52 +0000 (22:36 +0000)
committerjbj <devnull@localhost>
Sun, 16 Mar 2003 22:36:52 +0000 (22:36 +0000)
CVS patchset: 6694
CVS date: 2003/03/16 22:36:52

lib/Makefile.am
lib/psm.c
lib/psm.h
lib/tsystem.c
lib/tthread.c
rpmdb/rpmdb.c
rpmio/Makefile.am
rpmio/rpmsq.c [new file with mode: 0644]
rpmio/rpmsq.h [new file with mode: 0644]

index c3473bd..2e4ee03 100644 (file)
@@ -100,8 +100,8 @@ trb: trb.o librpm.la
 tthread: tthread.o librpm.la
        $(LINK) $(CFLAGS) $(DEFS) $(INCLUDES) -o $@ $< $(mylibs) @WITH_LIBELF_LIB@
 
-tsystem: tsystem.o
-       $(LINK) $(CFLAGS) $(DEFS) $(INCLUDES) -o $@ $< -lpthread
+tsystem: tsystem.o $(top_builddir)/popt/libpopt.la
+       $(LINK) $(CFLAGS) $(DEFS) $(INCLUDES) -o $@ $< $(top_builddir)/rpmio/librpmio.la $(top_builddir)/popt/libpopt.la
 
 tplatform: tplatform.o librpm.la
        $(LINK) @LDFLAGS_STATIC@ $(CFLAGS) $(DEFS) $(INCLUDES) -o $@ $< $(mylibs)
index ba19f7b..e0b1dbb 100644 (file)
--- a/lib/psm.c
+++ b/lib/psm.c
@@ -5,13 +5,11 @@
 
 #include "system.h"
 
-#include <signal.h>
-#include <sys/signal.h>
-
 #include <rpmio_internal.h>
 #include <rpmlib.h>
 #include <rpmmacro.h>
 #include <rpmurl.h>
+#include <rpmsq.h>
 
 #include "cpio.h"
 #include "fsm.h"               /* XXX CPIO_FOO/FSM_FOO constants */
@@ -458,199 +456,34 @@ static /*@observer@*/ const char * const tag2sln(int tag)
 }
 
 /**
- */
-/*@unchecked@*/
-static sigset_t caught;
-
-/**
- */
-/*@unchecked@*/
-static struct psmtbl_s {
-    int nalloced;
-    int npsms;
-/*@null@*/
-    rpmpsm * psms;
-} psmtbl = { 0, 0, NULL };
-
-/* forward ref */
-static void handler(int signum)
-       /*@globals caught, psmtbl, fileSystem @*/
-       /*@modifies caught, psmtbl, fileSystem @*/;
-
-/**
- */
-/*@unchecked@*/
-/*@-fullinitblock@*/
-static struct sigtbl_s {
-    int signum;
-    int active;
-    void (*handler) (int signum);
-    struct sigaction oact;
-} satbl[] = {
-    { SIGCHLD, 0, handler },
-    { -1,      0, NULL },
-};
-/*@=fullinitblock@*/
-
-/**
- */
-/*@-incondefs@*/
-static void handler(int signum)
-{
-    struct sigtbl_s * tbl;
-
-    for(tbl = satbl; tbl->signum >= 0; tbl++) {
-       if (tbl->signum != signum)
-           continue;
-       if (!tbl->active)
-           continue;
-       (void) sigaddset(&caught, signum);
-       switch (signum) {
-       case SIGCHLD:
-           while (1) {
-               int status = 0;
-               pid_t reaped = waitpid(0, &status, WNOHANG);
-               int i;
-
-               if (reaped <= 0)
-                   /*@innerbreak@*/ break;
-
-               if (psmtbl.psms)
-               for (i = 0; i < psmtbl.npsms; i++) {
-                   rpmpsm psm = psmtbl.psms[i];
-                   if (psm->child != reaped)
-                       /*@innercontinue@*/ continue;
-
-#if _PSM_DEBUG
-/*@-modfilesys@*/
-if (_psm_debug)
-fprintf(stderr, "      Reap: %p[%d:%d:%d] = %p child %d\n", psmtbl.psms, i, psmtbl.npsms, psmtbl.nalloced, psm, psm->child);
-/*@=modfilesys@*/
-#endif
-
-                   psm->reaped = reaped;
-                   psm->status = status;
-                   /*@innerbreak@*/ break;
-               }
-           }
-           /*@switchbreak@*/ break;
-       default:
-           /*@switchbreak@*/ break;
-       }
-       break;
-    }
-}
-/*@=incondefs@*/
-
-/**
- * Enable a signal handler.
- */
-static int enableSignal(int signum)
-       /*@globals caught, satbl, fileSystem @*/
-       /*@modifies caught, satbl, fileSystem @*/
-{
-    sigset_t newMask, oldMask;
-    struct sigtbl_s * tbl;
-    struct sigaction act;
-
-    (void) sigfillset(&newMask);               /* block all signals */
-    (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
-    for (tbl = satbl; tbl->signum >= 0; tbl++) {
-       if (signum >= 0 && signum != tbl->signum)
-           continue;
-/*@-modfilesys@*/
-if (_psm_debug)
-fprintf(stderr, "    Enable: %p[0:%d:%d] active %d\n", psmtbl.psms, psmtbl.npsms, psmtbl.nalloced, tbl->active);
-/*@=modfilesys@*/
-       if (tbl->active++ <= 0) {
-           (void) sigdelset(&caught, tbl->signum);
-           memset(&act, 0, sizeof(act));
-           act.sa_handler = tbl->handler;
-           (void) sigaction(tbl->signum, &act, &tbl->oact);
-       }
-       break;
-    }
-    return sigprocmask(SIG_SETMASK, &oldMask, NULL);
-}
-
-/**
- * Disable a signal handler.
- */
-static int disableSignal(int signum)
-       /*@globals satbl, fileSystem @*/
-       /*@modifies satbl, fileSystem @*/
-{
-    sigset_t newMask, oldMask;
-    struct sigtbl_s * tbl;
-
-    (void) sigfillset(&newMask);               /* block all signals */
-    (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
-    for (tbl = satbl; tbl->signum >= 0; tbl++) {
-       if (signum >= 0 && signum != tbl->signum)
-           continue;
-/*@-modfilesys@*/
-if (_psm_debug)
-fprintf(stderr, "   Disable: %p[0:%d:%d] active %d\n", psmtbl.psms, psmtbl.npsms, psmtbl.nalloced, tbl->active);
-/*@=modfilesys@*/
-       if (--tbl->active <= 0) {
-           tbl->active = 0;            /* XXX just in case */
-           (void) sigaction(tbl->signum, &tbl->oact, NULL);
-       }
-       break;
-    }
-    return sigprocmask(SIG_SETMASK, &oldMask, NULL);
-}
-
-/**
  * Register a child reaper, then fork a child.
  * @param psm          package state machine data
  * @return             fork(2) pid
  */
 static pid_t psmRegisterFork(rpmpsm psm)
-       /*@globals psmtbl, fileSystem, internalState @*/
-       /*@modifies psm, psmtbl, fileSystem, internalState @*/
+       /*@globals fileSystem, internalState @*/
+       /*@modifies psm, fileSystem, internalState @*/
 {
     sigset_t newMask, oldMask;
-    int empty = -1;
-    int i = psmtbl.npsms;
 
     (void) sigfillset(&newMask);               /* block all signals */
     (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
 
   if (psm->reaper) {
-    if (psmtbl.psms)
-    for (i = 0; i < psmtbl.npsms; i++) {
-       if (empty == -1 && psmtbl.psms[i] == NULL)
-           empty = i;
-       if (psm != psmtbl.psms[i])
-           continue;
-       break;
-    }
-    if (i == psmtbl.npsms) {
-       if (i >= psmtbl.nalloced) {
-           if (psmtbl.nalloced == 0) psmtbl.nalloced = 5;
-           while (psmtbl.nalloced < i)
-               psmtbl.nalloced += psmtbl.nalloced;
-           psmtbl.psms = xrealloc(psmtbl.psms,
-                       psmtbl.nalloced * sizeof(*psmtbl.psms));
-       }
-       empty = psmtbl.npsms++;
-    }
-    if (psmtbl.psms)   /* XXX can't happen */
-       psmtbl.psms[empty] = rpmpsmLink(psm, "psmRegister");
+    Insque(psm, NULL);
 /*@-modfilesys@*/
 if (_psm_debug)
-fprintf(stderr, "  Register: %p[%d:%d:%d] = %p\n", psmtbl.psms, empty, psmtbl.npsms, psmtbl.nalloced, psm);
+fprintf(stderr, "  Register: %p\n", psm);
 /*@=modfilesys@*/
 
-    (void) enableSignal(SIGCHLD);
+    (void) rpmsqEnable(SIGCHLD, NULL);
   }
 
     psm->reaped = 0;
     if ((psm->child = fork()) != 0) {
 /*@-modfilesys@*/
 if (_psm_debug)
-fprintf(stderr, "      Fork: %p[%d:%d:%d] = %p child %d\n", psmtbl.psms, 0, psmtbl.npsms, psmtbl.nalloced, psm, psm->child);
+fprintf(stderr, "      Fork: %p child %d\n", psm, psm->child);
 /*@=modfilesys@*/
     }
 
@@ -663,11 +496,10 @@ fprintf(stderr, "      Fork: %p[%d:%d:%d] = %p child %d\n", psmtbl.psms, 0, psmt
  * Unregister a child reaper.
  */
 static int psmWaitUnregister(rpmpsm psm, pid_t child)
-       /*@globals psmtbl, fileSystem, internalState @*/
-       /*@modifies psmtbl, fileSystem, internalState @*/
+       /*@globals fileSystem, internalState @*/
+       /*@modifies fileSystem, internalState @*/
 {
     sigset_t newMask, oldMask;
-    int i = 0;
 
     (void) sigfillset(&newMask);               /* block all signals */
     (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
@@ -679,34 +511,16 @@ static int psmWaitUnregister(rpmpsm psm, pid_t child)
 
 /*@-modfilesys@*/
 if (_psm_debug)
-fprintf(stderr, "      Wait: %p[%d:%d:%d] = %p child %d\n", psmtbl.psms, 0, psmtbl.npsms, psmtbl.nalloced, psm, psm->child);
+fprintf(stderr, "      Wait: %p child %d\n", psm, psm->child);
 /*@=modfilesys@*/
 
-    if (psmtbl.psms)
-    for (i = 0; i < psmtbl.npsms; i++) {
-       if (psmtbl.psms[i] == NULL)
-           continue;
-       if (psm != psmtbl.psms[i])
-           continue;
-       if (child != psm->child)
-           continue;
-       break;
-    }
-
-    if (i < psmtbl.npsms) {
-       (void) disableSignal(SIGCHLD);
+    if (psm->reaper) {
+       Remque(psm);
+       (void) rpmsqEnable(-SIGCHLD, NULL);
 /*@-modfilesys@*/
 if (_psm_debug)
-fprintf(stderr, "Unregister: %p[%d:%d:%d] = %p child %d\n", psmtbl.psms, i, psmtbl.npsms, psmtbl.nalloced, psm, child);
+fprintf(stderr, "Unregister: %p child %d\n", psm, child);
 /*@=modfilesys@*/
-       if (psmtbl.psms)        /* XXX can't happen */
-           psmtbl.psms[i] = rpmpsmFree(psmtbl.psms[i]);
-       if (psmtbl.npsms == (i+1))
-           psmtbl.npsms--;
-       if (psmtbl.npsms == 0) {
-           psmtbl.psms = _free(psmtbl.psms);
-           psmtbl.nalloced = 0;
-       }
     }
 
     return sigprocmask(SIG_SETMASK, &oldMask, NULL);
@@ -797,7 +611,7 @@ static rpmRC runScript(rpmpsm psm, Header h, const char * sln,
     psm->child = 0;
     psm->reaped = 0;
     psm->status = 0;
-    psm->reaper = 1;
+    psm->reaper = 0;
 
     /* XXX FIXME: except for %verifyscript, rpmteNEVR can be used. */
     xx = headerNVR(h, &n, &v, &r);
index 5893168..1f847e1 100644 (file)
--- a/lib/psm.h
+++ b/lib/psm.h
@@ -60,6 +60,12 @@ typedef enum pkgStage_e {
 /**
  */
 struct rpmpsm_s {
+    void * q_forw;             /*!< for use by insque(3)/remque(3). */
+    void * q_back;
+    pid_t child;               /*!< Currently running process. */
+    pid_t reaped;              /*!< Reaped waitpid return. */
+    int status;                        /*!< Reaped waitpid status. */
+
 /*@refcounted@*/
     rpmts ts;                  /*!< transaction set */
 /*@dependent@*/ /*@null@*/
@@ -68,7 +74,7 @@ struct rpmpsm_s {
     rpmfi fi;                  /*!< transaction element file info */
     FD_t cfd;                  /*!< Payload file handle. */
     FD_t fd;                   /*!< Repackage file handle. */
-    Header oh;                 /*!< Repackage/multilib header. */
+    Header oh;                 /*!< Repackage header. */
 /*@null@*/
     rpmdbMatchIterator mi;
 /*@observer@*/
@@ -90,9 +96,6 @@ struct rpmpsm_s {
     int chrootDone;            /*!< Was chroot(2) done by pkgStage? */
     int unorderedSuccessor;    /*!< Can the PSM be run asynchronously? */
     int reaper;                        /*!< Register SIGCHLD handler? */
-    pid_t reaped;              /*!< Reaped waitpid return. */
-    pid_t child;               /*!< Currently running process. */
-    int status;                        /*!< Reaped waitpid status. */
     rpmCallbackType what;      /*!< Callback type. */
     unsigned long amount;      /*!< Callback amount. */
     unsigned long total;       /*!< Callback total. */
index 083aaa4..1313781 100644 (file)
-
-/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
 #include "system.h"
 
 #include <pthread.h>
-#include <signal.h>
 
-#include <rpmlib.h>
-#include <rpmts.h>
-#include "psm.h"
+#include <rpmsq.h>
+#include <popt.h>
 
 #include "debug.h"
 
-#define _PSM_DEBUG      0
-/*@unchecked@*/
-int _psm_debug = _PSM_DEBUG;
-
-#define        SHELL_PATH      "/bin/sh"       /* Path of the shell.  */
-#define        SHELL_NAME      "sh"            /* Name to give it.  */
-
-
-/**
- */
-/*@unchecked@*/
-static sigset_t caught;
-
-/**
- */
-/*@unchecked@*/
-static struct psmtbl_s {
-    int nalloced;
-    int npsms;
-/*@null@*/
-    rpmpsm * psms;
-} psmtbl = { 0, 0, NULL };
-
-/* forward ref */
-static void handler(int signum)
-       /*@globals caught, psmtbl, fileSystem @*/
-       /*@modifies caught, psmtbl, fileSystem @*/;
-
-/**
- */
-/*@unchecked@*/
-static pthread_mutex_t satbl_lock = PTHREAD_MUTEX_INITIALIZER;
-
-/**
- */
-/*@unchecked@*/
-/*@-fullinitblock@*/
-static struct sigtbl_s {
-    int signum;
-    int active;
-    void (*handler) (int signum);
-    struct sigaction oact;
-} satbl[] = {
-    { SIGINT,   0, handler },
-#define        satbl_sigint    (&satbl[0])
-    { SIGQUIT,  0, handler },
-#define        satbl_sigquit   (&satbl[1])
-    { SIGCHLD, 0, handler },
-#define        satbl_sigchld   (&satbl[2])
-#define        sigchld_active  satbl_sigchld->active
-#define        DO_LOCK()       pthread_mutex_lock(&satbl_lock);
-#define        DO_UNLOCK()     pthread_mutex_unlock(&satbl_lock);
-#define        INIT_LOCK()     \
-       { pthread_mutex_init (&satbl_lock, NULL); sigchld_active = 0; }
-#define        ADD_REF()       sigchld_active++
-#define        SUB_REF()       --sigchld_active
-
-#define        CLEANUP_HANDLER(__handler, __arg, __oldtypeptr) \
-       pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, (__oldtypeptr)); \
-       pthread_cleanup_push((__handler), (__arg));
-#define        CLEANUP_RESET(__execute, __oldtype) \
-       pthread_cleanup_pop(__execute); \
-       pthread_setcanceltype ((__oldtype), &(__oldtype));
-
-    { SIGHUP,   0, handler },
-#define        satbl_sighup    (&satbl[3])
-    { SIGTERM,  0, handler },
-#define        satbl_sigterm   (&satbl[4])
-    { SIGPIPE,  0, handler },
-#define        satbl_sigpipe   (&satbl[5])
-    { -1,      0, NULL },
-};
-typedef struct sigtbl_s * sigtbl;
-/*@=fullinitblock@*/
-
-/**
- */
-/*@-incondefs@*/
-static void handler(int signum)
-{
-    sigtbl tbl;
-
-    for (tbl = satbl; tbl->signum >= 0; tbl++) {
-       if (tbl->signum != signum)
-           continue;
-       if (!tbl->active)
-           continue;
-       (void) sigaddset(&caught, signum);
-       switch (signum) {
-       case SIGCHLD:
-           while (1) {
-               int status = 0;
-               pid_t reaped = waitpid(0, &status, WNOHANG);
-               int i;
-
-               if (reaped <= 0)
-                   /*@innerbreak@*/ break;
-
-               if (psmtbl.psms)
-               for (i = 0; i < psmtbl.npsms; i++) {
-                   rpmpsm psm = psmtbl.psms[i];
-                   if (psm->child != reaped)
-                       /*@innercontinue@*/ continue;
-
-#if _PSM_DEBUG
-/*@-modfilesys@*/
-if (_psm_debug)
-fprintf(stderr, "      Reap: %p[%d:%d:%d] = %p child %d\n", psmtbl.psms, i, psmtbl.npsms, psmtbl.nalloced, psm, psm->child);
-/*@=modfilesys@*/
-#endif
-
-                   psm->reaped = reaped;
-                   psm->status = status;
-                   /*@innerbreak@*/ break;
-               }
-           }
-           /*@switchbreak@*/ break;
-       default:
-           /*@switchbreak@*/ break;
-       }
-       break;
-    }
-}
-/*@=incondefs@*/
-
-/* The cancellation handler.  */
-static void
-sigchld_cancel (void *arg)
-{
-    pid_t child = *(pid_t *) arg;
-    pid_t result;
-    int err;
-
-    err = kill(child, SIGKILL);
-
-    do {
-       result = waitpid(child, NULL, 0);
-    } while (result == (pid_t)-1 && errno == EINTR);
-
-    DO_LOCK ();
-    if (SUB_REF () == 0) {
-       (void) sigaction (SIGQUIT, &satbl_sigquit->oact, (struct sigaction *) NULL);
-       (void) sigaction (SIGINT, &satbl_sigint->oact, (struct sigaction *) NULL);
-    }
-    DO_UNLOCK ();
-}
-
-/* Execute LINE as a shell command, returning its status.  */
-static int
-do_system (const char *line)
-{
-    int oldtype;
-    int status = -1;
-    pid_t pid;
-    pid_t result;
-    struct sigaction sa;
-    sigset_t omask;
-
-    sa.sa_handler = SIG_IGN;
-    sa.sa_flags = 0;
-    sigemptyset (&sa.sa_mask);
-
-    DO_LOCK ();
-    if (ADD_REF () == 0) {
-       if (sigaction (SIGINT, &sa, &satbl_sigint->oact) < 0) {
-           SUB_REF ();
-           goto out;
-       }
-       if (sigaction (SIGQUIT, &sa, &satbl_sigquit->oact) < 0) {
-           SUB_REF ();
-           goto out_restore_sigint;
-       }
-    }
-    DO_UNLOCK ();
-
-    /* We reuse the bitmap in the 'sa' structure.  */
-    sigaddset (&sa.sa_mask, SIGCHLD);
-    if (sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0) {
-       DO_LOCK ();
-       if (SUB_REF () == 0)
-           goto out_restore_sigquit_and_sigint;
-       goto out;
-    }
-
-    CLEANUP_HANDLER(sigchld_cancel, &pid, &oldtype);
-
-    pid = fork ();
-    if (pid == (pid_t) 0) {
-       /* Child side.  */
-       const char *new_argv[4];
-       new_argv[0] = SHELL_NAME;
-       new_argv[1] = "-c";
-       new_argv[2] = line;
-       new_argv[3] = NULL;
-
-       /* Restore the signals.  */
-       (void) sigaction (SIGINT, &satbl_sigint->oact, NULL);
-       (void) sigaction (SIGQUIT, &satbl_sigquit->oact, NULL);
-       (void) sigprocmask (SIG_SETMASK, &omask, NULL);
-
-       INIT_LOCK ();
-
-       /* Exec the shell.  */
-       (void) execve (SHELL_PATH, (char *const *) new_argv, __environ);
-       _exit (127);
-    } else if (pid < (pid_t) 0) {
-       /* The fork failed.  */
-       goto out;
-    } else {
-       /* Parent side.  */
-       do {
-           result = waitpid(pid, &status, 0);
-       } while (result == (pid_t)-1 && errno == EINTR);
-       if (result != pid)
-           status = -1;
-    }
-
-    CLEANUP_RESET(0, oldtype);
-
-    DO_LOCK ();
-    if ((SUB_REF () == 0
-       && (sigaction (SIGINT, &satbl_sigint->oact, NULL)
-          | sigaction (SIGQUIT, &satbl_sigquit->oact, NULL)) != 0)
-       || sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
-    {
-       status = -1;
-    }
-    goto out;
-
-out_restore_sigquit_and_sigint:
-    (void) sigaction (SIGQUIT, &satbl_sigquit->oact, NULL);
-out_restore_sigint:
-    (void) sigaction (SIGINT, &satbl_sigint->oact, NULL);
-out:
-    DO_UNLOCK ();
-    return status;
-}
-
-static int
-xsystem (const char * line)
-{
-
-    if (line == NULL)
-       /* Check that we have a command processor available.  It might
-          not be available after a chroot(), for example.  */
-       return do_system ("exit 0") == 0;
-
-    return do_system (line);
-}
-
 static void *
 other_thread(void *dat)
 {
-    const char * s = (const char *)dat;
-    return ((void *) xsystem(s));
+    const char * cmd = (const char *)dat;
+    const char ** av = NULL;
+    int ac = 0;
+    int xx = poptParseArgvString(cmd, &ac, &av);
+    if (xx)
+       return ((void *)xx);
+fprintf(stderr, "thread(%lu): pid %u %s\n", pthread_self(), getpid(), cmd);
+    return ((void *) rpmsqExecve(av));
 }
 
 int main(int argc, char *argv[])
 {
     pthread_t pth;
+    const char * cmd = argv[1];
 
-    pthread_create(&pth, NULL, other_thread, "/bin/sleep 30" );
+    if (cmd == NULL)
+       cmd = "/bin/sleep 30";
+    pthread_create(&pth, NULL, other_thread, (void *)cmd);
+fprintf(stderr, "  main(%lu): pid %u other(%lu)\n", pthread_self(), getpid(), pth);
 
     sleep(2);
     pthread_cancel(pth);
index 290c37c..4adb5b6 100644 (file)
@@ -35,6 +35,7 @@ other_thread(void *dat)
   rpmReadConfigFiles(NULL, NULL);
   ts = rpmtsCreate();
   assert(ts);
+  (void) rpmtsSetRootDir(ts, "/");
 
   rpmIncreaseVerbosity();
   rpmIncreaseVerbosity();
index 5f44a4e..d865e22 100644 (file)
@@ -6,12 +6,7 @@
 
 #define        _USE_COPY_LOAD  /* XXX don't use DB_DBT_MALLOC (yet) */
 
-/*@unchecked@*/
-int _rpmdb_debug = 0;
-
 #include <sys/file.h>
-#include <signal.h>
-#include <sys/signal.h>
 
 #ifndef        DYING   /* XXX already in "system.h" */
 /*@-noparams@*/
@@ -35,6 +30,7 @@ extern void regfree (/*@only@*/ regex_t *preg)
 
 #include <rpmio_internal.h>
 #include <rpmmacro.h>
+#include <rpmsq.h>
 
 #include "rpmdb.h"
 #include "fprint.h"
@@ -50,6 +46,9 @@ extern void regfree (/*@only@*/ regex_t *preg)
 /*@access pgpDig@*/
 
 /*@unchecked@*/
+int _rpmdb_debug = 0;
+
+/*@unchecked@*/
 static int _rebuildinprogress = 0;
 /*@unchecked@*/
 static int _db_filter_dups = 0;
@@ -660,80 +659,6 @@ struct _rpmdbMatchIterator {
 
 };
 
-/**
- */
-/*@unchecked@*/
-static sigset_t caught;
-
-/* forward ref */
-static void handler(int signum);
-
-/**
- */
-/*@unchecked@*/
-/*@-fullinitblock@*/
-static struct sigtbl_s {
-    int signum;
-    int active;
-    void (*handler) (int signum);
-    struct sigaction oact;
-} satbl[] = {
-    { SIGHUP,  0, handler },
-    { SIGINT,  0, handler },
-    { SIGTERM, 0, handler },
-    { SIGQUIT, 0, handler },
-    { SIGPIPE, 0, handler },
-    { -1,      0, NULL },
-};
-/*@=fullinitblock@*/
-
-/**
- */
-/*@-incondefs@*/
-static void handler(int signum)
-       /*@globals caught, satbl @*/
-       /*@modifies caught @*/
-{
-    struct sigtbl_s * tbl;
-
-    for(tbl = satbl; tbl->signum >= 0; tbl++) {
-       if (tbl->signum != signum)
-           continue;
-       if (!tbl->active)
-           continue;
-       (void) sigaddset(&caught, signum);
-       break;
-    }
-}
-/*@=incondefs@*/
-
-/**
- * Enable all signal handlers.
- */
-static int enableSignals(void)
-       /*@globals caught, satbl, fileSystem @*/
-       /*@modifies caught, satbl, fileSystem @*/
-{
-    sigset_t newMask, oldMask;
-    struct sigtbl_s * tbl;
-    struct sigaction act;
-    int rc;
-
-    (void) sigfillset(&newMask);               /* block all signals */
-    (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
-    rc = 0;
-    for(tbl = satbl; tbl->signum >= 0; tbl++) {
-       if (tbl->active++ > 0)
-           continue;
-       (void) sigdelset(&caught, tbl->signum);
-       memset(&act, 0, sizeof(act));
-       act.sa_handler = tbl->handler;
-       rc = sigaction(tbl->signum, &act, &tbl->oact);
-       if (rc) break;
-    }
-    return sigprocmask(SIG_SETMASK, &oldMask, NULL);
-}
-
 /*@unchecked@*/
 static rpmdb rpmdbRock;
 
@@ -741,10 +666,9 @@ static rpmdb rpmdbRock;
 static rpmdbMatchIterator rpmmiRock;
 
 int rpmdbCheckSignals(void)
-       /*@globals rpmdbRock, rpmmiRock, satbl @*/
+       /*@globals rpmdbRock, rpmmiRock @*/
        /*@modifies rpmdbRock, rpmmiRock @*/
 {
-    struct sigtbl_s * tbl;
     sigset_t newMask, oldMask;
     static int terminate = 0;
 
@@ -752,12 +676,13 @@ int rpmdbCheckSignals(void)
 
     (void) sigfillset(&newMask);               /* block all signals */
     (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
-    for(tbl = satbl; tbl->signum >= 0; tbl++) {
-       if (tbl->active == 0)
-           continue;
-       if (sigismember(&caught, tbl->signum))
-           terminate = 1;
-    }
+
+    if (sigismember(&rpmsqCaught, SIGINT)
+     || sigismember(&rpmsqCaught, SIGQUIT)
+     || sigismember(&rpmsqCaught, SIGHUP)
+     || sigismember(&rpmsqCaught, SIGTERM)
+     || sigismember(&rpmsqCaught, SIGPIPE))
+       terminate = 1;
 
     if (terminate) {
        rpmdb db;
@@ -786,45 +711,21 @@ int rpmdbCheckSignals(void)
 }
 
 /**
- * Disable all signal handlers.
- */
-static int disableSignals(void)
-       /*@globals satbl, fileSystem @*/
-       /*@modifies satbl, fileSystem @*/
-{
-    struct sigtbl_s * tbl;
-    sigset_t newMask, oldMask;
-    int rc;
-
-    (void) sigfillset(&newMask);               /* block all signals */
-    (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
-    rc = 0;
-    for(tbl = satbl; tbl->signum >= 0; tbl++) {
-       if (--tbl->active > 0)
-           continue;
-       rc = sigaction(tbl->signum, &tbl->oact, NULL);
-       if (rc) break;
-    }
-    return sigprocmask(SIG_SETMASK, &oldMask, NULL);
-}
-
-/**
  * Block all signals, returning previous signal mask.
  */
 static int blockSignals(/*@unused@*/ rpmdb db, /*@out@*/ sigset_t * oldMask)
-       /*@globals satbl, fileSystem @*/
-       /*@modifies *oldMask, satbl, fileSystem @*/
+       /*@globals rpmsigTbl, fileSystem @*/
+       /*@modifies *oldMask, rpmsigTbl, fileSystem @*/
 {
-    struct sigtbl_s * tbl;
     sigset_t newMask;
 
     (void) sigfillset(&newMask);               /* block all signals */
     (void) sigprocmask(SIG_BLOCK, &newMask, oldMask);
-    for(tbl = satbl; tbl->signum >= 0; tbl++) {
-       if (tbl->active == 0)
-           continue;
-       (void) sigdelset(&newMask, tbl->signum);
-    }
+    sigdelset(&newMask, SIGINT);
+    sigdelset(&newMask, SIGQUIT);
+    sigdelset(&newMask, SIGHUP);
+    sigdelset(&newMask, SIGTERM);
+    sigdelset(&newMask, SIGPIPE);
     return sigprocmask(SIG_BLOCK, &newMask, NULL);
 }
 
@@ -949,7 +850,11 @@ int rpmdbClose(rpmdb db)
     /*@=usereleased@*/
 
 exit:
-    (void) disableSignals();
+    (void) rpmsqEnable(-SIGHUP,        NULL);
+    (void) rpmsqEnable(-SIGINT,        NULL);
+    (void) rpmsqEnable(-SIGTERM,NULL);
+    (void) rpmsqEnable(-SIGQUIT,NULL);
+    (void) rpmsqEnable(-SIGPIPE,NULL);
     return rc;
 }
 /*@=incondefs@*/
@@ -1060,7 +965,11 @@ static int openDatabase(/*@null@*/ const char * prefix,
     if (db == NULL)
        return 1;
 
-    (void) enableSignals();
+    (void) rpmsqEnable(SIGHUP, NULL);
+    (void) rpmsqEnable(SIGINT, NULL);
+    (void) rpmsqEnable(SIGTERM,NULL);
+    (void) rpmsqEnable(SIGQUIT,NULL);
+    (void) rpmsqEnable(SIGPIPE,NULL);
 
     db->db_api = _dbapi;
 
index 49355fb..e2dc7af 100644 (file)
@@ -17,7 +17,7 @@ pkgincdir = $(pkgincludedir)
 pkginc_HEADERS = \
        argv.h fts.h \
        rpmio.h rpmurl.h rpmmacro.h rpmlog.h rpmmessages.h rpmerr.h rpmpgp.h \
-       ugid.h
+       rpmsq.h ugid.h
 noinst_HEADERS = rpmio_internal.h
 
 BEECRYPTLOBJS = $(shell cat $(top_builddir)/beecrypt/listobjs)
@@ -29,7 +29,7 @@ usrlib_LTLIBRARIES = librpmio.la
 librpmio_la_SOURCES = \
        argv.c digest.c fts.c macro.c \
        rpmio.c rpmlog.c rpmmalloc.c \
-       rpmpgp.c rpmrpc.c strcasecmp.c stubs.c url.c ugid.c
+       rpmpgp.c rpmrpc.c rpmsq.c strcasecmp.c stubs.c url.c ugid.c
 librpmio_la_LDFLAGS = -release @VERSION@ \
        $(top_builddir)/file/libfmagic.la \
        @WITH_ZLIB_LIB@ \
diff --git a/rpmio/rpmsq.c b/rpmio/rpmsq.c
new file mode 100644 (file)
index 0000000..52180b6
--- /dev/null
@@ -0,0 +1,272 @@
+/** \ingroup rpmio
+ * \file rpmio/rpmsq.c
+ */
+
+#include "system.h"
+                                                                                
+#if defined(HAVE_PTHREAD_H) && !defined(__LCLINT__)
+#include <pthread.h>
+#endif
+
+#include <rpmsq.h>
+
+#include "debug.h"
+
+/*@unchecked@*/
+static struct rpmsqElem rpmsqRock;
+/*@unchecked@*/
+rpmsq rpmsqQueue = &rpmsqRock;
+
+void Insque(void * elem, void * prev)
+{
+    if (elem != NULL)
+       insque(elem, (prev ? prev : rpmsqQueue));
+}
+
+void Remque(void * elem)
+{
+    if (elem != NULL)
+       remque(elem);
+}
+
+/*@unchecked@*/
+sigset_t rpmsqCaught;
+
+/*@unchecked@*/
+static pthread_mutex_t rpmsigTbl_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+
+/*@unchecked@*/
+/*@-fullinitblock@*/
+static struct rpmsig_s {
+    int signum;
+    void (*handler) (int signum);
+    int active;
+    struct sigaction oact;
+} rpmsigTbl[] = {
+    { SIGINT,  rpmsqHandler },
+#define        rpmsigTbl_sigint        (&rpmsigTbl[0])
+    { SIGQUIT, rpmsqHandler },
+#define        rpmsigTbl_sigquit       (&rpmsigTbl[1])
+    { SIGCHLD, rpmsqHandler },
+#define        rpmsigTbl_sigchld       (&rpmsigTbl[2])
+
+#define        DO_LOCK()       pthread_mutex_lock(&rpmsigTbl_lock);
+#define        DO_UNLOCK()     pthread_mutex_unlock(&rpmsigTbl_lock);
+#define        INIT_LOCK()     \
+     { pthread_mutexattr_t attr; \
+       pthread_mutexattr_init(&attr); \
+       pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
+       pthread_mutex_init (&rpmsigTbl_lock, &attr); \
+       pthread_mutexattr_destroy(&attr); \
+       rpmsigTbl_sigchld->active = 0; \
+     }
+#define        ADD_REF(__tbl)  (__tbl)->active++
+#define        SUB_REF(__tbl)  --(__tbl)->active
+
+#define        CLEANUP_HANDLER(__handler, __arg, __oldtypeptr) \
+       pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, (__oldtypeptr)); \
+       pthread_cleanup_push((__handler), (__arg));
+#define        CLEANUP_RESET(__execute, __oldtype) \
+       pthread_cleanup_pop(__execute); \
+       pthread_setcanceltype ((__oldtype), &(__oldtype));
+
+    { SIGHUP,  rpmsqHandler },
+#define        rpmsigTbl_sighup        (&rpmsigTbl[3])
+    { SIGTERM, rpmsqHandler },
+#define        rpmsigTbl_sigterm       (&rpmsigTbl[4])
+    { SIGPIPE, rpmsqHandler },
+#define        rpmsigTbl_sigpipe       (&rpmsigTbl[5])
+    { -1,      NULL },
+};
+/*@=fullinitblock@*/
+
+/**
+ */
+/*@-incondefs@*/
+void rpmsqHandler(int signum)
+{
+    rpmsig tbl;
+
+    for (tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
+       if (tbl->signum != signum)
+           continue;
+
+       (void) sigaddset(&rpmsqCaught, signum);
+
+       switch (signum) {
+       case SIGCHLD:
+           while (1) {
+               rpmsq sq;
+               int status = 0;
+               pid_t reaped = waitpid(0, &status, WNOHANG);
+
+               if (reaped <= 0)
+                   /*@innerbreak@*/ break;
+
+               for (sq = rpmsqQueue->q_forw;
+                    sq != NULL && sq != rpmsqQueue;
+                    sq = sq->q_forw)
+               {
+                   if (sq->child != reaped)
+                       /*@innercontinue@*/ continue;
+                   sq->reaped = reaped;
+                   sq->status = status;
+                   /*@innerbreak@*/ break;
+               }
+           }
+           /*@switchbreak@*/ break;
+       default:
+           /*@switchbreak@*/ break;
+       }
+       break;
+    }
+}
+/*@=incondefs@*/
+
+/**
+ * Enable or disable a signal handler.
+ * @param signum       signal to enable (or disable if negative)
+ * @param handler      signal handler (or NULL to use rpmsqHandler())
+ * @return             no. of refs, -1 on error
+ */
+int rpmsqEnable(int signum, /*@null@*/ sighandler_t handler)
+       /*@globals rpmsqCaught, rpmsigTbl @*/
+       /*@modifies rpmsqCaught, rpmsigTbl @*/
+{
+    int tblsignum = (signum >= 0 ? signum : -signum);
+    struct sigaction sa;
+    rpmsig tbl;
+    int ret = -1;
+
+    DO_LOCK ();
+    for (tbl = rpmsigTbl; tbl->signum >= 0; tbl++) {
+       if (tblsignum != tbl->signum)
+           continue;
+
+       if (signum >= 0) {                      /* Enable. */
+           if (ADD_REF(tbl) <= 0) {
+               tbl->active = 1;                /* XXX just in case */
+               (void) sigdelset(&rpmsqCaught, tbl->signum);
+               sa.sa_flags = 0;
+               sigemptyset (&sa.sa_mask);
+               sa.sa_handler = (handler != NULL ? handler : tbl->handler);
+               if (sigaction(tbl->signum, &sa, &tbl->oact) < 0) {
+                   SUB_REF(tbl);
+                   break;
+               }
+           }
+       } else {                                /* Disable. */
+           if (SUB_REF(tbl) <= 0) {
+               tbl->active = 0;                /* XXX just in case */
+               if (sigaction(tbl->signum, &tbl->oact, NULL) < 0)
+                   break;
+           }
+       }
+       ret = tbl->active;
+       break;
+    }
+    DO_UNLOCK ();
+    return ret;
+}
+
+/**
+ * SIGCHLD cancellation handler.
+ */
+static void
+sigchld_cancel (void *arg)
+{
+    pid_t child = *(pid_t *) arg;
+    pid_t result;
+
+    (void) kill(child, SIGKILL);
+
+    do {
+       result = waitpid(child, NULL, 0);
+    } while (result == (pid_t)-1 && errno == EINTR);
+
+    DO_LOCK ();
+    if (SUB_REF (rpmsigTbl_sigchld) == 0) {
+       (void) rpmsqEnable(-SIGQUIT, NULL);
+       (void) rpmsqEnable(-SIGINT, NULL);
+    }
+    DO_UNLOCK ();
+}
+
+/**
+ * Execute a command, returning its status.
+ */
+int
+rpmsqExecve (const char ** argv)
+{
+    int oldtype;
+    int status = -1;
+    pid_t pid;
+    pid_t result;
+    sigset_t newMask, oldMask;
+
+    DO_LOCK ();
+    if (ADD_REF (rpmsigTbl_sigchld) == 0) {
+       if (rpmsqEnable(SIGINT, NULL) < 0) {
+           SUB_REF (rpmsigTbl_sigchld);
+           goto out;
+       }
+       if (rpmsqEnable(SIGQUIT, NULL) < 0) {
+           SUB_REF (rpmsigTbl_sigchld);
+           goto out_restore_sigint;
+       }
+    }
+    DO_UNLOCK ();
+
+    sigemptyset (&newMask);
+    sigaddset (&newMask, SIGCHLD);
+    if (sigprocmask (SIG_BLOCK, &newMask, &oldMask) < 0) {
+       DO_LOCK ();
+       if (SUB_REF (rpmsigTbl_sigchld) == 0)
+           goto out_restore_sigquit_and_sigint;
+       goto out;
+    }
+
+    CLEANUP_HANDLER(sigchld_cancel, &pid, &oldtype);
+
+    pid = fork ();
+    if (pid < (pid_t) 0) {             /* fork failed.  */
+       goto out;
+    } else if (pid == (pid_t) 0) {     /* Child. */
+
+       /* Restore the signals.  */
+       (void) sigaction (SIGINT, &rpmsigTbl_sigint->oact, NULL);
+       (void) sigaction (SIGQUIT, &rpmsigTbl_sigquit->oact, NULL);
+       (void) sigprocmask (SIG_SETMASK, &oldMask, NULL);
+
+       /* Reset rpmsigTbl lock and refcnt. */
+       INIT_LOCK ();
+
+       (void) execve (argv[0], (char *const *) argv, environ);
+       _exit (127);
+    } else {                           /* Parent. */
+       do {
+           result = waitpid(pid, &status, 0);
+       } while (result == (pid_t)-1 && errno == EINTR);
+       if (result != pid)
+           status = -1;
+    }
+
+    CLEANUP_RESET(0, oldtype);
+
+    DO_LOCK ();
+    if ((SUB_REF (rpmsigTbl_sigchld) == 0 &&
+        (rpmsqEnable(-SIGINT, NULL) < 0 || rpmsqEnable (-SIGQUIT, NULL) < 0))
+      || sigprocmask (SIG_SETMASK, &oldMask, (sigset_t *) NULL) != 0)
+    {
+       status = -1;
+    }
+    goto out;
+
+out_restore_sigquit_and_sigint:
+    (void) rpmsqEnable(-SIGQUIT, NULL);
+out_restore_sigint:
+    (void) rpmsqEnable(-SIGINT, NULL);
+out:
+    DO_UNLOCK ();
+    return status;
+}
diff --git a/rpmio/rpmsq.h b/rpmio/rpmsq.h
new file mode 100644 (file)
index 0000000..4fa96a7
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef        H_RPMSQ
+#define        H_RPMSQ
+
+/** \ingroup rpmio
+ * \file rpmio/rpmsq.h
+ *
+ */
+
+#include <signal.h>
+#include <sys/signal.h>
+#include <search.h>
+
+typedef struct rpmsig_s * rpmsig;
+
+typedef struct rpmsqElem * rpmsq;
+
+/**
+ * SIGCHLD queue element.
+ */
+struct rpmsqElem {
+    struct rpmsqElem * q_forw; /*!< for use by insque(3)/remque(3). */
+    struct rpmsqElem * q_back;
+    pid_t child;               /*!< Currently running child. */
+    pid_t reaped;              /*!< Reaped waitpid(3) return. */
+    int status;                        /*!< Reaped waitpid(3) status. */
+};
+
+/*@unchecked@*/
+extern rpmsq rpmsqQueue;
+
+/*@unchecked@*/
+extern sigset_t rpmsqCaught;
+
+#ifdef __cplusplus
+{
+#endif
+
+/**
+ */
+void Insque(/*@null@*/ void * elem, /*@null@*/ void * prev)
+       /*@globals rpmsqQueue @*/
+       /*@modifies elem, rpmsqQueue @*/;
+
+/**
+ */
+void Remque(/*@null@*/ void * elem)
+       /*@modifies elem @*/;
+
+/**
+ */
+void rpmsqHandler(int signum)
+       /*@globals rpmsqCaught, fileSystem @*/
+       /*@modifies rpmsqCaught, fileSystem @*/;
+
+/**
+ * Enable or disable a signal handler.
+ * @param signum       signal to enable (or disable if negative)
+ * @param handler      signal handler (or NULL to use rpmsqHandler())
+ * @return             no. of refs, -1 on error
+ */
+int rpmsqEnable(int signum, /*@null@*/ sighandler_t handler)
+       /*@globals rpmsqCaught, fileSystem, internalState @*/
+       /*@modifies rpmsqCaught, fileSystem, internalState @*/;
+
+/**
+ * Execute a command, returning its status.
+ */
+int
+rpmsqExecve (const char ** argv)
+       /*@*/;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_RPMSQ */