os161-1.99
 All Data Structures
forktest.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 /*
00031  * forktest - test fork().
00032  *
00033  * This should work correctly when fork is implemented.
00034  *
00035  * It should also continue to work after subsequent assignments, most
00036  * notably after implementing the virtual memory system.
00037  */
00038 
00039 #include <unistd.h>
00040 #include <string.h>
00041 #include <stdlib.h>
00042 #include <stdio.h>
00043 #include <err.h>
00044 
00045 /*
00046  * This is used by all processes, to try to help make sure all
00047  * processes have a distinct address space.
00048  */
00049 static volatile int mypid;
00050 
00051 /*
00052  * Helper function for fork that prints a warning on error.
00053  */
00054 static
00055 int
00056 dofork(void)
00057 {
00058         int pid;
00059         pid = fork();
00060         if (pid < 0) {
00061                 warn("fork");
00062         }
00063         return pid;
00064 }
00065 
00066 /*
00067  * Check to make sure each process has its own address space. Write
00068  * the pid into the data segment and read it back repeatedly, making
00069  * sure it's correct every time.
00070  */
00071 static
00072 void
00073 check(void)
00074 {
00075         int i;
00076 
00077         mypid = getpid();
00078         
00079         /* Make sure each fork has its own address space. */
00080         for (i=0; i<800; i++) {
00081                 volatile int seenpid;
00082                 seenpid = mypid;
00083                 if (seenpid != getpid()) {
00084                         errx(1, "pid mismatch (%d, should be %d) "
00085                              "- your vm is broken!", 
00086                              seenpid, getpid());
00087                 }
00088         }
00089 }
00090 
00091 /*
00092  * Wait for a child process.
00093  *
00094  * This assumes dowait is called the same number of times as dofork
00095  * and passed its results in reverse order. Any forks that fail send
00096  * us -1 and are ignored. The first 0 we see indicates the fork that
00097  * generated the current process; that means it's time to exit. Only
00098  * the parent of all the processes returns from the chain of dowaits.
00099  */
00100 static
00101 void
00102 dowait(int nowait, int pid)
00103 {
00104         int x;
00105 
00106         if (pid<0) {
00107                 /* fork in question failed; just return */
00108                 return;
00109         }
00110         if (pid==0) {
00111                 /* in the fork in question we were the child; exit */
00112                 exit(0);
00113         }
00114 
00115         if (!nowait) {
00116                 if (waitpid(pid, &x, 0)<0) {
00117                         warn("waitpid");
00118                 }
00119                 else if (WIFSIGNALED(x)) {
00120                         warnx("pid %d: signal %d", pid, WTERMSIG(x));
00121                 }
00122                 else if (WEXITSTATUS(x) != 0) {
00123                         warnx("pid %d: exit %d", pid, WEXITSTATUS(x));
00124                 }
00125         }
00126 }
00127 
00128 /*
00129  * Actually run the test.
00130  */
00131 static
00132 void
00133 test(int nowait)
00134 {
00135         int pid0, pid1, pid2, pid3;
00136 
00137         /*
00138          * Caution: This generates processes geometrically.
00139          *
00140          * It is unrolled to encourage gcc to registerize the pids,
00141          * to prevent wait/exit problems if fork corrupts memory.
00142          */
00143 
00144         pid0 = dofork();
00145         putchar('0');
00146         check();
00147         pid1 = dofork();
00148         putchar('1');
00149         check();
00150         pid2 = dofork();
00151         putchar('2');
00152         check();
00153         pid3 = dofork();
00154         putchar('3');
00155         check();
00156 
00157         /*
00158          * These must be called in reverse order to avoid waiting
00159          * improperly.
00160          */
00161         dowait(nowait, pid3);
00162         dowait(nowait, pid2);
00163         dowait(nowait, pid1);
00164         dowait(nowait, pid0);
00165 
00166         putchar('\n');
00167 }
00168 
00169 int
00170 main(int argc, char *argv[])
00171 {
00172         int nowait=0;
00173 
00174         if (argc==2 && !strcmp(argv[1], "-w")) {
00175                 nowait=1;
00176         }
00177         else if (argc!=1 && argc!=0) {
00178                 warnx("usage: forktest [-w]");
00179                 return 1;
00180         }
00181         warnx("Starting.");
00182 
00183         test(nowait);
00184 
00185         warnx("Complete.");
00186         return 0;
00187 }
 All Data Structures