summaryrefslogtreecommitdiff
path: root/ltp_framework/lib/forker.c
blob: ad8b4a7c58b8c6999dfe370d48730043c69a5750 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/*
 * 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., 59
 * Temple Place - Suite 330, Boston MA 02111-1307, 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(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 */