Home | History | Annotate | Download | only in doio
      1 /*
      2  * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
      3  *
      4  * This program is free software; you can redistribute it and/or modify it
      5  * under the terms of version 2 of the GNU General Public License as
      6  * published by the Free Software Foundation.
      7  *
      8  * This program is distributed in the hope that it would be useful, but
      9  * WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     11  *
     12  * Further, this software is distributed without any warranty that it is
     13  * free of the rightful claim of any third person regarding infringement
     14  * or the like.  Any license provided herein, whether implied or
     15  * otherwise, applies only to this software file.  Patent licenses, if
     16  * any, provided herein do not apply to combinations of this program with
     17  * other software, or any other product whatsoever.
     18  *
     19  * You should have received a copy of the GNU General Public License along
     20  * with this program; if not, write the Free Software Foundation, Inc.,
     21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     22  *
     23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
     24  * Mountain View, CA  94043, or:
     25  *
     26  * http://www.sgi.com
     27  *
     28  * For further information regarding this notice, see:
     29  *
     30  * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
     31  */
     32 /**************************************************************
     33  *
     34  *    OS Testing - Silicon Graphics, Inc.
     35  *
     36  *    FUNCTION NAME     : forker
     37  *			  background
     38  *
     39  *    FUNCTION TITLE    : fork desired number of copies of the current process
     40  *			  fork a process and return control to caller
     41  *
     42  *    SYNOPSIS:
     43  *      int forker(ncopies, mode, prefix)
     44  *      int ncopies;
     45  *	int mode;
     46  *	char *prefix;
     47  *
     48  *	int background(prefix);
     49  *	char *prefix;
     50  *
     51  *    AUTHOR            : Richard Logan
     52  *
     53  *    CO-PILOT(s)       : Dean Roehrich
     54  *
     55  *    INITIAL RELEASE   : UNICOS 8.0
     56  *
     57  *    DESIGN DESCRIPTION
     58  *	The background function will do a fork of the current process.
     59  *	The parent process will then exit, thus orphaning the
     60  *	child process.  Doing this will not nice the child process
     61  *	like executing a cmd in the background using "&" from the shell.
     62  *	If the fork fails and prefix is not NULL, a error message is printed
     63  *      to stderr and the process will exit with a value of errno.
     64  *
     65  *	The forker function will fork <ncopies> minus one copies
     66  *	of the current process.  There are two modes in how the forks
     67  *	will be done.  Mode 0 (default) will have all new processes
     68  *	be childern of the parent process.    Using Mode 1,
     69  *	the parent process will have one child and that child will
     70  *	fork the next process, if necessary, and on and on.
     71  *	The forker function will return the number of successful
     72  *	forks.  This value will be different for the parent and each child.
     73  *	Using mode 0, the parent will get the total number of successful
     74  *	forks.  Using mode 1, the newest child will get the total number
     75  *	of forks.  The parent will get a return value of 1.
     76  *
     77  *	The forker function also updates the global variables
     78  *	Forker_pids[] and Forker_npids.  The Forker_pids array will
     79  *      be updated to contain the pid of each new process.  The
     80  *	Forker_npids variable contains the number of entries
     81  *	in Forker_pids.  Note, not all processes will have
     82  *	access to all pids via Forker_pids.  If using mode 0, only the
     83  *	parent process and the last process will have all information.
     84  *      If using mode 1, only the last child process will have all information.
     85  *
     86  *	If the prefix parameter is not NULL and the fork system call fails,
     87  *      a error message will be printed to stderr.  The error message
     88  *      the be preceeded with prefix string.  If prefix is NULL,
     89  *      no error message is printed.
     90  *
     91  *    SPECIAL REQUIREMENTS
     92  *	None.
     93  *
     94  *    UPDATE HISTORY
     95  *      This should contain the description, author, and date of any
     96  *      "interesting" modifications (i.e. info should helpful in
     97  *      maintaining/enhancing this module).
     98  *      username     description
     99  *      ----------------------------------------------------------------
    100  *	rrl	    This functions will first written during
    101  *		the SFS testing days, 1993.
    102  *
    103  *    BUGS/LIMITATIONS
    104  *     The child pids are stored in the fixed array, Forker_pids.
    105  *     The array only has space for 4098 pids.  Only the first
    106  *     4098 pids will be stored in the array.
    107  *
    108  **************************************************************/
    109 
    110 #include <stdio.h>
    111 #include <errno.h>
    112 #include <unistd.h>		/* fork, getpid, sleep */
    113 #include <string.h>
    114 #include <stdlib.h>		/* exit */
    115 #include "forker.h"
    116 
    117 int Forker_pids[FORKER_MAX_PIDS];	/* holds pids of forked processes */
    118 int Forker_npids = 0;		/* number of entries in Forker_pids */
    119 
    120 /***********************************************************************
    121  *
    122  * This function will fork and the parent will exit zero and
    123  * the child will return.  This will orphan the returning process
    124  * putting it in the background.
    125  *
    126  * Return Value
    127  *   0 : if fork did not fail
    128  *  !0 : if fork failed, the return value will be the errno.
    129  ***********************************************************************/
    130 int background(char *prefix)
    131 {
    132 	switch (fork()) {
    133 	case -1:
    134 		if (prefix != NULL)
    135 			fprintf(stderr,
    136 				"%s: In %s background(), fork() failed, errno:%d %s\n",
    137 				prefix, __FILE__, errno, strerror(errno));
    138 		exit(errno);
    139 
    140 	case 0:		/* child process */
    141 		break;
    142 
    143 	default:
    144 		exit(0);
    145 	}
    146 
    147 	return 0;
    148 
    149 }				/* end of background */
    150 
    151 /***********************************************************************
    152  * Forker will fork ncopies-1 copies of self.
    153  *
    154  ***********************************************************************/
    155 int forker(int ncopies,
    156 	int mode,	/* 0 - all children of parent, 1 - only 1 direct child */
    157 	char *prefix)	/* if ! NULL, an message will be printed to stderr */
    158 			/* if fork fails. The prefix (program name) will */
    159 			/* preceed the message */
    160 {
    161 	int cnt;
    162 	int pid;
    163 	static int ind = 0;
    164 
    165 	Forker_pids[ind] = 0;
    166 
    167 	for (cnt = 1; cnt < ncopies; cnt++) {
    168 
    169 		switch (mode) {
    170 		case 1:	/* only 1 direct child */
    171 			if ((pid = fork()) == -1) {
    172 				if (prefix != NULL)
    173 					fprintf(stderr,
    174 						"%s: %s,forker(): fork() failed, errno:%d %s\n",
    175 						prefix, __FILE__, errno,
    176 						strerror(errno));
    177 				return 0;
    178 			}
    179 			Forker_npids++;
    180 
    181 			switch (pid) {
    182 			case 0:	/* child - continues the forking */
    183 
    184 				if (Forker_npids < FORKER_MAX_PIDS)
    185 					Forker_pids[Forker_npids - 1] =
    186 					    getpid();
    187 				break;
    188 
    189 			default:	/* parent - stop the forking */
    190 				if (Forker_npids < FORKER_MAX_PIDS)
    191 					Forker_pids[Forker_npids - 1] = pid;
    192 				return cnt - 1;
    193 			}
    194 
    195 			break;
    196 
    197 		default:	/* all new processes are childern of parent */
    198 			if ((pid = fork()) == -1) {
    199 				if (prefix != NULL)
    200 					fprintf(stderr,
    201 						"%s: %s,forker(): fork() failed, errno:%d %s\n",
    202 						prefix, __FILE__, errno,
    203 						strerror(errno));
    204 				return cnt - 1;
    205 			}
    206 			Forker_npids++;
    207 
    208 			switch (pid) {
    209 			case 0:	/* child - stops the forking */
    210 				if (Forker_npids < FORKER_MAX_PIDS)
    211 					Forker_pids[Forker_npids - 1] =
    212 					    getpid();
    213 				return cnt;
    214 
    215 			default:	/* parent - continues the forking */
    216 				if (Forker_npids < FORKER_MAX_PIDS)
    217 					Forker_pids[Forker_npids - 1] = pid;
    218 				break;
    219 			}
    220 			break;
    221 		}
    222 	}
    223 
    224 	if (Forker_npids < FORKER_MAX_PIDS)
    225 		Forker_pids[Forker_npids] = 0;
    226 	return cnt - 1;
    227 
    228 }				/* end of forker */
    229 
    230 #if UNIT_TEST
    231 
    232 /*
    233  * The following is a unit test main for the background and forker
    234  * functions.
    235  */
    236 
    237 int main(argc, argv)
    238 int argc;
    239 char **argv;
    240 {
    241 	int ncopies = 1;
    242 	int mode = 0;
    243 	int ret;
    244 	int ind;
    245 
    246 	if (argc == 1) {
    247 		printf("Usage: %s ncopies [mode]\n", argv[0]);
    248 		exit(1);
    249 	}
    250 
    251 	if (sscanf(argv[1], "%i", &ncopies) != 1) {
    252 		printf("%s: ncopies argument must be integer\n", argv[0]);
    253 		exit(1);
    254 	}
    255 
    256 	if (argc == 3)
    257 		if (sscanf(argv[2], "%i", &mode) != 1) {
    258 			printf("%s: mode argument must be integer\n", argv[0]);
    259 			exit(1);
    260 		}
    261 
    262 	printf("Starting Pid = %d\n", getpid());
    263 	ret = background(argv[0]);
    264 	printf("After background() ret:%d, pid = %d\n", ret, getpid());
    265 
    266 	ret = forker(ncopies, mode, argv[0]);
    267 
    268 	printf("forker(%d, %d, %s) ret:%d, pid = %d, sleeping 30 seconds.\n",
    269 	       ncopies, mode, argv[0], ret, getpid());
    270 
    271 	printf("%d My version of Forker_pids[],  Forker_npids = %d\n",
    272 	       getpid(), Forker_npids);
    273 
    274 	for (ind = 0; ind < Forker_npids; ind++) {
    275 		printf("%d ind:%-2d pid:%d\n", getpid(), ind, Forker_pids[ind]);
    276 	}
    277 
    278 	sleep(30);
    279 	exit(0);
    280 }
    281 
    282 #endif /* UNIT_TEST */
    283