• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24  * Mountain View, CA  94043, or:
25  *
26  * http://www.sgi.com
27  *
28  * For further information regarding this notice, see:
29  *
30  * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
31  *
32  */
33 /* $Header: /cvsroot/ltp/ltp/testcases/kernel/ipc/pipeio/pipeio.c,v 1.18 2009/03/19 07:10:02 subrata_modak Exp $ */
34 /*
35  *  This tool can be used to beat on system or named pipes.
36  *  See the help() function below for user information.
37  */
38 #include <stdio.h>
39 #include <fcntl.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <sys/types.h>
43 #include <sys/param.h>
44 #include <sys/wait.h>
45 #include <time.h>
46 #include <errno.h>
47 #include <string.h>
48 #include <signal.h>
49 #include <sys/stat.h>
50 
51 #include "tlibio.h"
52 
53 #include "test.h"
54 #include "safe_macros.h"
55 #include "lapi/sem.h"
56 
57 char *TCID = "pipeio";
58 int TST_TOTAL = 1;
59 
60 #define SAFE_FREE(p) { if (p) { free(p); (p)=NULL; } }
61 
62 #if defined(__linux__)
63 #define NBPW sizeof(int)
64 #endif
65 
66 #define OCTAL	'o'
67 #define HEX	'x'
68 #define DECIMAL	'd'
69 #define ASCII	'a'
70 #define NO_OUT	'n'
71 
72 #define PIPE_NAMED	"named pipe,"
73 #define PIPE_UNNAMED	"sys pipe,"
74 
75 #define BLOCKING_IO	"blking,"
76 #define NON_BLOCKING_IO	"non-blking,"
77 #define UNNAMED_IO	""
78 
79 #define MAX_ERRS 16
80 #define MAX_EMPTY 256
81 
82 static int parse_options(int argc, char *argv[]);
83 static void setup(int argc, char *argv[]);
84 static void cleanup(void);
85 
86 static void do_child(void);
87 static void do_parent(void);
88 
89 static void help(void), usage(void), prt_examples(void);
90 static void prt_buf(char **addr, char *buf, int length, int format);
91 static void sig_child(int sig);
92 static int check_rw_buf(void);
93 
94 static volatile sig_atomic_t nchildcompleted;
95 
96 /* variables may be modified in setup() */
97 static int num_writers = 1;	/* number of writers */
98 static int num_writes = 1;	/* number of writes per child */
99 static int loop;		/* loop indefinitely */
100 static int exit_error = 1;	/* exit on error #, zero means no exit */
101 static int size = 327;		/* default size */
102 static int unpipe;		/* un-named pipe if non-zero */
103 static int verbose;		/* verbose mode if set */
104 static int quiet;		/* quiet mode if set */
105 static int num_rpt;		/* ping number, how often to print message */
106 static int chld_wait;	/* max time to wait between writes, 1 == no wait */
107 static int parent_wait;	/* max time to wait between reads, 1 == no wait */
108 static int ndelay = O_NDELAY;	/* additional flag to open */
109 static char *writebuf;
110 static char *readbuf;
111 static char pname[PATH_MAX];	/* contains the name of the named pipe */
112 static char *blk_type = NON_BLOCKING_IO; /* blocking i/o or not */
113 static char *pipe_type;		/* type of pipe under test */
114 static int format = HEX;
115 static int format_size = -1;
116 static int iotype;		/* sync io */
117 
118 /* variables will be modified in running */
119 static int error;
120 static int count;
121 static int read_fd;
122 static int write_fd;
123 static int empty_read;
124 static int sem_id;
125 
126 static union semun u;
127 
main(int ac,char * av[])128 int main(int ac, char *av[])
129 {
130 	int i;
131 	unsigned int j;
132 	unsigned int uwait_iter = 1000, uwait_total = 5000000;
133 	pid_t child;
134 
135 	setup(ac, av);
136 
137 	for (i = num_writers; i > 0; --i) {
138 
139 		child = tst_fork();
140 		switch (child) {
141 		case -1:
142 			tst_brkm(TBROK | TERRNO, cleanup, "fork() failed");
143 		case 0:
144 			do_child();
145 			exit(0);
146 		default:
147 			break;
148 		}
149 	}
150 
151 	do_parent();
152 
153 	if (empty_read)
154 		tst_resm(TWARN, "%d empty reads", empty_read);
155 
156 	if (error) {
157 		tst_resm(TFAIL, "%d data errors on pipe, read size = %d, %s %s",
158 			 error, size, pipe_type, blk_type);
159 	} else if (!quiet) {
160 		tst_resm(TPASS, "%d pipe reads complete, read size = %d, %s %s",
161 			 count + 1, size, pipe_type, blk_type);
162 	}
163 
164 	/*
165 	 * wait for all children to finish, timeout after uwait_total
166 	 * semtimedop might not be available everywhere
167 	 */
168 	for (j = 0; j < uwait_total; j += uwait_iter) {
169 		if (semctl(sem_id, 1, GETVAL) == 0)
170 			break;
171 		usleep(uwait_iter);
172 	}
173 
174 	if (j >= uwait_total) {
175 		tst_resm(TWARN,
176 			 "Timed out waiting for child processes to exit");
177 	}
178 
179 	cleanup();
180 	tst_exit();
181 }
182 
parse_options(int argc,char * argv[])183 static int parse_options(int argc, char *argv[])
184 {
185 	char *cp;
186 	int c;
187 	int ret = 0;
188 	static double d;
189 
190 	while ((c = getopt(argc, argv, "T:bc:D:he:Ef:i:I:ln:p:qs:uvW:w:"))
191 	       != -1) {
192 		switch (c) {
193 		case 'T':
194 			TCID = optarg;
195 			break;
196 		case 'h':
197 			help();
198 			ret = 1;
199 			break;
200 		case 'D':	/* pipe name */
201 			strcpy(pname, optarg);
202 			break;
203 		case 'b':	/* blocked */
204 			ndelay = 0;
205 			blk_type = BLOCKING_IO;
206 			break;
207 		case 'c':	/* number childern */
208 			if (sscanf(optarg, "%d", &num_writers) != 1) {
209 				fprintf(stderr,
210 					"%s: --c option invalid arg '%s'.\n",
211 					TCID, optarg);
212 				ret = 1;
213 			} else if (num_writers <= 0) {
214 				fprintf(stderr, "%s: --c option must be "
215 					"greater than zero.\n", TCID);
216 				ret = 1;
217 			}
218 			break;
219 		case 'e':	/* exit on error # */
220 			if (sscanf(optarg, "%d", &exit_error) != 1) {
221 				fprintf(stderr,
222 					"%s: --e option invalid arg '%s'.\n",
223 					TCID, optarg);
224 				ret = 1;
225 			} else if (exit_error < 0) {
226 				fprintf(stderr, "%s: --e option must be "
227 					"greater than zero.\n", TCID);
228 				ret = 1;
229 			}
230 			break;
231 		case 'E':
232 			prt_examples();
233 			ret = 1;
234 			break;
235 		case 'f':	/* format of buffer on error */
236 			switch (optarg[0]) {
237 			case 'x':
238 			case 'X':
239 				format = HEX;
240 				break;
241 			case 'o':
242 			case 'O':
243 				format = OCTAL;
244 				break;
245 			case 'd':
246 			case 'D':
247 				format = DECIMAL;
248 				break;
249 			case 'a':
250 			case 'A':
251 				format = ASCII;
252 				break;
253 			case 'n':	/* not output */
254 			case 'N':
255 				format = NO_OUT;
256 				break;
257 
258 			default:
259 				fprintf(stderr,
260 					"%s: --f option invalid arg '%s'.\n",
261 					TCID, optarg);
262 				fprintf(stderr, "\tIt must be x(hex), o(octal),"
263 					"d(decimal), a(ascii) or n(none) with "
264 					"opt sz\n");
265 				ret = 1;
266 				break;
267 			}
268 			cp = optarg;
269 			cp++;
270 			if (*cp) {
271 				if (sscanf(cp, "%i", &format_size) != 1) {
272 					fprintf(stderr, "%s: --f option invalid"
273 						"arg '%s'.\n", TCID, optarg);
274 					fprintf(stderr, "\tIt must be x(hex),"
275 						"o(octal), d(decimal), a(ascii)"
276 						" or n(none) with opt sz\n");
277 					ret = 1;
278 					break;
279 				}
280 			}
281 			break;
282 
283 		case 'I':
284 			iotype = lio_parse_io_arg1(optarg);
285 			if (iotype == -1) {
286 				fprintf(stderr, "%s: --I arg is invalid, "
287 					"must be s, p, f, a, l, L or r.\n",
288 					TCID);
289 				ret = 1;
290 			}
291 			break;
292 
293 		case 'l':	/* loop forever */
294 			++loop;
295 			break;
296 
297 		case 'i':
298 		case 'n':	/* number writes per child */
299 			if (sscanf(optarg, "%d", &num_writes) != 1) {
300 				fprintf(stderr, "%s: --i/n option invalid "
301 					"arg '%s'.\n", TCID, optarg);
302 				ret = 1;
303 			} else if (num_writes < 0) {
304 				fprintf(stderr, "%s: --i/n option must be "
305 					"greater than equal to zero.\n",
306 					TCID);
307 				ret = 1;
308 			}
309 
310 			if (num_writes == 0)	/* loop forever */
311 				++loop;
312 			break;
313 		case 'p':	/* ping */
314 			if (sscanf(optarg, "%d", &num_rpt) != 1) {
315 				fprintf(stderr,
316 					"%s: --p option invalid arg '%s'.\n",
317 					TCID, optarg);
318 				ret = 1;
319 			} else if (num_rpt < 0) {
320 				fprintf(stderr, "%s: --p option must be greater"
321 					" than equal to zero.\n", TCID);
322 				ret = 1;
323 			}
324 			break;
325 		case 'q':	/* Quiet - NOPASS */
326 			quiet = 1;
327 			break;
328 		case 's':	/* size */
329 			if (sscanf(optarg, "%d", &size) != 1) {
330 				fprintf(stderr,
331 					"%s: --s option invalid arg '%s'.\n",
332 					TCID, optarg);
333 				ret = 1;
334 			} else if (size <= 0) {
335 				fprintf(stderr, "%s: --s option must be greater"
336 					" than zero.\n", TCID);
337 				ret = 1;
338 			}
339 			break;
340 		case 'u':
341 			unpipe = 1;	/* un-named pipe */
342 			break;
343 		case 'v':	/* verbose */
344 			verbose = 1;
345 			break;
346 		case 'W':	/* max wait time between reads */
347 			d = strtod(optarg, &cp);
348 			if (*cp != '\0') {
349 				fprintf(stderr,
350 					"%s: --w option invalid arg '%s'.\n",
351 					TCID, optarg);
352 				ret = 1;
353 			} else if (d < 0) {
354 				fprintf(stderr, "%s: --w option must be greater"
355 					" than zero.\n", TCID);
356 				ret = 1;
357 			}
358 			parent_wait = (int)(d * 1000000.0);
359 			break;
360 		case 'w':	/* max wait time between writes */
361 			d = strtod(optarg, &cp);
362 			if (*cp != '\0') {
363 				fprintf(stderr,
364 					"%s: --w option invalid arg '%s'.\n",
365 					TCID, optarg);
366 				ret = 1;
367 			} else if (d < 0) {
368 				fprintf(stderr, "%s: --w option must be greater"
369 					" than zero.\n", TCID);
370 				ret = 1;
371 			}
372 			chld_wait = (int)(d * 1000000.0);
373 			break;
374 		case '?':
375 			ret = 1;
376 			break;
377 		}
378 
379 		if (ret == 1) {
380 			usage();
381 			return ret;
382 		}
383 	}
384 
385 	return ret;
386 }
387 
setup(int argc,char * argv[])388 static void setup(int argc, char *argv[])
389 {
390 	int ret;
391 	char *toutput;
392 	int fds[2];
393 
394 	tst_sig(FORK, DEF_HANDLER, cleanup);
395 
396 	TEST_PAUSE;
397 
398 	tst_tmpdir();
399 
400 	if (signal(SIGCHLD, sig_child) == SIG_ERR) {
401 		tst_brkm(TBROK | TERRNO, cleanup,
402 			 "set signal handler for SIGCHLD failed");
403 	}
404 
405 	toutput = getenv("TOUTPUT");
406 	if (toutput != NULL && strcmp(toutput, "NOPASS") == 0)
407 		quiet = 1;
408 
409 	sprintf(pname, "%s", "tpipe");
410 
411 	ret = parse_options(argc, argv);
412 	if (ret == 1)
413 		tst_brkm(TBROK, cleanup, "options parse error");
414 
415 	if (format_size == -1)
416 		format_size = size;
417 
418 	/*
419 	 * If there is more than one writer, all writes and reads
420 	 * must be the same size.  Only writes of a size <= PIPE_BUF
421 	 * are atomic.  T
422 	 * Therefore, if size is greater than PIPE_BUF, we will break
423 	 * the writes into PIPE_BUF chunks.  We will also increase the
424 	 * number of writes to ensure the same (or more) amount of
425 	 * data is written.  This is the same as erroring and telling
426 	 * the user the new cmd line to do the same thing.
427 	 * Example:
428 	 *      pipeio -s 5000 -n 10 -c 5
429 	 *      (each child will write at least 50000 bytes, since all
430 	 *      writes have to be in 4096 chuncks or 13*4096 (53248)
431 	 *      bytes will be written.)  This is the same as:
432 	 *      pipeio -s 4096 -n 13 -c 5
433 	 */
434 	if (size > PIPE_BUF && num_writers > 1) {
435 		if (!loop) {
436 			/*
437 			 * we must set num_writes*num_writers
438 			 * doesn't overflow later
439 			 */
440 			num_writes = MIN(((long long)num_writes * size +
441 					 PIPE_BUF - 1) / PIPE_BUF,
442 					 INT_MAX / num_writers);
443 			tst_resm(TINFO, "adjusting i/o size to %d, and # of "
444 				 "writes to %d", PIPE_BUF, num_writes);
445 		} else {
446 			tst_resm(TINFO, "adjusting i/o size to %d", PIPE_BUF);
447 		}
448 		size = PIPE_BUF;
449 	}
450 
451 	writebuf = SAFE_MALLOC(cleanup, size);
452 	readbuf = SAFE_MALLOC(cleanup, size);
453 
454 	memset(writebuf, 'Z', size);
455 	writebuf[size - 1] = 'A';
456 
457 	sem_id = semget(IPC_PRIVATE, 2, IPC_CREAT | S_IRWXU);
458 	if (sem_id == -1) {
459 		tst_brkm(TBROK | TERRNO, cleanup,
460 			 "Couldn't allocate semaphore");
461 	}
462 
463 	if (semctl(sem_id, 0, SETVAL, u) == -1) {
464 		tst_brkm(TBROK | TERRNO, cleanup,
465 			 "Couldn't initialize semaphore 0 value");
466 	}
467 
468 	if (semctl(sem_id, 1, SETVAL, u) == -1) {
469 		tst_brkm(TBROK | TERRNO, cleanup,
470 			 "Couldn't initialize semaphore 1 value");
471 	}
472 
473 	if (unpipe) {
474 		SAFE_PIPE(cleanup, fds);
475 		read_fd = fds[0];
476 		write_fd = fds[1];
477 		pipe_type = PIPE_UNNAMED;
478 		blk_type = UNNAMED_IO;
479 	} else {
480 		SAFE_MKFIFO(cleanup, pname, 0777);
481 		pipe_type = PIPE_NAMED;
482 	}
483 }
484 
cleanup(void)485 static void cleanup(void)
486 {
487 	SAFE_FREE(writebuf);
488 	SAFE_FREE(readbuf);
489 
490 	semctl(sem_id, 0, IPC_RMID);
491 
492 	if (!unpipe)
493 		unlink(pname);
494 
495 	tst_rmdir();
496 }
497 
do_child(void)498 static void do_child(void)
499 {
500 	int *count_word;        /* holds address where to write writers count */
501 	int *pid_word;          /* holds address where to write writers pid */
502 	int nb, j;
503 	long clock;
504 	char *cp;
505 	long int n;
506 	struct sembuf sem_op;
507 	pid_t self_pid =  getpid();
508 
509 	if (!unpipe) {
510 		write_fd = open(pname, O_WRONLY);
511 		if (write_fd == -1) {
512 			fprintf(stderr, "child pipe open(%s, %#o) failed",
513 				pname, O_WRONLY | ndelay);
514 			exit(1);
515 		}
516 		if (ndelay && fcntl(write_fd, F_SETFL, O_NONBLOCK) == -1) {
517 			fprintf(stderr, "Failed setting the pipe to "
518 				"nonblocking mode");
519 			exit(1);
520 		}
521 	} else {
522 		close(read_fd);
523 	}
524 
525 	sem_op = (struct sembuf) {
526 		 .sem_num = 0, .sem_op = 1, .sem_flg = 0};
527 
528 	if (semop(sem_id, &sem_op, 1) == -1) {
529 		fprintf(stderr, "child: %d couldn't raise the semaphore 0",
530 			self_pid);
531 		exit(1);
532 	}
533 
534 	pid_word = (int *)&writebuf[0];
535 	count_word = (int *)&writebuf[NBPW];
536 
537 	for (j = 0; j < num_writes || loop; ++j) {
538 		/*
539 		 * writes are only in one unit when the size of the write
540 		 * is <= PIPE_BUF.
541 		 * Therefore, if size is greater than PIPE_BUF, we will break
542 		 * the writes into PIPE_BUF chunks.
543 		 * All writes and read need to be same size.
544 		 */
545 
546 		/*
547 		 * write pid and count in first two
548 		 * words of buffer
549 		 */
550 		*count_word = j;
551 		*pid_word = self_pid;
552 
553 		nb = lio_write_buffer(write_fd, iotype, writebuf, size,
554 				      SIGUSR1, &cp, 0);
555 		if (nb < 0) {
556 			/*
557 			 * If lio_write_buffer returns a negative number,
558 			 * the return will be -errno.
559 			 */
560 			fprintf(stderr, "pass %d: lio_write_buffer(%s) failed;"
561 				" it returned %d: %s",
562 				j, cp, nb, strerror(-nb));
563 				exit(1);
564 		} else if (nb != size) {
565 			fprintf(stderr, "pass %d: lio_write_buffer(%s) failed,"
566 				" write count %d, but expected to write %d",
567 				j, cp, nb, size);
568 		}
569 		if (verbose) {
570 			fprintf(stderr, "pass %d: pid %d: wrote %d bytes,"
571 				"expected %d bytes",
572 				j, self_pid, nb, size);
573 		}
574 
575 		if (chld_wait) {
576 			clock = time(0);
577 			srand48(clock);
578 			n = lrand48() % chld_wait;
579 			usleep(n);
580 		}
581 		fflush(stderr);
582 	}
583 
584 	/* child waits until parent completes open() */
585 	sem_op = (struct sembuf) {
586 		  .sem_num = 1, .sem_op = -1, .sem_flg = 0};
587 	if (semop(sem_id, &sem_op, 1) == -1)
588 		fprintf(stderr, "Couldn't lower the semaphore 1");
589 
590 	exit(0);
591 }
592 
check_rw_buf(void)593 static int check_rw_buf(void)
594 {
595 	int i;
596 
597 	for (i = 2 * NBPW; i < size; ++i) {
598 		if (writebuf[i] != readbuf[i]) {
599 			++error;
600 			tst_resm(TFAIL,
601 				 "FAIL data error on byte %d; rd# %d, sz= %d, "
602 				 "%s %s empty_reads= %d, err= %d",
603 				 i, count, size, pipe_type, blk_type,
604 				 empty_read, error);
605 			prt_buf(&readbuf, readbuf, format_size, format);
606 			fflush(stdout);
607 			return 1;
608 		}
609 	}
610 
611 	return 0;
612 }
613 
do_parent(void)614 static void do_parent(void)
615 {
616 	int i, nb;
617 	long clock;
618 	time_t start_time, current_time, diff_time;
619 	char *cp;
620 	long int n;
621 	struct sembuf sem_op;
622 
623 	start_time = time(0);
624 	if (!unpipe) {
625 		read_fd = SAFE_OPEN(cleanup, pname, O_RDONLY);
626 		if (ndelay && fcntl(read_fd, F_SETFL, O_NONBLOCK) == -1) {
627 			tst_brkm(TBROK | TERRNO, cleanup,
628 				 "Failed setting the pipe to nonblocking mode");
629 		}
630 	} else {
631 		SAFE_CLOSE(cleanup, write_fd);
632 	}
633 
634 	/* raise semaphore so children can exit */
635 	sem_op = (struct sembuf) {
636 		  .sem_num = 1, .sem_op = num_writers, .sem_flg = 0};
637 	if (semop(sem_id, &sem_op, 1) == -1) {
638 		tst_brkm(TBROK | TERRNO, cleanup,
639 			 "Couldn't raise the semaphore 1");
640 	}
641 
642 	sem_op = (struct sembuf) {
643 		  .sem_num = 0, .sem_op = -num_writers, .sem_flg = 0};
644 
645 	while (nchildcompleted < num_writers
646 	       && semop(sem_id, &sem_op, 1) == -1) {
647 		if (errno == EINTR)
648 			continue;
649 		tst_brkm(TBROK | TERRNO, cleanup,
650 			 "Couldn't wait on semaphore 0");
651 	}
652 
653 	/* parent start to read pipe */
654 	for (i = num_writers * num_writes; i > 0 || loop; --i) {
655 		if (error >= MAX_ERRS || empty_read >= MAX_EMPTY)
656 			break;
657 		if (parent_wait) {
658 			clock = time(0);
659 			srand48(clock);
660 			n = lrand48() % parent_wait;
661 			usleep(n);
662 		}
663 		++count;
664 		nb = lio_read_buffer(read_fd, iotype, readbuf, size,
665 				     SIGUSR1, &cp, 0);
666 		if (nb < 0) {
667 			/*
668 			 * If lio_read_buffer returns a negative number,
669 			 * the return will be -errno.
670 			 */
671 			tst_resm(TFAIL, "pass %d: lio_read_buffer(%s) failed; "
672 				 "returned %d: %s", i, cp, nb, strerror(-nb));
673 			++i;
674 			count--;
675 			error++;
676 			continue;
677 		} else {
678 			if (nb == 0) {
679 				if (nchildcompleted >= num_writers && !loop) {
680 					tst_resm(TWARN, "The children have "
681 						 "died prematurely");
682 					break;	/* All children have died */
683 				}
684 				empty_read++;
685 				++i;
686 				count--;
687 				continue;
688 			} else if (nb < size && size <= PIPE_BUF) {
689 				tst_resm(TFAIL, "pass %d: partial read from the"
690 					" pipe: read %d bytes, expected %d, "
691 					"read count %d", i, nb, size, count);
692 				++error;
693 			} else if (nb == size) {
694 				check_rw_buf();
695 				if (exit_error && exit_error == error)
696 					return;
697 			}
698 
699 			if (verbose || (num_rpt && !(count % num_rpt))) {
700 				current_time = time(0);
701 				diff_time = current_time - start_time;
702 				tst_resm(TFAIL,
703 					 "(%d) rd# %d, sz= %d, %s %s "
704 					 "empty_reads= %d, err= %d\n",
705 					 (int)diff_time, count, size,
706 					 pipe_type, blk_type,
707 					 empty_read, error);
708 				fflush(stdout);
709 			}
710 		}
711 	}
712 
713 	SAFE_CLOSE(cleanup, read_fd);
714 }
715 
usage(void)716 static void usage(void)
717 {
718 	fprintf(stderr, "Usage: %s [-bEv][-c #writers][-D pname][-h]"
719 		"[-e exit_num][-f fmt][-l][-i #writes][-n #writes][-p num_rpt]"
720 		"\n\t[-s size][-W max_wait][-w max_wait][-u]\n", TCID);
721 	fflush(stderr);
722 }
723 
help(void)724 static void help(void)
725 {
726 	usage();
727 
728 	printf(" -b    - blocking reads and writes. default non-block\n\
729   -c #writers  - number of writers (childern)\n\
730   -D pname     - name of fifo (def tpipe<pid>)\n\
731   -h           - print this help message\n\
732   -e exit_num  - exit on error exit_num, 0 is ignore errors, 1 is default.\n\
733   -E           - print cmd line examples and exit\n\
734   -f format    - define format of bad buffer: h(hex), o(octal)\n\
735                  d(decimal), a(ascii), n (none). hex is default\n\
736 	         option size can be added to control output\n\
737   -i #writes   - number write per child, zero means forever.\n\
738   -I io_type   - Specifies io type: s - sync, p - polled async, a - async (def s)\n\
739                  l - listio sync, L - listio async, r - random\n\
740   -l           - loop forever (implied by -n 0).\n\
741   -n #writes   - same as -i (for compatability).\n\
742   -p num_rpt   - number of reads before a report\n\
743   -q           - quiet mode, no PASS results are printed\n\
744   -s size      - size of read and write (def 327)\n\
745                  if size >= 4096, i/o will be in 4096 chuncks\n\
746   -w max_wait  - max time (seconds) for sleep between writes.\n\
747                  max_wait is interpreted as a double with ms accuracy.\n\
748   -W max_wait  - max time (seconds) for sleep between reads\n\
749                  max_wait is interpreted as a double with ms accuracy.\n\
750   -u           - un-named pipe instead of named pipe\n\
751   -v           - verbose mode, all writes/reads resutlts printed\n");
752 
753 	fflush(stdout);
754 }
755 
prt_buf(char ** addr,char * buf,int length,int format)756 static void prt_buf(char **addr, char *buf, int length, int format)
757 {
758 	int i;
759 	int num_words = length / NBPW;	/* given length in bytes, get length in words */
760 	int width;		/* number of columns */
761 	int extra_words = 0;	/* odd or even number of words */
762 	char *a = buf;
763 	char b[NBPW];
764 	char c[NBPW * 2];
765 	char *p;
766 	long *word;
767 
768 	if (format == NO_OUT)	/* if no output wanted, return */
769 		return;
770 
771 	if (length % NBPW)
772 		++num_words;	/* is length in full words? */
773 	if (format == ASCII) {
774 		width = 3;
775 	} else {
776 		width = 2;
777 		/* do we have an odd number of words? */
778 		extra_words = num_words % width;
779 	}
780 	for (i = 0; i < num_words; ++i, a += NBPW, addr++) {
781 		word = (long *)a;
782 		if (!(i % width)) {
783 			if (i > 0 && format != ASCII) {
784 				/*
785 				 * print the ascii equivalent of the data
786 				 * before beginning the next line of output.
787 				 */
788 				memset(c, 0x00, width * NBPW);
789 				/*
790 				 * get the last 2 words printed
791 				 */
792 				memcpy(c, a - (width * NBPW), width * NBPW);
793 				for (p = c; (p - c) < (int)(width*NBPW); ++p) {
794 					if (*p < '!' || *p > '~')
795 						*p = '.';
796 				}
797 				printf("\t%16.16s", c);
798 			}
799 			printf("\n%p: ", addr);
800 			/***printf("\n%7o (%d): ",addr,i);***/
801 		}
802 
803 		switch (format) {
804 		case HEX:
805 			printf("%16.16lx ", *word);
806 			break;
807 		case DECIMAL:
808 			printf("%10.10ld ", *word);
809 			break;
810 		case ASCII:
811 			memcpy(b, a, NBPW);
812 			for (p = b; (p - b) < (int)NBPW; ++p) {
813 				if (*p < '!' || *p > '~')
814 					*p = '.';
815 			}
816 			printf("%8.8s ", b);
817 			break;
818 		default:
819 			printf("%22.22lo ", *word);
820 			break;
821 		}
822 	}
823 	if (format != ASCII) {
824 		/*
825 		 * print the ascii equivalent of the last words in the buffer
826 		 * before returning.
827 		 */
828 		memset(c, 0x00, width * NBPW);
829 		if (extra_words)
830 			width = extra_words;	/* odd number of words */
831 		memcpy(c, a - (width * NBPW), width * NBPW);
832 		for (p = c; (p - c) < (int)(width * NBPW); ++p) {
833 			if (*p < '!' || *p > '~')
834 				*p = '.';
835 		}
836 		if (width == 2)
837 			printf("\t%16.16s", c);
838 		else
839 			printf("\t\t%16.8s", c);
840 	}
841 	printf("\n");
842 	fflush(stdout);
843 }
844 
prt_examples(void)845 static void prt_examples(void)
846 {
847 	printf("%s -c 5 -i 0 -s 4090 -b\n", TCID);
848 	printf("%s -c 5 -i 0 -s 4090 -b -u \n", TCID);
849 	printf("%s -c 5 -i 0 -s 4090 -b -W 3 -w 3 \n", TCID);
850 }
851 
sig_child(int sig)852 static void sig_child(int sig)
853 {
854 	int status;
855 
856 	nchildcompleted++;
857 #if DEBUG
858 	#define STR	"parent: received SIGCHLD\n"
859 	write(STDOUT_FILENO, str, strlen(STR));
860 #endif
861 	waitpid(-1, &status, WNOHANG);
862 }
863