Re: Proposed Patch for Zombies Left by Dpi_start_dpid() in dpi.c

Jorge Arellano Cid <[email protected]>
Newsgroups gmane.comp.web.dillo.devel
Message-ID <[email protected]>
Hi Johannes, JG:

On Thu, Aug 29, 2013 at 09:13:49AM +0200, Johannes Hofmann wrote:
> Hi Jorge,
> 
> On Wed, Aug 28, 2013 at 08:48:35PM -0400, Jorge Arellano Cid wrote:
> > Hi,
> > 
> > On Wed, Aug 28, 2013 at 07:51:34PM +0200, Johannes Hofmann wrote:
> > > Hi JG,
> > > 
> > > On Tue, Aug 27, 2013 at 03:15:14PM -0400, JG wrote:
> > > > It seems that the dpid children forked by Dpi_start_dpid() in dpi.c
> > > > are not reaped when they terminate themselves after a period of
> > > > inactivity while the parent dillo process is still running.  The patch
> > > > below is simply to reap these zombies.  The SIGCHLD handler should
> > > > probably do more, but I am not yet familiar enough with Dillo to know
> > > > what.
> > > > 
> > > > I believe this patch adheres to the Dillo rules of coding style, but
> > > > am new to the list and a novice at Dillo patching.  And hence also
> > > > apologies to Jorge for this duplication of a previous communication by
> > > > private email (although with one small change to get the patch to
> > > > compile under OpenBSD as well as Linux).
> > > 
> > > I can reproduce the issue here by killing dpid manually.
> > > For me the following also fixes it:
> > > 
> > > diff -r 659dc205c377 src/dillo.cc
> > > --- a/src/dillo.cc    Wed Aug 21 11:42:38 2013 +0200
> > > +++ b/src/dillo.cc    Wed Aug 28 19:48:10 2013 +0200
> > > @@ -329,6 +329,7 @@
> > >  
> > >     // Some OSes exit dillo without this (not GNU/Linux).
> > >     signal(SIGPIPE, SIG_IGN);
> > > +   signal(SIGCHLD, SIG_IGN);
> > >  
> > >     /* Handle command line options */
> > >     opt_argv = dNew0(char*, numOptions(Options) + 1);
> > > 
> > > Can you please check whether it works for you too? It would have the
> > > advantage that we have all signal related stuff in one place.
> > 
> >   Oh,  I'm looking at it now too! 
> > For me this is an old TODO: with subtle issues lurking.
> > 
> > 
> >   Somehow, setting SIG_IGN to a child rings me wrong...  :-)
> > 
> > 
> >   After some digging (Manual page sigaction(2)):
> > 
> > ...
> > 
> > "A  child  created  via  fork(2)  inherits a copy of its parent's
> > signal  dispositions.  During  an  execve(2), the dispositions of
> > handled  signals  are  reset  to the default; the dispositions of
> > ignored signals are left unchanged."
> 
> I guess this is no problem, as dpid explicitely adds a signal
> handler for SIGCHLD again, but I'm happy if you take care of the
> whole issue :-)

  The attached program is a stress test for SIGCHLD. The idea is to
find a formula that works well even in such cases. IIRC both of you
have access to BSD machines so please test it there.

  The  program  spawns  255  children  which  sleep 5 seconds and
terminate generating a SIGCHLD avalanche, which should be handled
cleanly. It works OK in Debian.

    $gcc -W -Wall sigcld.c -o sigcld
    $./sigcld

  in another terminal (during the 5 secs. sleep window):

    $ps aux|grep sigcld

    (shows the long list)

  then while main is Sleeping 10 seconds:

    $ps aux|grep sigcld

    (shows only one sigcld process)

  after it exits:

    $ps aux|grep sigcld

    (no process left)

  TIA.

-- 
  Cheers
  Jorge.-

_______________________________________________
Dillo-dev mailing list
[email protected]
http://lists.auriga.wearlab.de/cgi-bin/mailman/listinfo/dillo-dev
sigcld.c (text/x-csrc, 2.2 KB)
#include <sys/types.h>
#include <sys/wait.h>
#include <wait.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

// SIGCHLD -------------------------------------------------------------------
static int gone = 0;


/*
 * Avoid dpid becoming a zombie.
 * Notes:
 *   . We let sigaction block SIGCHLD while in the handler.
 *   . Portability is not simple. e.g.
 *       http://www.faqs.org/faqs/unix-faq/faq/part3/section-13.html
 *       man sigaction, waitpid
 */
static void raw_sigchld2(int signum)
{
   pid_t pid;
   int status;

   while (1) {
      pid = waitpid(-1, &status, WNOHANG);
      if (pid > 0) {
         if (WIFEXITED(status))        /* normal exit */
            printf("e%d ", WEXITSTATUS(status));
         else if (WIFSIGNALED(status)) /* terminated by signal */
            printf("s%d ", WTERMSIG(status));
         ++gone;
      } else if (pid == 0 || errno == ECHILD) {
         break;
      } else {
         if (errno == EINTR)
            continue;
         perror("waitpid");
         break;
      }
   }
   ++signum; /* compiler happiness */
}

/*! Establish SIGCHLD handler */
static void est_sigchld(void)
{
   struct sigaction sigact;
   sigset_t set;

   (void) sigemptyset(&set);
   sigact.sa_handler = raw_sigchld2; /* our custom handler */
   sigact.sa_mask = set;             /* no aditional signal blocks */
   sigact.sa_flags = SA_NOCLDSTOP;   /* ignore stop/resume states */
   if (sigaction(SIGCHLD, &sigact, NULL) == -1) {
      perror("sigaction");
      exit(1);
   }
}



// Main ----------------------------------------------------------------------

int main(void)
{
   int i;
   pid_t child;

   /* Install our SIGCHLD handler */
   est_sigchld();

   for (i = 0; i < 256; ++i) {
      if ((child = fork()) < 0) {
         perror("fork");
         exit(-1);
      } else if (child == 0) {
         /* in child */
         sleep(5);
         break;
      } else {
         /* in parent */
         printf("num children = %d\n", i);
      }
   }
 
   if (child == 0) {
      /* in child */
      return 0;
   }
 
   /* In parent */
   while (gone < 256) {
      printf("%d ", gone);
      sleep(1);
   }

   printf("Sleeping 10 sec...\n");
   sleep(10);
   return 0;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.