[comp.unix.questions] Question on fork

farnham@spot.Colorado.EDU (Farnham David) (05/16/91)

I'm having trouble getting rid of processes which I've killed.
I have a situation where the main program calls a function which
fork()'s and exec()'s.  This function returns the pid of the
child to the main program.  The main program then kill()'s this child.

I don't seem to have any problem killing the child, but after several
iterations I run out of process space and I can no longer fork().
Could someone please shed some light on what I'm doing wrong.  Mild
flames are tolerable if I'm doing something REALLY stupid :-)

Using: Sun sparc 2, 4.1.1
Code follows:
----------------------------------------
#include <stdio.h>    /* this is main() and fun() */
#include <signal.h>

int fun();

main()
{
    int pid;

    while (1) {
        pid = fun();
        sleep(1);
        if ((kill(pid,SIGKILL)) == -1) {
            fprintf (stderr,"Kill failed\n");
            exit(1);
        }
    }
}

int fun()
{
    int pid;

    switch(pid = fork()) {
        case -1:
            fprintf (stderr,"Can't fork\n");
            break;
        case 0:
            execl("./tst","tst",(char *)NULL);
            fprintf (stderr,"Can't exec\n");
            break;
        default:
            return pid;
    }
}
----------------------------------------
#include <stdio.h>  /* this is tst.c */

main()
{
    puts ("in tst");
    while (1)
        ;
}
----------------------------------------

Dave Farnham
Ball Aerospace
Electro-Optical/Cryogenics Division
P.O. Box 1062
Boulder, CO  80306
{ farnham@spot.colorado.edu, farnham@handel.cs.colostate.edu }

subbarao@phoenix.Princeton.EDU (Kartik Subbarao) (05/16/91)

In article <1991May15.201821.15350@colorado.edu> farnham@spot.Colorado.EDU (Farnham David) writes:
>I'm having trouble getting rid of processes which I've killed.
>I have a situation where the main program calls a function which
>fork()'s and exec()'s.  This function returns the pid of the
>child to the main program.  The main program then kill()'s this child.
>
>I don't seem to have any problem killing the child, but after several
>iterations I run out of process space and I can no longer fork().
>Could someone please shed some light on what I'm doing wrong.  Mild
>flames are tolerable if I'm doing something REALLY stupid :-)

Most likely, the reason why you're running out of process space is because
you don't wait() for your children. You can kill your children 'till you're
blue in the face, and it won't help any. That's because when a process
dies, it becomes a zombie until someone waits for it. This means that it
takes up a space in the process table, though it's really not doing
anything. It's a simple fix:

>
>    while (1) {
>        pid = fun();
>        sleep(1);
>        if ((kill(pid,SIGKILL)) == -1) {
>            fprintf (stderr,"Kill failed\n");
>            exit(1);
>        }
		 wait(0); /* add this line in */
>	 }

Of course, if you're actually INTERESTED in what the kid returns, then you
should look at wait(2) to find out more variations on wait.


			-Kartik


--
internet% ypwhich

subbarao@phoenix.Princeton.EDU -| Internet
kartik@silvertone.Princeton.EDU (NeXT mail)  
SUBBARAO@PUCC.BITNET			          - Bitnet

weimer@garden.ssd.kodak.com (Gary Weimer (253-7796)) (05/16/91)

In article <azA8awz/XVBkw@idunno.Princeton.EDU>,
subbarao@phoenix.Princeton.EDU (Kartik Subbarao) writes:
|> In article <1991May15.201821.15350@colorado.edu>
farnham@spot.Colorado.EDU (Farnham David) writes:
|> >I'm having trouble getting rid of processes which I've killed.
|> >I have a situation where the main program calls a function which
|> >fork()'s and exec()'s.  This function returns the pid of the
|> >child to the main program.  The main program then kill()'s this child.
|> >
|> >I don't seem to have any problem killing the child, but after several
|> >iterations I run out of process space and I can no longer fork().
|> >Could someone please shed some light on what I'm doing wrong.  Mild
|> >flames are tolerable if I'm doing something REALLY stupid :-)
|> 
|> Most likely, the reason why you're running out of process space is because
|> you don't wait() for your children. You can kill your children 'till you're
|> blue in the face, and it won't help any. That's because when a process
|> dies, it becomes a zombie until someone waits for it. This means that it
|> takes up a space in the process table, though it's really not doing
|> anything. It's a simple fix:
|> 
|> >
|> >    while (1) {
|> >        pid = fun();
|> >        sleep(1);
|> >        if ((kill(pid,SIGKILL)) == -1) {
|> >            fprintf (stderr,"Kill failed\n");
|> >            exit(1);
|> >        }
|> 		 wait(0); /* add this line in */
|> >	 }

Is this all that's wrong with vi in SunOS??? Doing:

vi
!}fmt
:r!ps

produces (extras left out):

  PID TT STAT  TIME COMMAND
 4262 p5 S     0:00 vi
 4263 p5 Z     0:00 <defunct>
                    ^^^^^^^^^
With one of these for each shell run from within vi. Gets anoying when your
process table gets full...

weimer@ssd.kodak.com ( Gary Weimer )

gwyn@smoke.brl.mil (Doug Gwyn) (05/17/91)

In article <1991May15.201821.15350@colorado.edu> farnham@spot.Colorado.EDU (Farnham David) writes:
>I don't seem to have any problem killing the child, but after several
>iterations I run out of process space and I can no longer fork().

Sure -- processes continue to occupy slots in the process table,
and thus are counted against your process limit, until they are
successfully wait()ed on.  Kill()ing them just makes zombies out
of the processes; wait() lays them to rest.

gt0178a@prism.gatech.EDU (BURNS) (05/26/91)

in article <16177@smoke.brl.mil>, gwyn@smoke.brl.mil (Doug Gwyn) says:

> In article <1991May15.201821.15350@colorado.edu> farnham@spot.Colorado.EDU (Farnham David) writes:
>>I don't seem to have any problem killing the child, but after several
>>iterations I run out of process space and I can no longer fork().

> Sure -- processes continue to occupy slots in the process table,
> and thus are counted against your process limit, until they are
> successfully wait()ed on.  Kill()ing them just makes zombies out
> of the processes; wait() lays them to rest.

If the SIG_DFL for SIGCHLD is to discard the signal, why do you HAVE to
wait for the child? The only time I've had to wait under HP-UX for a child
is to guard against *transient* peaks of numbers of children - they would
eventually die anyway. Is this a SYSV/BSD diff? Thanx.
-- 
BURNS,JIM (returned student & Technology Dynamics staff member, an ATDC co.)
Georgia Institute of Technology, 30178 Georgia Tech Station,
Atlanta Georgia, 30332            | Internet: gt0178a@prism.gatech.edu
uucp:	  ...!{decvax,hplabs,ncar,purdue,rutgers}!gatech!prism!gt0178a

gwyn@smoke.brl.mil (Doug Gwyn) (05/27/91)

In article <29877@hydra.gatech.EDU> gt0178a@prism.gatech.EDU (BURNS) writes:
>If the SIG_DFL for SIGCHLD is to discard the signal, why do you HAVE to
>wait for the child?

I can't speak for HP-UX, but in general SIGCHLD/SIGCLD is pretty badly
botched.  In the original System V implementation, how you set SIGCLD
also determines the semantics for a subsequent wait() system call.  All
I can suggest is (a) leave SIGCLD alone, and (b) if you're trying to
use SIGCLD anyway, check the SPECIFIC system manual and be very careful.

In good old original UNIX, the only way to get rid of a zombie was to
wait() on it, and if its parent terminated, then init (Process #1) would
inherit it and IT would wait() on it.

mouse@thunder.mcrcim.mcgill.edu (der Mouse) (05/30/91)

In article <1991May15.215826.26327@athena.mit.edu>, jik@athena.mit.edu (Jonathan I. Kamens) writes:

> You need to wait on your children to get them to go away; until you
> do that, they're zombies.

>   Here's my occasionally posted article about that:

> Unfortunately, it's impossible to generalize how the death of child
> processes should behave, because the exact mechanism varies over the
> various flavors of Unix.  [...]

If you just want to fork children, don't want them to bother you when
they die, don't care about preserving precise parenthood relationships,
and don't care about the return status from the wait or resource usage
or anything of the sort, you *can* do *that* portably.  All you need to
do is fork and have the parent wait for the child explicitly, then have
the child fork again, with the second-level child doing the real work
and the first-level child dying immediately after the second fork.

This way, the parent has no children left, because its only child
exited.  When the intermediate process died, init (PID 1) inherited the
second child and will worry about doing the wait() when it dies.

Not that this is always appropriate, but sometimes it is.

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu