signal(SIGCHLD,SIG_IGN) function is not compatible with LINUX,SCO UNIX ...

signal(SIGCHLD,SIG_IGN) function is not compatible with LINUX,SCO UNIX ...

Post by cric » Wed, 19 Aug 1998 04:00:00



Hi :
    I am writting a daemon program on FREE BSD. For some reason I need
to fork a child process to execution some special function. I found the FREE
BSD signal(SIGCHLD,SIG_IGN) function is not compatible with
SCO UNIX,LINUX or SUN SOLARIS. When my child process exit.
FREE BSD left my child process on Z+ state. This will occupy a process
resource. I tested my program on SCO UNIX,LINUX and SOLARIS. All
of them won't left my child process to Z+ state.
Is there anyone who knows how to solve this problem on FREE BSD ?
Any hint or answer will be helpful for me.
                        Thanks            Crick.

The following is a short test program on FREE BSD. If anyone has interest
in my question. He can use these two program to check and test it.

/* parent test program */
#include        <sys/types.h>
#include        <sys/socket.h>
#include        <netinet/in.h>
#include        <netdb.h>
#include        <stdlib.h>
#include        <stdio.h>
#include        <errno.h>
#include        <string.h>
#include        <unistd.h>
#include        <fcntl.h>
#include        <signal.h>

void main(argc, argv)
int     argc;
char *  argv[];
{
 int  i,flag;
 pid_t  pid;
 char  buf[256];

 signal(SIGCHLD,SIG_IGN);
 sprintf(buf,"./child");
 if (fork() == 0) {
     execl(buf,buf,0);
        }
 printf("press <enter> to exit...\n");
 getchar();
 printf("test complete\n");

Quote:}

/* child test program */
#include        <sys/types.h>
#include        <sys/socket.h>
#include        <netinet/in.h>
#include        <netdb.h>
#include        <stdlib.h>
#include        <stdio.h>
#include        <errno.h>
#include        <string.h>
#include        <unistd.h>
#include        <fcntl.h>
#include        <signal.h>
void main(argc, argv)
int     argc;
char *  argv[];
{
 printf("child process...\n");
 exit(0);
Quote:}

 
 
 

signal(SIGCHLD,SIG_IGN) function is not compatible with LINUX,SCO UNIX ...

Post by Jon C. Snade » Wed, 19 Aug 1998 04:00:00




> # Hi :
> #     I am writting a daemon program on FREE BSD. For some reason I need
> # to fork a child process to execution some special function. I found the FREE
> # BSD signal(SIGCHLD,SIG_IGN) function is not compatible with
> # SCO UNIX,LINUX or SUN SOLARIS. When my child process exit.
> # FREE BSD left my child process on Z+ state. This will occupy a process
> # resource. I tested my program on SCO UNIX,LINUX and SOLARIS. All
> # of them won't left my child process to Z+ state.
> # Is there anyone who knows how to solve this problem on FREE BSD ?
> # Any hint or answer will be helpful for me.

> Don't ignore the signal but catch it and wait for all children which may
> have terminated.  Also, 3.0 now supports the flag SA_NOCLDWAIT so you
> don't get zombies.  You can use it with sigaction.

The System V semantics of SIGCLD are different from those of other
signals in that explicitly setting the disposition to SIG_IGN will
prevent zombies.  Many feel this is a questionable practice because of
the compatibility issue (see Stevens' _Advanced Programming in the UNIX
Environment_, e.g.).  BSD derived systems have never supported this
bug|feature.  As the previous responder (Gabor) pointed out, FreeBSD
does this in the ``correct'' way via SA_NOCLDWAIT.  Unfortunately for
Sys V, the overloaded semantics for SIG_IGN of SIGCLD were put in place
when all they had was the old signal() function, so there was no
alternative way of specifying the desired action.

Jon Snader

 
 
 

signal(SIGCHLD,SIG_IGN) function is not compatible with LINUX,SCO UNIX ...

Post by cric » Thu, 20 Aug 1998 04:00:00


Dear Gabor :
    Thanks for your advice, but my daemon program can't wail even for just
    30 seconds. And my child process may take a few minutes before exit.
    I'll try your advice not for my daemon program but just to make clear
    whether FREE BSD can prevent from zombies.
                            Thanks.                        Crick.
Gabor ???g??31 ...

># Hi :
>#     I am writting a daemon program on FREE BSD. For some reason I need
># to fork a child process to execution some special function. I found the
FREE
># BSD signal(SIGCHLD,SIG_IGN) function is not compatible with
># SCO UNIX,LINUX or SUN SOLARIS. When my child process exit.
># FREE BSD left my child process on Z+ state. This will occupy a process
># resource. I tested my program on SCO UNIX,LINUX and SOLARIS. All
># of them won't left my child process to Z+ state.
># Is there anyone who knows how to solve this problem on FREE BSD ?
># Any hint or answer will be helpful for me.

>Don't ignore the signal but catch it and wait for all children which may
>have terminated.  Also, 3.0 now supports the flag SA_NOCLDWAIT so you
>don't get zombies.  You can use it with sigaction.

 
 
 

signal(SIGCHLD,SIG_IGN) function is not compatible with LINUX,SCO UNIX ...

Post by cric » Thu, 20 Aug 1998 04:00:00


Dear Snader :
    Do you means it's impossible for me to prevent from zombies on my case ?
If so, I think I'll give up FREE BSD and announce that I can't support FREE
BSD, also BSDI.
                Thanks for telling me it.                            Crick.




>> # Hi :
>> #     I am writting a daemon program on FREE BSD. For some reason I need
>> # to fork a child process to execution some special function. I found the
FREE
>> # BSD signal(SIGCHLD,SIG_IGN) function is not compatible with
>> # SCO UNIX,LINUX or SUN SOLARIS. When my child process exit.
>> # FREE BSD left my child process on Z+ state. This will occupy a process
>> # resource. I tested my program on SCO UNIX,LINUX and SOLARIS. All
>> # of them won't left my child process to Z+ state.
>> # Is there anyone who knows how to solve this problem on FREE BSD ?
>> # Any hint or answer will be helpful for me.

>> Don't ignore the signal but catch it and wait for all children which may
>> have terminated.  Also, 3.0 now supports the flag SA_NOCLDWAIT so you
>> don't get zombies.  You can use it with sigaction.

>The System V semantics of SIGCLD are different from those of other
>signals in that explicitly setting the disposition to SIG_IGN will
>prevent zombies.  Many feel this is a questionable practice because of
>the compatibility issue (see Stevens' _Advanced Programming in the UNIX
>Environment_, e.g.).  BSD derived systems have never supported this
>bug|feature.  As the previous responder (Gabor) pointed out, FreeBSD
>does this in the ``correct'' way via SA_NOCLDWAIT.  Unfortunately for
>Sys V, the overloaded semantics for SIG_IGN of SIGCLD were put in place
>when all they had was the old signal() function, so there was no
>alternative way of specifying the desired action.

>Jon Snader

 
 
 

signal(SIGCHLD,SIG_IGN) function is not compatible with LINUX,SCO UNIX ...

Post by Peter da Sil » Thu, 20 Aug 1998 04:00:00



>Dear Gabor :
>    Thanks for your advice, but my daemon program can't wail even for just
>    30 seconds. And my child process may take a few minutes before exit.
>    I'll try your advice not for my daemon program but just to make clear
>    whether FREE BSD can prevent from zombies.

Funny, I just had this exact same discussion with one of my users. The system
call "wait" doesn't wait for a time period, rather it waits for all children
to exit before returning. I realise the name can be confusing.

Anyway, there's a trick you can do:

  switch(fork()) {
    default: wait(); break;  /* wait for dead kid */
    case -1: perror("fork()"); break; /* stillborn, complain */
    case 0: /* first child */
      switch(fork()) {
        default: exit(0); /* suicide so parent gets on with its life */
        case -1: perror("fork()"); exit(-1); /* dang! */
        case 0: /* Now I'm in an orphan process owned by init */
          daemon_stuff_goes_here;
          exit(0); /* Give up my status to the master daemon */
      }
  }

This is about the most portable way to keep from spawning zombies.

--

  `-_-' "It takes 5 NT servers to offer the performance and availability
   'U`    of a single UNIX server" -- Network Computing, July 15 1998.

 
 
 

signal(SIGCHLD,SIG_IGN) function is not compatible with LINUX,SCO UNIX ...

Post by Patrick M. Hause » Thu, 20 Aug 1998 04:00:00



> Dear Snader :
>     Do you means it's impossible for me to prevent from zombies on my case ?
> If so, I think I'll give up FREE BSD and announce that I can't support FREE
> BSD, also BSDI.
>                 Thanks for telling me it.                            Crick.

Of course you can prevent zomnbies. Every network server that forks
for incoming connections does it.

What he meant to tell you is, it's not done with _one_ line of code,
because that's not the "right thing" [tm].

You need a couple of lines, but nothing too complicated, really.
It's all in Stevens, Advanced Programming in the Unix Environment.

I don't have this at hand - otherwise I'd even type it in for you,
because I don't like someone dropping BSD for no reason ;-)

Have a look at that book, and you'll be fine. No zombies.

Patrick

P.S. And, no, your server doesn't have to "wait". It must call the
wait() system call from time to time, but this can be done in a way
that returns immediately.

 
 
 

signal(SIGCHLD,SIG_IGN) function is not compatible with LINUX,SCO UNIX ...

Post by Jon C. Snade » Thu, 20 Aug 1998 04:00:00



>     Do you means it's impossible for me to prevent from zombies on my case ?

Of course not.  I was only explaining why the behavior of SIGCLD/SIGCHLD
differs between SysV and BSD systems (and note that what I said applies
to BSD derived systems in general, not just FreeBSD and BSDI).  To
prevent zombies, you do what Gabor suggested--catch the SIGCHLD and call
wait or waitpid.  Note that this does *not* cause the parent to block,
because there is a child waiting to be reaped (otherwise you wouldn't
have gotten the SIGCHLD signal).  I usually use waitpid with the WHOHANG
option so that I can call it repeatedly until it reports that no further
children have died.

Quote:> If so, I think I'll give up FREE BSD and announce that I can't support FREE
> BSD, also BSDI.

You'll be giving up more than FreedBSD and BSDI.  As I said above, you
get this same behavior on all BSD derived systems.  Using wait/waitpid
as I outlined above works for both BSD and SysV systems--that is why it
is the preferred method.  It's portable to both flavors of UNIX, while
depending on the SIG_IGN trick is not.

Jon Snader

 
 
 

signal(SIGCHLD,SIG_IGN) function is not compatible with LINUX,SCO UNIX ...

Post by Matt Dill » Thu, 20 Aug 1998 04:00:00





:>>Dear Gabor :
:>>    Thanks for your advice, but my daemon program can't wail even for just
:>>    30 seconds. And my child process may take a few minutes before exit.
:>>    I'll try your advice not for my daemon program but just to make clear
:>>    whether FREE BSD can prevent from zombies.
:>
:>Funny, I just had this exact same discussion with one of my users. The system
:>call "wait" doesn't wait for a time period, rather it waits for all children
:>to exit before returning. I realise the name can be confusing.
:>
:>Anyway, there's a trick you can do:
:>
:>  switch(fork()) {
:>    default: wait(); break;  /* wait for dead kid */
:>    case -1: perror("fork()"); break; /* stillborn, complain */
:>    case 0: /* first child */
:>      switch(fork()) {
:>        default: exit(0); /* suicide so parent gets on with its life */
:>        case -1: perror("fork()"); exit(-1); /* dang! */
:>        case 0: /* Now I'm in an orphan process owned by init */
:>          daemon_stuff_goes_here;
:>          exit(0); /* Give up my status to the master daemon */
:>      }
:>  }
:>
:>This is about the most portable way to keep from spawning zombies.
:>
:>--

:>  `-_-' "It takes 5 NT servers to offer the performance and availability
:>   'U`    of a single UNIX server" -- Network Computing, July 15 1998.

    Ugh.  

    I think Gabor's confusion is that he thinks that since wait() blocks,
    there is no way to reap the children without creating delays in his
    main loop.

    There are several non-blocking solutions available.  The one that I have
    found to be the *most* portable between SysV and BSD systems has been
    waitpid().

    The simple code would be like this:

        void reapChildren(int sigNo);

        ...
        main( ... ) {
            signal(SIGCHLD, reapChildren);
             ...
        }

        void
        reapChildren(int sigNo)
        {
            /*
             * re-install signal handler.  Doesn't hurt in bsd, required by
             * sysv.
             */
            signal(SIGCHLD, reapChildren);
            /*
             * reap any children ready to be reaped, then return from the
             * signal handler.
             */
            while (waitpid(-1, NULL, WNOHANG) > 0)
                ;
        }

    It is not the most efficient code.. you can do a whole lot better with
    sigaction(), but it works and it's portable.  The only thing you have
    to deal with is that on some systems the signal function is expected
    to return an int rather then be a void function.  The use of wait3()
    verses waitpid() also works.  wait4() is typically not portable.
    waitpid() is usually more portable then wait3().

    What peter has done at the top is another solution... it's called a double
    fork.  You fork the first child.  The first child's parent is the orignal
    parent.  But then you have the first child fork a *second* child and then
    the first child exits.   The second child's parent is the first child until
    the first child exits, then it's parent becomes init.  The original parent
    simply does a synchronous wait on the first child which is essentially
    non (or very short)-blocking because the first child exits the instant
    it forks off the second chlid.  Personally, I do not like this method
    because a double fork() is relatively expensive.  sigaction() is also
    reasonably portable amoungst the machines that support it... most modern
    machines do, though some machines might implement flags that others do
    not.  That is relatively easy to deal with using #ifdef's though.

    Beyond that, Gabor needs to learn a bit more UNIX programming.  But I
    sure wouldn't let a few lines of code stop me from making a program
    work across a wider spectrum of machines!

                                                -Matt

--
    Matthew Dillon  Engineering, HiWay Technologies, Inc. & BEST Internet
                    Communications

 
 
 

signal(SIGCHLD,SIG_IGN) function is not compatible with LINUX,SCO UNIX ...

Post by Matt Dill » Thu, 20 Aug 1998 04:00:00







:># :>>Dear Gabor :
:>
:>crick is thanking for my advice.  He was the one who asked the question.

    ooops, sorry, I meant Crick.  Not Gabor.

                                        -Matt

--
    Matthew Dillon  Engineering, HiWay Technologies, Inc. & BEST Internet
                    Communications

 
 
 

signal(SIGCHLD,SIG_IGN) function is not compatible with LINUX,SCO UNIX ...

Post by Rahul Dhe » Thu, 20 Aug 1998 04:00:00



Quote:>    void reapChildren(int sigNo);
>    ...
>    main( ... ) {
>        signal(SIGCHLD, reapChildren);
>         ...
>    }
>    void
>    reapChildren(int sigNo)
>    {
>        /*
>         * re-install signal handler.  Doesn't hurt in bsd, required by
>         * sysv.
>         */
>        signal(SIGCHLD, reapChildren);
>        /*
>         * reap any children ready to be reaped, then return from the
>         * signal handler.
>         */
>        while (waitpid(-1, NULL, WNOHANG) > 0)
>            ;
>    }
>    It is not the most efficient code.. you can do a whole lot better with
>    sigaction(), but it works and it's portable.

This ought to be a standard library function:

     main(...) {
        reapchildren(1);        /* enable automatic reaping of children */
        ...
     }

Then every time this question is asked we can just say "easy, just call
reapchildren(1) once".  Calling it as reapchildren(0) would presumably
disable this and allow zombies to accumulate unless the user explicitly
does the wait().

SysV fanatics can redefine reapdhilcren() to install the SIG_IGN handler
for SIGCHLD.
--

 
 
 

signal(SIGCHLD,SIG_IGN) function is not compatible with LINUX,SCO UNIX ...

Post by Matt Dill » Thu, 20 Aug 1998 04:00:00




:..
:>
:>    The simple code would be like this:
:>
:>   void reapChildren(int sigNo);
:>
:>   ...
:>   main( ... ) {
:>       signal(SIGCHLD, reapChildren);
:>        ...
:>   }
:>
:>   void
:>   reapChildren(int sigNo)
:>   {
:>       /*
:>        * re-install signal handler.  Doesn't hurt in bsd, required by
:>        * sysv.
:>        */
:>       signal(SIGCHLD, reapChildren);
:>       /*
:>        * reap any children ready to be reaped, then return from the
:>        * signal handler.
:>        */
:>       while (waitpid(-1, NULL, WNOHANG) > 0)
:>           ;
:>   }

    Well, it appears my example isn't as portable as I thought... SysV
    apparently barfs on it due to the re-arming of the signal prior to
    the reaping of the children.   The obvious answer, re-arming after
    the waitpid() loop ought to work, but isn't good either because it can
    cause recursive stacking of multiple signal frames.

    I guess the correct answer is to use the sigaction() call after all
    to install a signal handler that doesn't need to be re-armed (presumably
    doing it's own signal blocking on entry and unblocking on exit), or
    to use the sigaction() call to set SA_NOCLDWAIT on SIGCHLD.

                                                -Matt

--
    Matthew Dillon  Engineering, HiWay Technologies, Inc. & BEST Internet
                    Communications

 
 
 

signal(SIGCHLD,SIG_IGN) function is not compatible with LINUX,SCO UNIX ...

Post by John Saunder » Fri, 21 Aug 1998 04:00:00


The only problem with this method is that every system call
in your program must check for the EINTR error code return
and then retry the system call. So if you had...

    len = read(...);

You would need to change it to...

    while (((len = read(...)) < 0) && (errno == EINTR))
        ;

Then do that for every system call in your program that
could possibly wait and it becomes a pain in the butt.

Why is this so? Because to service the SIGCHLD handler
the kernel must terminate the waiting system call and
return the EINTR error code. Linux has a special action
enabled with the sigaction() call to restart system calls
automatically for the specified signal. I don't know if
FreeBSD supports this in 2.2.x at least.

Cheers.
--   .   +-------------------------------------------------------+

/  Oz  \ | SCITEC LIMITED   Phone +61294289563  Fax +61294289933 |
\_,--\_/ | "By the time you make ends meet, they move the ends." |
      v  +-------------------------------------------------------+

 
 
 

signal(SIGCHLD,SIG_IGN) function is not compatible with LINUX,SCO UNIX ...

Post by Zeni » Fri, 21 Aug 1998 04:00:00


:     Well, it appears my example isn't as portable as I thought... SysV
:     apparently barfs on it due to the re-arming of the signal prior to
:     the reaping of the children.   The obvious answer, re-arming after
:     the waitpid() loop ought to work, but isn't good either because it can
:     cause recursive stacking of multiple signal frames.
        >snip<

        Is it just me, or are signals in general one of the most
        fundamentally flawed designs in Unix?

        Personally, I do my best do never touch signals.  They are bad
        news from every direction.  Unreliable, non-portable, buggy...
        If I can I do everything through other IPC means.  They seem
        so simple and so useful, yet there internal design on pretty
        much every Unix ever made is so flawed that simplicity is deadly
        and usefulness is questionable.  Anything useful is almost
        guaranteed to not be portable.

        When I can get away with it, I disable all signals I can.  I use
        double fork()ing to start my children when I can afford the
        expense and try not to fork() much.  Then I renable INT and TERM
        in the parent only for shutdown use only and do all other IPC
        (reconfig, reload, etc) through pipes.
--

BSD:  A psychoactive drug, popular in the 80s, probably developed at UC
Berkeley or thereabouts.  Similar in many ways to the prescription-only
medication called "System V", but infinitely more useful. (Or, at least,
more fun.)  The full chemical name is "Berkeley Standard Distribution".

 
 
 

signal(SIGCHLD,SIG_IGN) function is not compatible with LINUX,SCO UNIX ...

Post by Dom Mitchel » Fri, 21 Aug 1998 04:00:00



>         Is it just me, or are signals in general one of the most
>         fundamentally flawed designs in Unix?

Well, environment variables come close.  :-)
--
Dom Mitchell          -- Palmer & Harvey McLane