| // 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 */ |