2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
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.
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.
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.
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., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
33 /* $Header: /cvsroot/ltp/ltp/testcases/kernel/ipc/pipeio/pipeio.c,v 1.15 2008/12/11 13:17:49 subrata_modak Exp $ */
35 * This tool can be used to beat on system or named pipes.
36 * See the help() function below for user information.
42 #include <sys/types.h>
43 #include <sys/param.h>
56 char *TCID
="pipeio"; /* Test program identifier. */
57 int TST_TOTAL
=1; /* Total number of test cases. */
58 extern int Tst_count
; /* Test Case counter for tst_* routines */
60 #define SAFE_FREE(p) { if(p) { free(p); (p)=NULL; } }
62 /* To avoid extensive modifications to the code, use this bodge */
63 #define exit(x) myexit(x)
68 tst_resm (TFAIL
, "Test failed");
70 tst_resm (TPASS
, "Test passed");
74 #if defined(__linux__)
75 # define NBPW sizeof(int)
86 #define PIPE_NAMED "named pipe,"
87 #define PIPE_UNNAMED "sys pipe,"
89 #define BLOCKING_IO "blking,"
90 #define NON_BLOCKING_IO "non-blking,"
96 void sig_handler(), help(), usage(), prt_buf(), prt_examples();
100 int Nchildcomplete
= 0;
103 * Ensure PATH_MAX is define
107 #define PATH_MAX MAXPATHLEN
109 #define PATH_MAX 1024
110 #endif /* ! MAXPATHLEN */
111 #endif /* PATH_MAX */
120 int nb
; /* number of bytes read */
121 int num_wrters
=1; /* number of writers */
122 int num_writes
=1; /* number of writes per child */
123 int loop
=0; /* loop indefinitely */
124 int exit_error
= 1; /* exit on error #, zero means no exit */
125 int size
=327; /* default size */
126 int unpipe
= 0; /* un-named pipe if non-zero */
127 int verbose
=0; /* verbose mode if set */
128 int quiet
=0; /* quiet mode if set */
129 int num_rpt
=0; /* ping number, how often to print message */
130 int chld_wait
= 0; /* max time to wait between writes, 1 == no wait */
131 int parent_wait
= 0; /* max time to wait between reads, 1 == no wait*/
132 int ndelay
= O_NDELAY
; /* additional flag to open */
134 char *writebuf
= NULL
;
135 char *readbuf
= NULL
;
139 char pname
[PATH_MAX
]; /* contains the name of the unamed pipe */
140 char dir
[PATH_MAX
]; /* directory to create pipe in */
141 char *blk_type
; /* blocking i/o or not */
142 char *pipe_type
; /* type of pipe under test */
143 int fds
[2]; /* un-named pipe fds */
146 int empty_read
= 0; /* counter for the number of empty reads */
147 time_t start_time
, current_time
, diff_time
; /* start time, current time, diff of times */
148 int *count_word
; /* holds address where to write writers count */
149 int *pid_word
; /* holds address where to write writers pid */
151 int format_size
= -1;
152 int background
= 0; /* if set, put process in background */
154 int iotype
= 0; /* sync io */
155 char *toutput
; /* for getenv() */
157 struct sembuf sem_op
;
160 blk_type
= NON_BLOCKING_IO
;
162 sprintf(pname
,"%s.%d",PPATH
,getpid());
164 if( (toutput
=getenv("TOUTPUT")) != NULL
) {
165 if( strcmp( toutput
, "NOPASS") == 0 ) {
170 while ((c
=getopt (ac
, av
, "T:BbCc:D:d:he:Ef:i:I:ln:p:qs:uvW:w:P:")) != EOF
) {
179 case 'd': /* dir name */
182 case 'D': /* pipe name */
183 strcpy(pname
, optarg
);
185 case 'B': /* background */
188 case 'b': /* blocked */
190 blk_type
= BLOCKING_IO
;
194 "%s: --C option not supported on this architecture\n",
198 case 'c': /* number childern */
199 if (sscanf(optarg
, "%d", &num_wrters
) != 1) {
200 fprintf(stderr
,"%s: --c option invalid arg '%s'.\n",
205 else if ( num_wrters
<= 0 ) {
207 "%s: --c option must be greater than zero.\n",
213 case 'e': /* exit on error # */
214 if (sscanf(optarg
, "%d", &exit_error
) != 1) {
215 fprintf(stderr
,"%s: --e option invalid arg '%s'.\n",
220 else if ( exit_error
< 0 ) {
222 "%s: --e option must be greater than zero.\n",
233 case 'f': /* format of buffer on error */
251 case 'n': /* not output */
257 fprintf(stderr
,"%s: --f option invalid arg '%s'.\n",
260 "\tIt must be x(hex), o(octal), d(decimal), a(ascii) or n(none) with opt sz\n");
267 if ( sscanf(cp
, "%i", &format_size
) != 1 ) {
268 fprintf(stderr
,"%s: --f option invalid arg '%s'.\n",
271 "\tIt must be x(hex), o(octal), d(decimal), a(ascii) or n(none) with opt sz\n");
279 if((iotype
=lio_parse_io_arg1(optarg
)) == -1 ) {
281 "%s: --I arg is invalid, must be s, p, f, a, l, L or r.\n",
287 case 'l': /* loop forever */
292 case 'n': /* number writes per child */
293 if (sscanf(optarg
, "%d", &num_writes
) != 1) {
294 fprintf(stderr
,"%s: --i/n option invalid arg '%s'.\n",
299 else if ( num_writes
< 0 ) {
301 "%s: --i/n option must be greater than equal to zero.\n",
307 if (num_writes
== 0) /* loop forever */
311 case 'P': /* panic flag */
312 fprintf(stderr
, "%s: --P not supported on this architecture\n",
317 if (sscanf(optarg
, "%d", &num_rpt
) != 1) {
318 fprintf(stderr
,"%s: --p option invalid arg '%s'.\n",
323 else if ( num_rpt
< 0 ) {
325 "%s: --p option must be greater than equal to zero.\n",
331 case 'q': /* Quiet - NOPASS */
335 if (sscanf(optarg
, "%d", &size
) != 1) {
336 fprintf(stderr
,"%s: --s option invalid arg '%s'.\n",
341 else if ( size
<= 0 ) {
343 "%s: --s option must be greater than zero.\n",
350 unpipe
=1; /* un-named pipe */
352 case 'v': /* verbose */
355 case 'W': /* max wait time between writes */
356 d
= strtod(optarg
, &cp
);
358 fprintf(stderr
,"%s: --w option invalid arg '%s'.\n",
365 "%s: --w option must be greater than zero.\n",
370 parent_wait
= (int)(d
* 1000000.0);
372 case 'w': /* max wait time between writes */
373 d
= strtod(optarg
, &cp
);
375 fprintf(stderr
,"%s: --w option invalid arg '%s'.\n",
382 "%s: --w option must be greater than zero.\n",
387 chld_wait
= (int)(d
* 1000000.0);
396 if ( format_size
== -1 )
401 * If there is more than one writer, all writes and reads
402 * must be the same size. Only writes of a size <= PIPE_BUF
404 * Therefore, if size is greater than PIPE_BUF, we will break
405 * the writes into PIPE_BUF chunks. We will also increase the
406 * number of writes to ensure the same (or more) amount of
407 * data is written. This is the same as erroring and telling
408 * the user the new cmd line to do the same thing.
410 * pipeio -s 5000 -n 10 -c 5
411 * (each child will write at least 50000 bytes, since all
412 * writes have to be in 4096 chuncks or 13*4096 (53248)
413 * bytes will be written.) This is the same as:
414 * pipeio -s 4096 -n 13 -c 5
416 if ( size
> PIPE_BUF
&& num_wrters
> 1 ) {
418 /* we must set num_writes s.t. num_writes*num_wrters doesn't overflow later */
419 num_writes
=MIN(((long long)num_writes
*size
+PIPE_BUF
-1)/PIPE_BUF
, INT_MAX
/num_wrters
);
420 tst_resm (TINFO
, "adjusting i/o size to %d, and # of writes to %d",
421 PIPE_BUF
, num_writes
);
424 tst_resm (TINFO
, "adjusting i/o size to %d", PIPE_BUF
);
430 if ((writebuf
= (char *) malloc(size
)) == NULL
||
431 (readbuf
= (char *) malloc(size
)) == NULL
) {
432 tst_resm (TFAIL
, "malloc() failed: %s", strerror(errno
));
438 memset(writebuf
,'Z',size
);
440 writebuf
[size
-1] = 'A'; /* to detect partial read/write problem */
442 if((sem_id
= semget(IPC_PRIVATE
, 1, IPC_CREAT
|S_IRWXU
)) == -1) {
443 tst_brkm(TBROK
, tst_exit
, "Couldn't allocate semaphore: %s", strerror(errno
));
446 if(semctl(sem_id
, 0, SETVAL
, 0) == -1)
447 tst_brkm(TBROK
, tst_exit
, "Couldn't initialize semaphore value: %s", strerror(errno
));
450 if ( (n
=fork() ) == -1 ) {
451 tst_resm (TFAIL
, "fork() failed: %s", strerror(errno
));
454 else if ( n
!= 0 ) /* parent */
459 if ( pipe(fds
) == -1 ) {
460 tst_resm (TFAIL
, "pipe() failed to create un-named pipe: %s", strerror(errno
));
465 pipe_type
= PIPE_UNNAMED
;
466 blk_type
= UNNAMED_IO
;
468 if (strlen(dir
) && chdir(dir
) == -1) {
469 tst_resm (TFAIL
, "chdir(%s) failed: %s", dir
, strerror(errno
));
473 if ( stat(pname
, &stbuf
) == -1 ) {
475 if ( mkfifo(pname
,0777) == -1 ) {
476 tst_resm (TFAIL
, "mkfifo(%s,0777) failed: %s", pname
, strerror(errno
));
480 pipe_type
= PIPE_NAMED
;
486 printf("num_wrters = %d\n", num_wrters
);
490 signal(SIGCHLD
, sig_child
);
491 signal(SIGHUP
, sig_handler
);
492 signal(SIGINT
, sig_handler
);
493 signal(SIGQUIT
, sig_handler
);
495 signal(SIGRECOVERY
, sig_handler
);
496 #endif /* SIGRECOVERY */
498 sigset(SIGCHLD
, sig_child
);
499 sigset(SIGHUP
, sig_handler
);
500 sigset(SIGINT
, sig_handler
);
501 sigset(SIGQUIT
, sig_handler
);
503 sigset(SIGRECOVERY
, sig_handler
);
504 #endif /* SIGRECOVERY */
507 for (i
=num_wrters
; i
> 0; --i
) {
508 if ((c
=fork()) < 0) {
509 tst_resm (TFAIL
, "fork() failed: %s", strerror(errno
));
512 if (c
== 0) break; /* stop child from forking */
514 if (c
== 0) { /***** if child *****/
516 printf("child after fork pid = %d\n", getpid());
519 if ((write_fd
= open(pname
,O_WRONLY
)) == -1) {
520 tst_resm (TFAIL
, "child pipe open(%s, %#o) failed: %s", pname
, O_WRONLY
|ndelay
, strerror(errno
));
523 if(ndelay
&& fcntl(write_fd
, F_SETFL
, O_NONBLOCK
) == -1) {
524 tst_brkm(TBROK
, tst_exit
, "Failed setting the pipe to nonblocking mode: %s", strerror(errno
));
531 sem_op
= (struct sembuf
) {
537 if(semop(sem_id
, &sem_op
, 1) == -1)
538 tst_brkm(TBROK
, tst_exit
, "Couldn't raise the semaphore: %s", strerror(errno
));
541 pid_word
= (int *)&writebuf
[0];
542 count_word
= (int *)&writebuf
[NBPW
];
544 for (j
=0; j
< num_writes
|| loop
; ++j
) {
546 /* writes are only in one unit when the size of the write
548 * Therefore, if size is greater than PIPE_BUF, we will break
549 * the writes into PIPE_BUF chunks.
550 * All writes and read need to be same size.
554 * write pid and count in first two
559 *pid_word
= getpid();
561 if ((nb
= lio_write_buffer(write_fd
, iotype
, writebuf
, size
,
562 SIGUSR1
, &cp
, 0)) < 0 ) {
564 * If lio_write_buffer returns a negative number,
565 * the return will be -errno.
567 tst_resm (TFAIL
, "pass %d: lio_write_buffer(%s) failed; it returned %d: %s", j
, cp
, nb
, strerror(-nb
));
570 else if (nb
!= size
) {
571 tst_resm (TFAIL
, "pass %d: lio_write_buffer(%s) failed, write count %d, but expected to write %d",
575 tst_resm (TINFO
, "pass %d: pid %d: wrote %d bytes, expected %d bytes",
576 j
, getpid(), nb
, size
);
581 n
= lrand48() % chld_wait
;
587 if (c
> 0) { /***** if parent *****/
590 if ((read_fd
= open(pname
,O_RDONLY
)) == -1) {
591 tst_resm (TFAIL
, "parent pipe open(%s, %#o) failed: %s", pname
, O_RDONLY
, strerror(errno
));
594 if(ndelay
&& fcntl(read_fd
, F_SETFL
, O_NONBLOCK
) == -1) {
595 tst_brkm(TBROK
, tst_exit
, "Failed setting the pipe to nonblocking mode: %s", strerror(errno
));
602 sem_op
= (struct sembuf
) {
604 .sem_op
= -num_wrters
,
608 while(Nchildcomplete
< num_wrters
&& semop(sem_id
, &sem_op
, 1) == -1) {
612 tst_brkm(TBROK
, tst_exit
, "Couldn't wait on semaphore: %s", strerror(errno
));
615 for (i
=num_wrters
*num_writes
; i
> 0 || loop
; --i
) {
616 if(error
>= MAX_ERRS
|| empty_read
>= MAX_EMPTY
)
621 n
= lrand48() % parent_wait
;
625 if ((nb
= lio_read_buffer(read_fd
, iotype
, readbuf
, size
,
626 SIGUSR1
, &cp
, 0)) < 0 ) {
628 * If lio_read_buffer returns a negative number,
629 * the return will be -errno.
631 tst_resm (TFAIL
, "pass %d: lio_read_buffer(%s) failed; it returned %d: %s", i
, cp
, nb
, strerror(-nb
));
639 if ( Nchildcomplete
>= num_wrters
) {
641 tst_resm(TWARN
, "The children have died prematurely");
642 break; /* All children have died */
647 "%s: Nothing on the pipe (%d),read count %d (read not counted)\n",
648 TCID,empty_read,count);
654 } else if (nb
< size
&& size
<= PIPE_BUF
) {
655 tst_resm (TFAIL
, "pass %d: partial read from the pipe: read %d bytes, expected %d, read count %d",
658 } else if (nb
== size
) {
659 for (j
=2*NBPW
;j
< size
; ++j
) {
660 if (writebuf
[j
] != readbuf
[j
]) {
662 tst_resm (TFAIL
, "1 FAIL data error on byte %d; rd# %d, sz= %d, %s %s empty_reads= %d, err= %d",
663 j
, count
, size
, pipe_type
, blk_type
, empty_read
, error
);
664 prt_buf(&readbuf
,readbuf
,format_size
,format
);
666 if ( exit_error
&& exit_error
== error
)
674 if (verbose
|| (num_rpt
&& !(count
% num_rpt
))) {
675 current_time
= time(0);
676 diff_time
= current_time
- start_time
; /* elapsed time */
677 tst_resm (TFAIL
, "(%d) rd# %d, sz= %d, %s %s empty_reads= %d, err= %d\n",
678 (int)diff_time
,count
,size
,pipe_type
,blk_type
,empty_read
,error
);
684 tst_resm(TWARN
, "%d empty reads", empty_read
);
687 tst_resm (TFAIL
, "1 FAIL %d data errors on pipe, read size = %d, %s %s",
688 error
,size
,pipe_type
,blk_type
);
691 tst_resm (TPASS
, "1 PASS %d pipe reads complete, read size = %d, %s %s",
692 count
+1,size
,pipe_type
,blk_type
);
694 semctl(sem_id
, 0, IPC_RMID
);
708 fprintf(stderr
, "Usage: %s [-BbCEv][-c #writers][-D pname][-d dir][-h][-e exit_num][-f fmt][-l][-i #writes][-n #writes][-p num_rpt]\n\t[-s size][-W max_wait][-w max_wait][-u]\n",TCID
);
718 printf(" -B - execute actions in background\n\
719 -b - blocking reads and writes. default non-block\n\
720 -c #writers - number of writers (childern)\n\
721 -D pname - name of fifo (def tpipe<pid>)\n\
722 -d dir - cd to dir before creating named pipe\n\
723 - (silently ignored if used with -u)\n\
724 -h - print this help message\n\
725 -e exit_num - exit on error exit_num, 0 is ignore errors, 1 is default.\n\
726 -E - print cmd line examples and exit\n\
727 -f format - define format of bad buffer: h(hex), o(octal)\n\
728 d(decimal), a(ascii), n (none). hex is default\n\
729 option size can be added to control output\n\
730 -i #writes - number write per child, zero means forever.\n\
731 -I io_type - Specifies io type: s - sync, p - polled async, a - async (def s)\n\
732 l - listio sync, L - listio async, r - random\n\
733 -l - loop forever (implied by -n 0).\n\
734 -n #writes - same as -i (for compatability).\n\
735 -p num_rpt - number of reads before a report\n\
736 -q - quiet mode, no PASS results are printed\n\
737 -s size - size of read and write (def 327)\n\
738 if size >= 4096, i/o will be in 4096 chuncks\n\
739 -w max_wait - max time (seconds) for sleep between writes.\n\
740 max_wait is interpreted as a double with ms accuracy.\n\
741 -W max_wait - max time (seconds) for sleep between reads\n\
742 max_wait is interpreted as a double with ms accuracy.\n\
743 -u - un-named pipe instead of named pipe\n\
744 -v - verbose mode, all writes/reads resutlts printed\n");
751 prt_buf(long addr
, char * buf
, int length
, int format
)
755 int num_words
= length
/NBPW
; /* given length in bytes, get length in words */
756 int width
; /* number of columns */
757 int extra_words
= 0; /* odd or even number of words */
764 if ( format
== NO_OUT
) /* if no output wanted, return */
767 if (length
% NBPW
) ++num_words
; /* is length in full words? */
768 if (format
== ASCII
) {
772 /* do we have an odd number of words? */
773 extra_words
= num_words
%width
;
775 for(i
=0; i
< num_words
; ++i
, a
+= NBPW
, addr
++) {
778 if (i
> 0 && format
!= ASCII
) {
780 * print the ascii equivalent of the data
781 * before beginning the next line of output.
783 memset(c
,0x00,width
*NBPW
);
785 * get the last 2 words printed
787 memcpy(c
,a
-(width
*NBPW
),width
*NBPW
);
788 for (p
= c
; (p
-c
) < width
*NBPW
; ++p
) {
789 if (*p
< '!' || *p
> '~')
792 printf("\t%16.16s",c
);
794 printf("\n%7lo: ",addr
);
795 /***printf("\n%7o (%d): ",addr,i);***/
800 printf("%16.16lx ",*word
);
803 printf("%10.10ld ",*word
);
807 for (p
= b
; (p
-b
) < NBPW
; ++p
) {
808 if (*p
< '!' || *p
> '~')
814 printf("%22.22lo ",*word
);
818 if (format
!= ASCII
) {
820 * print the ascii equivalent of the last words in the buffer
823 memset(c
,0x00,width
*NBPW
);
824 if (extra_words
) width
= extra_words
; /* odd number of words */
825 memcpy(c
,a
-(width
*NBPW
),width
*NBPW
);
826 for (p
= c
; (p
-c
) < width
*NBPW
; ++p
) {
827 if (*p
< '!' || *p
> '~')
831 printf("\t%16.16s",c
);
833 printf("\t\t%16.8s",c
);
842 printf("%s -c 5 -i 0 -s 4090 -b\n", TCID
);
843 printf("%s -c 5 -i 0 -s 4090 -b -u \n", TCID
);
844 printf("%s -c 5 -i 0 -s 4090 -b -W 3 -w 3 \n", TCID
);
855 printf("parent: received SIGCHLD\n");
857 waitpid(-1, &status
, WNOHANG
);
859 signal(SIGCHLD
, sig_child
);
861 sigset(SIGCHLD
, sig_child
);
869 if ( sig
== SIGRECOVERY
) {
870 printf("%s: received SIGRECOVERY, count = %d\n", TCID
, count
);
873 signal(sig
, sig_handler
);
875 sigset(sig
, sig_handler
);
880 printf("%s: received unexpected signal: %d\n", TCID
, sig
);