Newsgroups: comp.os.minix
Subject: Re: A fork() question
References: <7c1jmd$tvo$1@nnrp1.dejanews.com> <7c1tcg$ad1$1@nusku.cts.com>
Organization: Rochester Institute of Technology, Rochester, NY
From: aje9383@osfmail.isc.rit.edu (Andrew Erickson)
NNTP-Posting-Host: grace.isc.rit.edu
X-Original-NNTP-Posting-Host: grace.isc.rit.edu
Message-ID: <36e489b7.0@isc-newsserver.isc.rit.edu>
Date: 8 Mar 1999 21:38:47 -0500
X-Trace: 8 Mar 1999 21:38:47 -0500, grace.isc.rit.edu
Lines: 116
XPident: aje9383
X-Original-NNTP-Posting-Host: 129.21.3.100
XPident: Unknown
Path: star.cs.vu.nl!sun4nl!EU.net!news-peer1.sprintlink.net!news-in-east1.sprintlink.net!news.sprintlink.net!isc-newsserver.isc.rit.edu!aje9383
Xref: star.cs.vu.nl comp.os.minix:34927

In article <7c1tcg$ad1$1@nusku.cts.com>, Will Rose <cwr@cts.com> wrote:
>ajamajam@my-dejanews.com wrote:
>: Okay, this is the deal!  Playing with "fork"...  If I have this program:
>

Hmmm....(Program formatting changed to suit my personal preferences)
(NOTE TO OTHERS:  I will be attempting to interpret the output.  Consider
it a spoiler if you wish to figure it out on your own...)

>: void main () {
>: int x;
>: pid_t pid;
>
>:    for (x=1; x<=3; x++) {
>:       pid=fork();
>:       printf ("loop #%d, pid #%d\n", x, pid);
>:    }
>:    printf ("\n");
>: }
>
>: , and I'm getting the following result:

These are from the first process (call it PID 816 or something), which
starts up 817, 818, and 819.  We know that the parent is finishing before
the first one fork()d starts (PID 817) because we aren't getting pid=0.

>: loop #1, pid #817
>: loop #2, pid #818
>: loop #3, pid #819
>
And 816 exits here.  Apparently, 817 runs for awhile...

>: loop #1, pid #0          <-- enters from 816 here
>: loop #2, pid #820        <-- fork()s 820, 821
>: loop #3, pid #821
>
817 exits here.  Now, some strange things start happening....
>: loop #1, pid #817
>: loop #2, pid #0
>: loop #3, pid #822
>
#2 and #3 would make sense for either 818 or 820--we really don't know
which.  Line #1 should not exist...apparently--at least one wouldn't expect
it when first looking over the program.  (As it turns out, this is
from PID 818.)

Why does line #1 exist, you may well ask?  I suspect it has to do with the
implementation of the standard i/o libarary, which is carefully caching
output prior to flushing it at the exit of the program.  Thus, this stuff
was left in the stdout buffer, carefully copied (and added to) when the
fork() occured, and spat out when the process exited.

I do find it rather strange that the buffer isn't flushed on each printf,
however; I thought that was the default for standard output.  (At least,
under MacMinix 1.5, it is; ISTR that the standard library was at least
partly rewritten for 2.0, though.  Perhaps it's fully buffered when output
is redirected to a file by default now.)

>: loop #1, pid #0
>: loop #2, pid #0
>: loop #3, pid #823
>
And this is from 820, methinks--the first grandkid of the original process.

I won't bother typing all the stuff for the rest of the output, as it's
reasonably easy to figure out given the ideas above.

<Snip rest of output>

>: This is actually pretty kool!  Actually it is a nice to learn about how
>: processes work.  My take is that the first three loops of the original
>: process start a child each, 817-819.  (duh?!) Given that there is no
>: "exec" to start an independent process, each of the children don't go
>: anywhere else.  They seem to start another round of children. Then they
>: end up settling down with a pid of value "0," which is what we look for
>: when starting a new process.

Pretty much it.

>: Maybe I should have reviewed this a little bit more so I look less of a
>: smuck, but then again part of the fun of writing to the list will be lost. 
>: Either way, any words of wisdom?!

Okay, now test your knowledge.  Without peeking at the output, how many
processes, including the original invocation of the program, will eventually
exist?

Assuming there is no buffering, how many (non-blank) lines of output will be
produced?  How many loop #1's, #2's, and #3's?  Test this by setting the
output to be unbuffered (see setbuf() for help on doing that).

(Will Rose's comments:)
>
>The number of processes is limited by a #define in config.h, NR_PROCS.
>I suspect the standard limit is 32, so allowing for the initial shell,
>and anything else that may be running, you'll have a total number of
>forks in the high twenties.

Actually, this program isn't an infinite fork() bomb--with three iterations,
it shouldn't fill up the process table unless a whole lot is going on in the
background, assuming NR_PROCS is 32 or more.  I'd give the actual number,
but we don't want people cheating on the first homework question. :-)

Actually, this program could form the basis for a *really* *nice* assignment
for an operating systems class.  If it isn't an exercise from OS:D&I,
perhaps something like it should be added...you have to rather understand
how fork() operates to predict any characteristics, and have a pretty
thorough knowledge of the standard library to get it correct (or
approximately correct--one could reasonably argue that the actual output is
somewhat non-deterministic.)

Thanks for sharing this.
--Andrew Erickson, aje9383@cs.rit.edu
Amspay otnay esslay eyay ebay urriedbay inay amspay ourselfyay!


