1 /*******************************************************************************
2  *  The BYTE UNIX Benchmarks - Release 3
3  *          Module: dummy.c   SID: 3.3 5/15/91 19:30:19
4  *
5  *******************************************************************************
6  * Bug reports, patches, comments, suggestions should be sent to:
7  *
8  *	Ben Smith, Rick Grehan or Tom Yager
9  *	ben@bytepb.byte.com   rick_g@bytepb.byte.com   tyager@bytepb.byte.com
10  *
11  *******************************************************************************
12  *  Modification Log:
13  *  10/22/97 - code cleanup to remove ANSI C compiler warnings
14  *             Andy Kahn <kahn@zk3.dec.com>
15  *
16  ******************************************************************************/
17 /*
18  *  Hacked up C program for use in the standard shell.? scripts of
19  *  the multiuser test.  This is based upon makework.c, and is typically
20  *  edited using edscript.2 before compilation.
21  *
22  * $Header: dummy.c,v 3.4 87/06/23 15:54:53 kjmcdonell Beta $
23  */
24 char SCCSid[] = "@(#) @(#)dummy.c:3.3 -- 5/15/91 19:30:19";
25 
26 #include <stdio.h>
27 #include <signal.h>
28 
29 #define DEF_RATE	5.0
30 #define GRANULE		5
31 #define CHUNK		60
32 #define MAXCHILD	12
33 #define MAXWORK		10
34 
35 float	thres;
36 float	est_rate = DEF_RATE;
37 int	nusers;		/* number of concurrent users to be simulated by
38 			 * this process */
39 int	firstuser;	/* ordinal identification of first user for this
40 			 * process */
41 int	nwork = 0;	/* number of job streams */
42 int	exit_status = 0;	/* returned to parent */
43 int	sigpipe;	/* pipe write error flag */
44 
45 struct st_work {
46 	char	*cmd;		/* name of command to run */
47 	char	**av;		/* arguments to command */
48 	char	*input;		/* standard input buffer */
49 	int	inpsize;	/* size of standard input buffer */
50 } work[MAXWORK];
51 
52 struct {
53 	int	xmit;	/* # characters sent */
54 	char	*bp;	/* std input buffer pointer */
55 	int	blen;	/* std input buffer length */
56 	int	fd;	/* stdin to command */
57 	int	pid;	/* child PID */
58 	char	*line;	/* start of input line */
59 	int	firstjob;	/* inital piece of work */
60 	int	thisjob;	/* current piece of work */
61 } child[MAXCHILD], *cp;
62 
main(argc,argv)63 main(argc, argv)
64 int	argc;
65 char	*argv[];
66 {
67     int		i;
68     int		l;
69     int		fcopy = 0;	/* fd for copy output */
70     int		master = 1;	/* the REAL master, == 0 for clones */
71     int		nchild;		/* no. of children for a clone to run */
72     int		done;		/* count of children finished */
73     int		output;		/* aggregate output char count for all
74 				   children */
75     int		c;
76     int		thiswork = 0;	/* next job stream to allocate */
77     int		nch;		/* # characters to write */
78     int		written;	/* # characters actully written */
79     char	logname[15];	/* name of the log file(s) */
80     void		onalarm(void);
81     void		pipeerr(void);
82     void		wrapup(void);
83     void		grunt(void);
84     char	*malloc();
85     int		pvec[2];	/* for pipes */
86     char	*p;
87     char	*prog;		/* my name */
88 
89 #if ! debug
90     freopen("masterlog.00", "a", stderr);
91 #endif
92     fprintf(stderr, "*** New Run ***  ");
93     prog = argv[0];
94     while (argc > 1 && argv[1][0] == '-')  {
95 	p = &argv[1][1];
96 	argc--;
97 	argv++;
98 	while (*p) {
99 	    switch (*p) {
100 	    case 'r':
101 			/* code DELETED here */
102 			argc--;
103 			argv++;
104 			break;
105 
106 	    case 'c':
107 			/* code DELETED here */
108 			lseek(fcopy, 0L, 2);	/* append at end of file */
109 			break;
110 
111 	    default:
112 		fprintf(stderr, "%s: bad flag '%c'\n", prog, *p);
113 			exit(4);
114 	    }
115 	    p++;
116 	}
117     }
118 
119     if (argc < 2) {
120 	fprintf(stderr, "%s: missing nusers\n", prog);
121 	exit(4);
122     }
123 
124     nusers = atoi(argv[1]);
125     if (nusers < 1) {
126 	fprintf(stderr, "%s: impossible nusers (%d<-%s)\n", prog, nusers, argv[1]);
127 	exit(4);
128     }
129     fprintf(stderr, "%d Users\n", nusers);
130     argc--;
131     argv++;
132 
133     /* build job streams */
134     getwork();
135 #if debug
136     dumpwork();
137 #endif
138 
139     /* clone copies of myself to run up to MAXCHILD jobs each */
140     firstuser = MAXCHILD;
141     fprintf(stderr, "master pid %d\n", getpid());
142     fflush(stderr);
143     while (nusers > MAXCHILD) {
144 	fflush(stderr);
145 	if (nusers >= 2*MAXCHILD)
146 	    /* the next clone must run MAXCHILD jobs */
147 	    nchild = MAXCHILD;
148 	else
149 	    /* the next clone must run the leftover jobs */
150 	    nchild = nusers - MAXCHILD;
151 	if ((l = fork()) == -1) {
152 	    /* fork failed */
153 	    fatal("** clone fork failed **\n");
154 	    goto bepatient;
155 	} else if (l > 0) {
156 	    fprintf(stderr, "master clone pid %d\n", l);
157 	    /* I am the master with nchild fewer jobs to run */
158 	    nusers -= nchild;
159 	    firstuser += MAXCHILD;
160 	    continue;
161 	} else {
162 	    /* I am a clone, run MAXCHILD jobs */
163 #if ! debug
164 	    sprintf(logname, "masterlog.%02d", firstuser/MAXCHILD);
165 	    freopen(logname, "w", stderr);
166 #endif
167 	    master = 0;
168 	    nusers = nchild;
169 	    break;
170 	}
171     }
172     if (master)
173 	firstuser = 0;
174 
175     close(0);
176 
177     /* code DELETED here */
178 
179     fflush(stderr);
180 
181     srand(time(0));
182     thres = 0;
183     done = output = 0;
184     for (i = 0; i < nusers; i++) {
185 	if (child[i].blen == 0)
186 	    done++;
187 	else
188 	    thres += est_rate * GRANULE;
189     }
190     est_rate = thres;
191 
192     signal(SIGALRM, onalarm);
193     signal(SIGPIPE, pipeerr);
194     alarm(GRANULE);
195     while (done < nusers) {
196 	for (i = 0; i < nusers; i++) {
197 	    cp = &child[i];
198 	    if (cp->xmit >= cp->blen) continue;
199 	    l = rand() % CHUNK + 1;	/* 1-CHUNK chars */
200 	    if (l == 0) continue;
201 	    if (cp->xmit + l > cp->blen)
202 		l = cp->blen - cp->xmit;
203 	    p = cp->bp;
204 	    cp->bp += l;
205 	    cp->xmit += l;
206 #if debug
207 	    fprintf(stderr, "child %d, %d processed, %d to go\n", i, cp->xmit, cp->blen - cp->xmit);
208 #endif
209 	    while (p < cp->bp) {
210 		if (*p == '\n' || (p == &cp->bp[-1] && cp->xmit >= cp->blen)) {
211 		    /* write it out */
212 		    nch = p - cp->line + 1;
213 		    if ((written = write(cp->fd, cp->line, nch)) != nch) {
214 
215 			/* code DELETED here */
216 
217 		    }
218 		    if (fcopy)
219 			write(fcopy, cp->line, p - cp->line + 1);
220 #if debug
221 		    fprintf(stderr, "child %d gets \"", i);
222 		    {
223 			char *q = cp->line;
224 			while (q <= p) {
225 				if (*q >= ' ' && *q <= '~')
226 					fputc(*q, stderr);
227 				else
228 					fprintf(stderr, "\\%03o", *q);
229 				q++;
230 			}
231 		    }
232 		    fputc('"', stderr);
233 #endif
234 		    cp->line = &p[1];
235 		}
236 		p++;
237 	    }
238 	    if (cp->xmit >= cp->blen) {
239 		done++;
240 		close(cp->fd);
241 #if debug
242 	fprintf(stderr, "child %d, close std input\n", i);
243 #endif
244 	    }
245 	    output += l;
246 	}
247 	while (output > thres) {
248 	    pause();
249 #if debug
250 	    fprintf(stderr, "after pause: output, thres, done %d %.2f %d\n", output, thres, done);
251 #endif
252 	}
253     }
254 
255 bepatient:
256     alarm(0);
257 /****
258  *  If everything is going OK, we should simply be able to keep
259  *  looping unitil 'wait' fails, however some descendent process may
260  *  be in a state from which it can never exit, and so a timeout
261  *  is used.
262  *  5 minutes should be ample, since the time to run all jobs is of
263  *  the order of 5-10 minutes, however some machines are painfully slow,
264  *  so the timeout has been set at 20 minutes (1200 seconds).
265  ****/
266 
267     /* code DELETED here */
268 
269 }
270 
onalarm()271 onalarm()
272 {
273     thres += est_rate;
274     signal(SIGALRM, onalarm);
275     alarm(GRANULE);
276 }
277 
grunt()278 grunt()
279 {
280     /* timeout after label "bepatient" in main */
281     exit_status = 4;
282     wrapup();
283 }
284 
pipeerr()285 pipeerr()
286 {
287 	sigpipe++;
288 }
289 
wrapup()290 wrapup()
291 {
292     /* DUMMY, real code dropped */
293 }
294 
getwork()295 getwork()
296 {
297 
298     /* DUMMY, real code dropped */
299     gets();
300     strncpy();
301     malloc(); realloc();
302     open(); close();
303 }
304 
fatal(s)305 fatal(s)
306 char *s;
307 {
308     int	i;
309     fprintf(stderr, s);
310     fflush(stderr);
311     perror("Reason?");
312     for (i = 0; i < nusers; i++) {
313 	if (child[i].pid > 0 && kill(child[i].pid, SIGKILL) != -1)
314 	    fprintf(stderr, "pid %d killed off\n", child[i].pid);
315     }
316     fflush(stderr);
317     exit_status = 4;
318     return;
319 }
320