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