Date: Wed, 10 Feb 2010 12:44:57 +0530 From: Naveen Gujje <gujjenaveen@gmail.com> To: freebsd-hackers@freebsd.org Subject: System() returning ECHILD error on FreeBSD 7.2 Message-ID: <39c945731002092314u4a8fd100q69c0735a11e9063a@mail.gmail.com>
next in thread | raw e-mail | index | archive | help
Hi, We have a web proxy (running on FreeBSD 7.2-RELEASE-p2), where we register the SIGCHLD handler as follows: signal(SIGCHLD, SigChildHandler); void SigChildHandler(int sig) { pid_t pid; /* get status of all dead procs */ do { int procstat; pid = waitpid(-1, &procstat, WNOHANG); if (pid < 0) { if (errno == EINTR) continue; /* ignore it */ else { if (errno != ECHILD) perror("getting waitpid"); pid = 0; /* break out */ } } else if (pid != 0) syslog(LOG_INFO, "child process %d completed", (int) pid); } while (pid); signal(SIGCHLD, SigChildHandler); } And, in some other part of the code, we call system() to add an ethernet interface. This system() call is returning -1 with errno set to ECHILD, though the passed command is executed successfully. I have noticed that, the problem is observed only after we register SigChildHandler. If I have a simple statement like system("ls") before and after the call to signal(SIGCHLD, SigChildHandler), the call before setting signal handler succeeds without errors and the call after setting signal handler returns -1 with errno set to ECHILD. Here, I believe that within the system() call, the child exited before the parent got a chance to call _wait4 and thus resulted in ECHILD error. But, for the child to exit without notifying the parent, SIGCHLD has to be set to SIG_IGN in the parent and this is not the case, because we are already setting it to SigChildHandler. If I set SIGCHLD to SIG_DFL before calling system() then i don't see this problem. I would like to know how setting SIGCHLD to SIG_DFL or SigChildHanlder is making the difference. Can someone please help me out? [Note: Replacing signal() with sigaction() doesn't help either.] Following is the code for system() call cat /usr/src/lib/libc/stdlib/system.c int __system(command) const char *command; { pid_t pid, savedpid; int pstat; struct sigaction ign, intact, quitact; sigset_t newsigblock, oldsigblock; if (!command) /* just checking... */ return(1); /* * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save * existing signal dispositions. */ ign.sa_handler = SIG_IGN; (void)sigemptyset(&ign.sa_mask); ign.sa_flags = 0; (void)_sigaction(SIGINT, &ign, &intact); (void)_sigaction(SIGQUIT, &ign, &quitact); (void)sigemptyset(&newsigblock); (void)sigaddset(&newsigblock, SIGCHLD); (void)_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); switch(pid = fork()) { case -1: /* error */ break; case 0: /* child */ /* * Restore original signal dispositions and exec the command. */ (void)_sigaction(SIGINT, &intact, NULL); (void)_sigaction(SIGQUIT, &quitact, NULL); (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL); _exit(127); default: /* parent */ savedpid = pid; do { pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0); } while (pid == -1 && errno == EINTR); break; } (void)_sigaction(SIGINT, &intact, NULL); (void)_sigaction(SIGQUIT, &quitact, NULL); (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); return(pid == -1 ? -1 : pstat); } Thanks, Naveen
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?39c945731002092314u4a8fd100q69c0735a11e9063a>