/*
* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
* Mountain View, CA 94043, or:
*
* http://www.sgi.com
*
* For further information regarding this notice, see:
*
* http://oss.sgi.com/projects/GenInfo/NoticeExplan/
*/
/**************************************************************
*
* OS Testing - Silicon Graphics, Inc.
*
* FUNCTION NAME : forker
* background
*
* FUNCTION TITLE : fork desired number of copies of the current process
* fork a process and return control to caller
*
* SYNOPSIS:
* int forker(ncopies, mode, prefix)
* int ncopies;
* int mode;
* char *prefix;
*
* int background(prefix);
* char *prefix;
*
* AUTHOR : Richard Logan
*
* CO-PILOT(s) : Dean Roehrich
*
* INITIAL RELEASE : UNICOS 8.0
*
* DESIGN DESCRIPTION
* The background function will do a fork of the current process.
* The parent process will then exit, thus orphaning the
* child process. Doing this will not nice the child process
* like executing a cmd in the background using "&" from the shell.
* If the fork fails and prefix is not NULL, a error message is printed
* to stderr and the process will exit with a value of errno.
*
* The forker function will fork <ncopies> minus one copies
* of the current process. There are two modes in how the forks
* will be done. Mode 0 (default) will have all new processes
* be childern of the parent process. Using Mode 1,
* the parent process will have one child and that child will
* fork the next process, if necessary, and on and on.
* The forker function will return the number of successful
* forks. This value will be different for the parent and each child.
* Using mode 0, the parent will get the total number of successful
* forks. Using mode 1, the newest child will get the total number
* of forks. The parent will get a return value of 1.
*
* The forker function also updates the global variables
* Forker_pids[] and Forker_npids. The Forker_pids array will
* be updated to contain the pid of each new process. The
* Forker_npids variable contains the number of entries
* in Forker_pids. Note, not all processes will have
* access to all pids via Forker_pids. If using mode 0, only the
* parent process and the last process will have all information.
* If using mode 1, only the last child process will have all information.
*
* If the prefix parameter is not NULL and the fork system call fails,
* a error message will be printed to stderr. The error message
* the be preceeded with prefix string. If prefix is NULL,
* no error message is printed.
*
* SPECIAL REQUIREMENTS
* None.
*
* UPDATE HISTORY
* This should contain the description, author, and date of any
* "interesting" modifications (i.e. info should helpful in
* maintaining/enhancing this module).
* username description
* ----------------------------------------------------------------
* rrl This functions will first written during
* the SFS testing days, 1993.
*
* BUGS/LIMITATIONS
* The child pids are stored in the fixed array, Forker_pids.
* The array only has space for 4098 pids. Only the first
* 4098 pids will be stored in the array.
*
**************************************************************/
#include <stdio.h>
#include <errno.h>
#include <unistd.h> /* fork, getpid, sleep */
#include <string.h>
#include <stdlib.h> /* exit */
#include "forker.h"
int Forker_pids[FORKER_MAX_PIDS]; /* holds pids of forked processes */
int Forker_npids = 0; /* number of entries in Forker_pids */
/***********************************************************************
*
* This function will fork and the parent will exit zero and
* the child will return. This will orphan the returning process
* putting it in the background.
*
* Return Value
* 0 : if fork did not fail
* !0 : if fork failed, the return value will be the errno.
***********************************************************************/
int background(char *prefix)
{
switch (fork()) {
case -1:
if (prefix != NULL)
fprintf(stderr,
"%s: In %s background(), fork() failed, errno:%d %s\n",
prefix, __FILE__, errno, strerror(errno));
exit(errno);
case 0: /* child process */
break;
default:
exit(0);
}
return 0;
} /* end of background */
/***********************************************************************
* Forker will fork ncopies-1 copies of self.
*
***********************************************************************/
int forker(int ncopies,
int mode, /* 0 - all children of parent, 1 - only 1 direct child */
char *prefix) /* if ! NULL, an message will be printed to stderr */
/* if fork fails. The prefix (program name) will */
/* preceed the message */
{
int cnt;
int pid;
static int ind = 0;
Forker_pids[ind] = 0;
for (cnt = 1; cnt < ncopies; cnt++) {
switch (mode) {
case 1: /* only 1 direct child */
if ((pid = fork()) == -1) {
if (prefix != NULL)
fprintf(stderr,
"%s: %s,forker(): fork() failed, errno:%d %s\n",
prefix, __FILE__, errno,
strerror(errno));
return 0;
}
Forker_npids++;
switch (pid) {
case 0: /* child - continues the forking */
if (Forker_npids < FORKER_MAX_PIDS)
Forker_pids[Forker_npids - 1] =
getpid();
break;
default: /* parent - stop the forking */
if (Forker_npids < FORKER_MAX_PIDS)
Forker_pids[Forker_npids - 1] = pid;
return cnt - 1;
}
break;
default: /* all new processes are childern of parent */
if ((pid = fork()) == -1) {
if (prefix != NULL)
fprintf(stderr,
"%s: %s,forker(): fork() failed, errno:%d %s\n",
prefix, __FILE__, errno,
strerror(errno));
return cnt - 1;
}
Forker_npids++;
switch (pid) {
case 0: /* child - stops the forking */
if (Forker_npids < FORKER_MAX_PIDS)
Forker_pids[Forker_npids - 1] =
getpid();
return cnt;
default: /* parent - continues the forking */
if (Forker_npids < FORKER_MAX_PIDS)
Forker_pids[Forker_npids - 1] = pid;
break;
}
break;
}
}
if (Forker_npids < FORKER_MAX_PIDS)
Forker_pids[Forker_npids] = 0;
return cnt - 1;
} /* end of forker */
#if UNIT_TEST
/*
* The following is a unit test main for the background and forker
* functions.
*/
int main(argc, argv)
int argc;
char **argv;
{
int ncopies = 1;
int mode = 0;
int ret;
int ind;
if (argc == 1) {
printf("Usage: %s ncopies [mode]\n", argv[0]);
exit(1);
}
if (sscanf(argv[1], "%i", &ncopies) != 1) {
printf("%s: ncopies argument must be integer\n", argv[0]);
exit(1);
}
if (argc == 3)
if (sscanf(argv[2], "%i", &mode) != 1) {
printf("%s: mode argument must be integer\n", argv[0]);
exit(1);
}
printf("Starting Pid = %d\n", getpid());
ret = background(argv[0]);
printf("After background() ret:%d, pid = %d\n", ret, getpid());
ret = forker(ncopies, mode, argv[0]);
printf("forker(%d, %d, %s) ret:%d, pid = %d, sleeping 30 seconds.\n",
ncopies, mode, argv[0], ret, getpid());
printf("%d My version of Forker_pids[], Forker_npids = %d\n",
getpid(), Forker_npids);
for (ind = 0; ind < Forker_npids; ind++) {
printf("%d ind:%-2d pid:%d\n", getpid(), ind, Forker_pids[ind]);
}
sleep(30);
exit(0);
}
#endif /* UNIT_TEST */