blob: 63d8fcdba8d0da5a133d9e5166b32ba3242dc729 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2000 Silicon Graphics, Inc.
* All Rights Reserved.
*/
/**************************************************************
*
* 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;
*
* extern int Forker_pids[];
* extern int Forker_npids;
*
* 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(prefix)
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(ncopies, mode, prefix)
int ncopies;
int mode; /* 0 - all childern 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 */