NetBSD-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

signal handling problem



Hi,
   can anyone tell me whats wrong with the following code fragment?
I've trimmed out the guts of the code and just left the signal and process 
setup and handling (If you want to see the whole thing its cnid_metad.c 
from the netatalk 2.1.2 release).

As written it fails to reap children (on 5.1_RC3) but if you remove the 
"if (sigchild)" prior to the "while ((pid = waitpid..." it works.

cheers
mark


static volatile sig_atomic_t sigchild = 0;

struct server {
    char  *name;
    pid_t pid;
    int control_fd;               /* file descriptor to child cnid_dbd 
process */
};

static struct server srv[MAXVOLS];


/* -------------------- */
static int maybe_start_dbd(char *dbdpn, char *dbdir, char *usockfn)
{
    pid_t pid;
    struct server *up;

    up = test_usockfn(dbdir);
    if (up && up->pid) {
        /* we already have a process, send our fd */
        if (send_cred(up->control_fd, rqstfd) < 0) {
            /* FIXME */
            return -1;
        }
        return 0;
    }

 
    if ((pid = fork()) < 0) {
        return -1;
    }
    if (pid == 0) {
         ret = execlp(dbdpn, dbdpn, dbdir, buf1, buf2, logconfig, NULL);
         exit(0);
     }
    /*
     *  Parent.
     */
    up->pid = pid;
    return 0;
}

/* ------------------ */
static void catch_child(int sig _U_) 
{
    sigchild = 1;
}

/* ----------------------- */
static void set_signal(void)
{
    struct sigaction sv;
    sigset_t set;

    signal(SIGPIPE, SIG_IGN);

    sv.sa_handler = catch_child;
    sv.sa_flags = SA_NOCLDSTOP;
    sigemptyset(&sv.sa_mask);
    if (sigaction(SIGCHLD, &sv, NULL) < 0) {
        LOG(log_error, logtype_cnid, "cnid_metad: sigaction: %s", 
strerror(errno));
        exit(1);
    }
    /* block everywhere but in pselect */
    sigemptyset(&set);
    sigaddset(&set, SIGCHLD);
    sigprocmask(SIG_BLOCK, &set, NULL);
}

int usockfd_check(int sockfd, const sigset_t *sigset)
{
    int fd;
    socklen_t size;
    fd_set readfds;
    int ret;
    struct timeval tv;
     
    FD_ZERO(&readfds);
    FD_SET(sockfd, &readfds);

    if ((ret = pselect(sockfd + 1, &readfds, NULL, NULL, NULL, sigset)) < 
0) {
        if (errno == EINTR)
            return 0;
        return -1;
    }
}

/* ------------------ */
int main(int argc, char *argv[])
{
    pid_t pid;
    int   status;
    int    ret;
    sigset_t set;


    set_signal();

    sigemptyset(&set);
    sigprocmask(SIG_SETMASK, NULL, &set);
    sigdelset(&set, SIGCHLD);

    while (1) {
        rqstfd = usockfd_check(srvfd, &set);
        /* Collect zombie processes and log what happened to them */
        if (sigchild) while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
            for (i = 0; i < MAXVOLS; i++) {
                if (srv[i].pid == pid) {
                    srv[i].pid = 0;
                    break;
                }
            }
            if (WIFEXITED(status)) {
                LOG(log_info, logtype_cnid, "cnid_dbd pid %i exited with 
exit code %i",
                    pid, WEXITSTATUS(status));
            }
            else if (WIFSIGNALED(status)) {
                LOG(log_info, logtype_cnid, "cnid_dbd pid %i exited with 
signal %i",
                    pid, WTERMSIG(status));
            }
            sigchild = 0;
        }
        if (rqstfd <= 0)
            continue;

        maybe_start_dbd(dbdpn, dbdir, dbp->usock_file);

    }
}


Home | Main Index | Thread Index | Old Index