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