blob: da6a39774208346bcdc22cf278b56a89e871c410 [file] [log] [blame]
plars865695b2001-08-27 22:15:12 +00001/*
nstrazf471e112002-10-31 15:57:48 +00002 * 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
Wanlong Gaofed96412012-10-24 10:10:29 +080020 * with this program; if not, write the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
nstrazf471e112002-10-31 15:57:48 +000022 *
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 *
plars865695b2001-08-27 22:15:12 +000032 */
subrata_modak25e21872009-03-19 07:10:02 +000033/* $Header: /cvsroot/ltp/ltp/testcases/kernel/ipc/pipeio/pipeio.c,v 1.18 2009/03/19 07:10:02 subrata_modak Exp $ */
plars865695b2001-08-27 22:15:12 +000034/*
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>
robbiew045fd162002-12-04 18:42:53 +000045#include <time.h>
plars865695b2001-08-27 22:15:12 +000046#include <errno.h>
47#include <string.h>
48#include <signal.h>
49#include <sys/stat.h>
subrata_modakea37be82008-12-11 13:17:49 +000050#include <sys/sem.h>
plars865695b2001-08-27 22:15:12 +000051
52#include "tlibio.h"
53
robbiew92b688b2004-03-01 22:36:38 +000054#include "test.h"
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +080055#include "safe_macros.h"
robbiew92b688b2004-03-01 22:36:38 +000056
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +080057char *TCID = "pipeio";
58int TST_TOTAL = 1;
robbiew92b688b2004-03-01 22:36:38 +000059
Garrett Cooperdf3eb162010-11-28 22:44:32 -080060#define SAFE_FREE(p) { if (p) { free(p); (p)=NULL; } }
robbiew92b688b2004-03-01 22:36:38 +000061
mridgef7298c72005-12-05 19:14:37 +000062#if defined(__linux__)
Wanlong Gao354ebb42012-12-07 10:10:04 +080063#define NBPW sizeof(int)
plars865695b2001-08-27 22:15:12 +000064#endif
65
plars865695b2001-08-27 22:15:12 +000066#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
subrata_modakea37be82008-12-11 13:17:49 +000079#define MAX_ERRS 16
80#define MAX_EMPTY 256
81
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +080082static int parse_options(int argc, char *argv[]);
83static void setup(int argc, char *argv[]);
84static void cleanup(void);
plars865695b2001-08-27 22:15:12 +000085
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +080086static void do_child(void);
87static void do_parent(void);
plars865695b2001-08-27 22:15:12 +000088
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +080089static void help(void), usage(void), prt_examples(void);
90static void prt_buf(char **addr, char *buf, int length, int format);
91static void sig_child(int sig);
92static int check_rw_buf(void);
plars865695b2001-08-27 22:15:12 +000093
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +080094static volatile sig_atomic_t nchildcompleted;
95
96/* variables may be modified in setup() */
97static int num_writers = 1; /* number of writers */
98static int num_writes = 1; /* number of writes per child */
99static int loop; /* loop indefinitely */
100static int exit_error = 1; /* exit on error #, zero means no exit */
101static int size = 327; /* default size */
102static int unpipe; /* un-named pipe if non-zero */
103static int verbose; /* verbose mode if set */
104static int quiet; /* quiet mode if set */
105static int num_rpt; /* ping number, how often to print message */
106static int chld_wait; /* max time to wait between writes, 1 == no wait */
107static int parent_wait; /* max time to wait between reads, 1 == no wait */
108static int ndelay = O_NDELAY; /* additional flag to open */
109static char *writebuf;
110static char *readbuf;
111static char pname[PATH_MAX]; /* contains the name of the named pipe */
112static char *blk_type = NON_BLOCKING_IO; /* blocking i/o or not */
113static char *pipe_type; /* type of pipe under test */
114static int format = HEX;
115static int format_size = -1;
116static int iotype; /* sync io */
117
118/* variables will be modified in running */
119static int error;
120static int count;
121static int read_fd;
122static int write_fd;
123static int empty_read;
124static int sem_id;
125
126static union semun {
127 int val;
128 struct semid_ds *buf;
129 unsigned short int *array;
130} u;
131
132int main(int ac, char *av[])
plars865695b2001-08-27 22:15:12 +0000133{
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800134 int i;
135 unsigned int j;
136 unsigned int uwait_iter = 1000, uwait_total = 5000000;
137 pid_t child;
Garrett Cooper2c282152010-12-16 00:55:50 -0800138
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800139 setup(ac, av);
plars865695b2001-08-27 22:15:12 +0000140
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800141 for (i = num_writers; i > 0; --i) {
142
143 child = tst_fork();
144 switch (child) {
145 case -1:
146 tst_brkm(TBROK | TERRNO, cleanup, "fork() failed");
147 case 0:
148 do_child();
149 exit(0);
150 default:
151 break;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800152 }
plars865695b2001-08-27 22:15:12 +0000153 }
154
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800155 do_parent();
156
157 if (empty_read)
158 tst_resm(TWARN, "%d empty reads", empty_read);
159
160 if (error) {
161 tst_resm(TFAIL, "%d data errors on pipe, read size = %d, %s %s",
162 error, size, pipe_type, blk_type);
163 } else if (!quiet) {
164 tst_resm(TPASS, "%d pipe reads complete, read size = %d, %s %s",
165 count + 1, size, pipe_type, blk_type);
166 }
167
168 /*
169 * wait for all children to finish, timeout after uwait_total
170 * semtimedop might not be available everywhere
171 */
172 for (j = 0; j < uwait_total; j += uwait_iter) {
173 if (semctl(sem_id, 1, GETVAL) == 0)
174 break;
175 usleep(uwait_iter);
176 }
177
178 if (j >= uwait_total) {
179 tst_resm(TWARN,
180 "Timed out waiting for child processes to exit");
181 }
182
183 cleanup();
184 tst_exit();
185}
186
187static int parse_options(int argc, char *argv[])
188{
189 char *cp;
190 int c;
191 int ret = 0;
192 static double d;
193
194 while ((c = getopt(argc, argv, "T:bc:D:he:Ef:i:I:ln:p:qs:uvW:w:"))
195 != -1) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800196 switch (c) {
robbiew92b688b2004-03-01 22:36:38 +0000197 case 'T':
198 TCID = optarg;
199 break;
plars865695b2001-08-27 22:15:12 +0000200 case 'h':
201 help();
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800202 ret = 1;
plars865695b2001-08-27 22:15:12 +0000203 break;
204 case 'D': /* pipe name */
205 strcpy(pname, optarg);
206 break;
plars865695b2001-08-27 22:15:12 +0000207 case 'b': /* blocked */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800208 ndelay = 0;
plars865695b2001-08-27 22:15:12 +0000209 blk_type = BLOCKING_IO;
210 break;
plars865695b2001-08-27 22:15:12 +0000211 case 'c': /* number childern */
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800212 if (sscanf(optarg, "%d", &num_writers) != 1) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800213 fprintf(stderr,
214 "%s: --c option invalid arg '%s'.\n",
215 TCID, optarg);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800216 ret = 1;
217 } else if (num_writers <= 0) {
218 fprintf(stderr, "%s: --c option must be "
219 "greater than zero.\n", TCID);
220 ret = 1;
plars865695b2001-08-27 22:15:12 +0000221 }
222 break;
223 case 'e': /* exit on error # */
224 if (sscanf(optarg, "%d", &exit_error) != 1) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800225 fprintf(stderr,
226 "%s: --e option invalid arg '%s'.\n",
227 TCID, optarg);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800228 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800229 } else if (exit_error < 0) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800230 fprintf(stderr, "%s: --e option must be "
231 "greater than zero.\n", TCID);
232 ret = 1;
plars865695b2001-08-27 22:15:12 +0000233 }
234 break;
plars865695b2001-08-27 22:15:12 +0000235 case 'E':
236 prt_examples();
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800237 ret = 1;
plars865695b2001-08-27 22:15:12 +0000238 break;
239 case 'f': /* format of buffer on error */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800240 switch (optarg[0]) {
plars865695b2001-08-27 22:15:12 +0000241 case 'x':
242 case 'X':
243 format = HEX;
244 break;
245 case 'o':
246 case 'O':
247 format = OCTAL;
248 break;
249 case 'd':
250 case 'D':
251 format = DECIMAL;
252 break;
253 case 'a':
254 case 'A':
255 format = ASCII;
256 break;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800257 case 'n': /* not output */
plars865695b2001-08-27 22:15:12 +0000258 case 'N':
259 format = NO_OUT;
260 break;
261
Wanlong Gao354ebb42012-12-07 10:10:04 +0800262 default:
plars865695b2001-08-27 22:15:12 +0000263 fprintf(stderr,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800264 "%s: --f option invalid arg '%s'.\n",
265 TCID, optarg);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800266 fprintf(stderr, "\tIt must be x(hex), o(octal),"
267 "d(decimal), a(ascii) or n(none) with "
268 "opt sz\n");
269 ret = 1;
plars865695b2001-08-27 22:15:12 +0000270 break;
271 }
272 cp = optarg;
273 cp++;
Garrett Cooperdf3eb162010-11-28 22:44:32 -0800274 if (*cp) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800275 if (sscanf(cp, "%i", &format_size) != 1) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800276 fprintf(stderr, "%s: --f option invalid"
277 "arg '%s'.\n", TCID, optarg);
278 fprintf(stderr, "\tIt must be x(hex),"
279 "o(octal), d(decimal), a(ascii)"
280 " or n(none) with opt sz\n");
281 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800282 break;
283 }
plars865695b2001-08-27 22:15:12 +0000284 }
285 break;
286
Wanlong Gao354ebb42012-12-07 10:10:04 +0800287 case 'I':
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800288 iotype = lio_parse_io_arg1(optarg);
289 if (iotype == -1) {
290 fprintf(stderr, "%s: --I arg is invalid, "
291 "must be s, p, f, a, l, L or r.\n",
Wanlong Gao354ebb42012-12-07 10:10:04 +0800292 TCID);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800293 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800294 }
plars865695b2001-08-27 22:15:12 +0000295 break;
296
297 case 'l': /* loop forever */
298 ++loop;
299 break;
300
301 case 'i':
302 case 'n': /* number writes per child */
303 if (sscanf(optarg, "%d", &num_writes) != 1) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800304 fprintf(stderr, "%s: --i/n option invalid "
305 "arg '%s'.\n", TCID, optarg);
306 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800307 } else if (num_writes < 0) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800308 fprintf(stderr, "%s: --i/n option must be "
309 "greater than equal to zero.\n",
Wanlong Gao354ebb42012-12-07 10:10:04 +0800310 TCID);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800311 ret = 1;
plars865695b2001-08-27 22:15:12 +0000312 }
313
314 if (num_writes == 0) /* loop forever */
315 ++loop;
plars865695b2001-08-27 22:15:12 +0000316 break;
317 case 'p': /* ping */
318 if (sscanf(optarg, "%d", &num_rpt) != 1) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800319 fprintf(stderr,
320 "%s: --p option invalid arg '%s'.\n",
321 TCID, optarg);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800322 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800323 } else if (num_rpt < 0) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800324 fprintf(stderr, "%s: --p option must be greater"
325 " than equal to zero.\n", TCID);
326 ret = 1;
plars865695b2001-08-27 22:15:12 +0000327 }
328 break;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800329 case 'q': /* Quiet - NOPASS */
330 quiet = 1;
plars865695b2001-08-27 22:15:12 +0000331 break;
332 case 's': /* size */
333 if (sscanf(optarg, "%d", &size) != 1) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800334 fprintf(stderr,
335 "%s: --s option invalid arg '%s'.\n",
336 TCID, optarg);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800337 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800338 } else if (size <= 0) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800339 fprintf(stderr, "%s: --s option must be greater"
340 " than zero.\n", TCID);
341 ret = 1;
plars865695b2001-08-27 22:15:12 +0000342 }
343 break;
344 case 'u':
Wanlong Gao354ebb42012-12-07 10:10:04 +0800345 unpipe = 1; /* un-named pipe */
plars865695b2001-08-27 22:15:12 +0000346 break;
347 case 'v': /* verbose */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800348 verbose = 1;
plars865695b2001-08-27 22:15:12 +0000349 break;
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800350 case 'W': /* max wait time between reads */
plars865695b2001-08-27 22:15:12 +0000351 d = strtod(optarg, &cp);
352 if (*cp != '\0') {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800353 fprintf(stderr,
354 "%s: --w option invalid arg '%s'.\n",
355 TCID, optarg);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800356 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800357 } else if (d < 0) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800358 fprintf(stderr, "%s: --w option must be greater"
359 " than zero.\n", TCID);
360 ret = 1;
plars865695b2001-08-27 22:15:12 +0000361 }
362 parent_wait = (int)(d * 1000000.0);
363 break;
364 case 'w': /* max wait time between writes */
365 d = strtod(optarg, &cp);
366 if (*cp != '\0') {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800367 fprintf(stderr,
368 "%s: --w option invalid arg '%s'.\n",
369 TCID, optarg);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800370 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800371 } else if (d < 0) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800372 fprintf(stderr, "%s: --w option must be greater"
373 " than zero.\n", TCID);
374 ret = 1;
plars865695b2001-08-27 22:15:12 +0000375 }
376 chld_wait = (int)(d * 1000000.0);
377 break;
378 case '?':
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800379 ret = 1;
plars865695b2001-08-27 22:15:12 +0000380 break;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800381 }
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800382
383 if (ret == 1) {
384 usage();
385 return ret;
386 }
plars865695b2001-08-27 22:15:12 +0000387 }
388
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800389 return ret;
390}
391
392static void setup(int argc, char *argv[])
393{
394 int ret;
395 char *toutput;
396 int fds[2];
397
398 tst_sig(FORK, DEF_HANDLER, cleanup);
399
400 TEST_PAUSE;
401
402 tst_tmpdir();
403
404 if (signal(SIGCHLD, sig_child) == SIG_ERR) {
405 tst_brkm(TBROK | TERRNO, cleanup,
406 "set signal handler for SIGCHLD failed");
407 }
408
409 toutput = getenv("TOUTPUT");
410 if (toutput != NULL && strcmp(toutput, "NOPASS") == 0)
411 quiet = 1;
412
413 sprintf(pname, "%s", "tpipe");
414
415 ret = parse_options(argc, argv);
416 if (ret == 1)
417 tst_brkm(TBROK, cleanup, "options parse error");
418
Garrett Cooper8fb1cdb2010-11-28 22:56:35 -0800419 if (format_size == -1)
plars865695b2001-08-27 22:15:12 +0000420 format_size = size;
421
422 /*
plars865695b2001-08-27 22:15:12 +0000423 * If there is more than one writer, all writes and reads
424 * must be the same size. Only writes of a size <= PIPE_BUF
425 * are atomic. T
426 * Therefore, if size is greater than PIPE_BUF, we will break
427 * the writes into PIPE_BUF chunks. We will also increase the
subrata_modak4bb656a2009-02-26 12:02:09 +0000428 * number of writes to ensure the same (or more) amount of
plars865695b2001-08-27 22:15:12 +0000429 * data is written. This is the same as erroring and telling
430 * the user the new cmd line to do the same thing.
431 * Example:
Wanlong Gao354ebb42012-12-07 10:10:04 +0800432 * pipeio -s 5000 -n 10 -c 5
433 * (each child will write at least 50000 bytes, since all
434 * writes have to be in 4096 chuncks or 13*4096 (53248)
435 * bytes will be written.) This is the same as:
plars865695b2001-08-27 22:15:12 +0000436 * pipeio -s 4096 -n 13 -c 5
437 */
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800438 if (size > PIPE_BUF && num_writers > 1) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800439 if (!loop) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800440 /*
441 * we must set num_writes*num_writers
442 * doesn't overflow later
443 */
444 num_writes = MIN(((long long)num_writes * size +
445 PIPE_BUF - 1) / PIPE_BUF,
446 INT_MAX / num_writers);
447 tst_resm(TINFO, "adjusting i/o size to %d, and # of "
448 "writes to %d", PIPE_BUF, num_writes);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800449 } else {
450 tst_resm(TINFO, "adjusting i/o size to %d", PIPE_BUF);
451 }
452 size = PIPE_BUF;
plars865695b2001-08-27 22:15:12 +0000453 }
454
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800455 writebuf = SAFE_MALLOC(cleanup, size);
456 readbuf = SAFE_MALLOC(cleanup, size);
plars865695b2001-08-27 22:15:12 +0000457
Wanlong Gao354ebb42012-12-07 10:10:04 +0800458 memset(writebuf, 'Z', size);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800459 writebuf[size - 1] = 'A';
plars865695b2001-08-27 22:15:12 +0000460
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800461 sem_id = semget(IPC_PRIVATE, 2, IPC_CREAT | S_IRWXU);
462 if (sem_id == -1) {
463 tst_brkm(TBROK | TERRNO, cleanup,
464 "Couldn't allocate semaphore");
subrata_modakea37be82008-12-11 13:17:49 +0000465 }
466
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800467 if (semctl(sem_id, 0, SETVAL, u) == -1) {
468 tst_brkm(TBROK | TERRNO, cleanup,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800469 "Couldn't initialize semaphore 0 value");
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800470 }
Jan Stancekc5bb3eb2011-12-15 10:35:27 +0100471
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800472 if (semctl(sem_id, 1, SETVAL, u) == -1) {
473 tst_brkm(TBROK | TERRNO, cleanup,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800474 "Couldn't initialize semaphore 1 value");
plars865695b2001-08-27 22:15:12 +0000475 }
476
Garrett Cooperdf3eb162010-11-28 22:44:32 -0800477 if (unpipe) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800478 SAFE_PIPE(cleanup, fds);
plars865695b2001-08-27 22:15:12 +0000479 read_fd = fds[0];
480 write_fd = fds[1];
481 pipe_type = PIPE_UNNAMED;
482 blk_type = UNNAMED_IO;
483 } else {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800484 if (mkfifo(pname, 0777) == -1) {
485 tst_brkm(TBROK | TERRNO, cleanup,
486 "mkfifo(%s, 0777) failed", pname);
plars865695b2001-08-27 22:15:12 +0000487 }
488 pipe_type = PIPE_NAMED;
489 }
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800490}
plars865695b2001-08-27 22:15:12 +0000491
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800492static void cleanup(void)
493{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800494 SAFE_FREE(writebuf);
subrata_modakbdbaec52009-02-26 12:14:51 +0000495 SAFE_FREE(readbuf);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800496
497 semctl(sem_id, 0, IPC_RMID);
498
499 if (!unpipe)
500 SAFE_UNLINK(NULL, pname);
501
502 tst_rmdir();
plars865695b2001-08-27 22:15:12 +0000503}
504
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800505static void do_child(void)
plars865695b2001-08-27 22:15:12 +0000506{
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800507 int *count_word; /* holds address where to write writers count */
508 int *pid_word; /* holds address where to write writers pid */
509 int nb, j;
510 long clock;
511 char *cp;
512 long int n;
513 struct sembuf sem_op;
514 pid_t self_pid = getpid();
plars865695b2001-08-27 22:15:12 +0000515
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800516 if (!unpipe) {
517 write_fd = open(pname, O_WRONLY);
518 if (write_fd == -1) {
519 fprintf(stderr, "child pipe open(%s, %#o) failed",
520 pname, O_WRONLY | ndelay);
521 exit(1);
522 }
523 if (ndelay && fcntl(write_fd, F_SETFL, O_NONBLOCK) == -1) {
524 fprintf(stderr, "Failed setting the pipe to "
525 "nonblocking mode");
526 exit(1);
527 }
528 } else {
529 close(read_fd);
530 }
531
532 sem_op = (struct sembuf) {
533 .sem_num = 0, .sem_op = 1, .sem_flg = 0};
534
535 if (semop(sem_id, &sem_op, 1) == -1) {
536 fprintf(stderr, "child: %d couldn't raise the semaphore 0",
537 self_pid);
538 exit(1);
539 }
540
541 pid_word = (int *)&writebuf[0];
542 count_word = (int *)&writebuf[NBPW];
543
544 for (j = 0; j < num_writes || loop; ++j) {
545 /*
546 * writes are only in one unit when the size of the write
547 * is <= PIPE_BUF.
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.
551 */
552
553 /*
554 * write pid and count in first two
555 * words of buffer
556 */
557 *count_word = j;
558 *pid_word = self_pid;
559
560 nb = lio_write_buffer(write_fd, iotype, writebuf, size,
561 SIGUSR1, &cp, 0);
562 if (nb < 0) {
563 /*
564 * If lio_write_buffer returns a negative number,
565 * the return will be -errno.
566 */
567 fprintf(stderr, "pass %d: lio_write_buffer(%s) failed;"
568 " it returned %d: %s",
569 j, cp, nb, strerror(-nb));
570 exit(1);
571 } else if (nb != size) {
572 fprintf(stderr, "pass %d: lio_write_buffer(%s) failed,"
573 " write count %d, but expected to write %d",
574 j, cp, nb, size);
575 }
576 if (verbose) {
577 fprintf(stderr, "pass %d: pid %d: wrote %d bytes,"
578 "expected %d bytes",
579 j, self_pid, nb, size);
580 }
581
582 if (chld_wait) {
583 clock = time(0);
584 srand48(clock);
585 n = lrand48() % chld_wait;
586 usleep(n);
587 }
588 fflush(stderr);
589 }
590
591 /* child waits until parent completes open() */
592 sem_op = (struct sembuf) {
593 .sem_num = 1, .sem_op = -1, .sem_flg = 0};
594 if (semop(sem_id, &sem_op, 1) == -1)
595 fprintf(stderr, "Couldn't lower the semaphore 1");
596
597 exit(0);
plars865695b2001-08-27 22:15:12 +0000598}
599
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800600static int check_rw_buf(void)
601{
602 int i;
603
604 for (i = 2 * NBPW; i < size; ++i) {
605 if (writebuf[i] != readbuf[i]) {
606 ++error;
607 tst_resm(TFAIL,
608 "FAIL data error on byte %d; rd# %d, sz= %d, "
609 "%s %s empty_reads= %d, err= %d",
610 i, count, size, pipe_type, blk_type,
611 empty_read, error);
612 prt_buf(&readbuf, readbuf, format_size, format);
613 fflush(stdout);
614 return 1;
615 }
616 }
617
618 return 0;
619}
620
621static void do_parent(void)
622{
623 int i, nb;
624 long clock;
625 time_t start_time, current_time, diff_time;
626 char *cp;
627 long int n;
628 struct sembuf sem_op;
629
630 start_time = time(0);
631 if (!unpipe) {
632 read_fd = SAFE_OPEN(cleanup, pname, O_RDONLY);
633 if (ndelay && fcntl(read_fd, F_SETFL, O_NONBLOCK) == -1) {
634 tst_brkm(TBROK | TERRNO, cleanup,
635 "Failed setting the pipe to nonblocking mode");
636 }
637 } else {
638 SAFE_CLOSE(cleanup, write_fd);
639 }
640
641 /* raise semaphore so children can exit */
642 sem_op = (struct sembuf) {
643 .sem_num = 1, .sem_op = num_writers, .sem_flg = 0};
644 if (semop(sem_id, &sem_op, 1) == -1) {
645 tst_brkm(TBROK | TERRNO, cleanup,
646 "Couldn't raise the semaphore 1");
647 }
648
649 sem_op = (struct sembuf) {
650 .sem_num = 0, .sem_op = -num_writers, .sem_flg = 0};
651
652 while (nchildcompleted < num_writers
653 && semop(sem_id, &sem_op, 1) == -1) {
654 if (errno == EINTR)
655 continue;
656 tst_brkm(TBROK | TERRNO, cleanup,
657 "Couldn't wait on semaphore 0");
658 }
659
660 /* parent start to read pipe */
661 for (i = num_writers * num_writes; i > 0 || loop; --i) {
662 if (error >= MAX_ERRS || empty_read >= MAX_EMPTY)
663 break;
664 if (parent_wait) {
665 clock = time(0);
666 srand48(clock);
667 n = lrand48() % parent_wait;
668 usleep(n);
669 }
670 ++count;
671 nb = lio_read_buffer(read_fd, iotype, readbuf, size,
672 SIGUSR1, &cp, 0);
673 if (nb < 0) {
674 /*
675 * If lio_read_buffer returns a negative number,
676 * the return will be -errno.
677 */
678 tst_resm(TFAIL, "pass %d: lio_read_buffer(%s) failed; "
679 "returned %d: %s", i, cp, nb, strerror(-nb));
680 ++i;
681 count--;
682 error++;
683 continue;
684 } else {
685 if (nb == 0) {
686 if (nchildcompleted >= num_writers && !loop) {
687 tst_resm(TWARN, "The children have "
688 "died prematurely");
689 break; /* All children have died */
690 }
691 empty_read++;
692 ++i;
693 count--;
694 continue;
695 } else if (nb < size && size <= PIPE_BUF) {
696 tst_resm(TFAIL, "pass %d: partial read from the"
697 " pipe: read %d bytes, expected %d, "
698 "read count %d", i, nb, size, count);
699 ++error;
700 } else if (nb == size) {
701 check_rw_buf();
702 if (exit_error && exit_error == error)
703 return;
704 }
705
706 if (verbose || (num_rpt && !(count % num_rpt))) {
707 current_time = time(0);
708 diff_time = current_time - start_time;
709 tst_resm(TFAIL,
710 "(%d) rd# %d, sz= %d, %s %s "
711 "empty_reads= %d, err= %d\n",
712 (int)diff_time, count, size,
713 pipe_type, blk_type,
714 empty_read, error);
715 fflush(stdout);
716 }
717 }
718 }
719}
720
721static void usage(void)
722{
723 fprintf(stderr, "Usage: %s [-bEv][-c #writers][-D pname][-h]"
724 "[-e exit_num][-f fmt][-l][-i #writes][-n #writes][-p num_rpt]"
725 "\n\t[-s size][-W max_wait][-w max_wait][-u]\n", TCID);
726 fflush(stderr);
727}
728
729static void help(void)
plars865695b2001-08-27 22:15:12 +0000730{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800731 usage();
plars865695b2001-08-27 22:15:12 +0000732
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800733 printf(" -b - blocking reads and writes. default non-block\n\
plars865695b2001-08-27 22:15:12 +0000734 -c #writers - number of writers (childern)\n\
735 -D pname - name of fifo (def tpipe<pid>)\n\
plars865695b2001-08-27 22:15:12 +0000736 -h - print this help message\n\
737 -e exit_num - exit on error exit_num, 0 is ignore errors, 1 is default.\n\
738 -E - print cmd line examples and exit\n\
739 -f format - define format of bad buffer: h(hex), o(octal)\n\
740 d(decimal), a(ascii), n (none). hex is default\n\
741 option size can be added to control output\n\
742 -i #writes - number write per child, zero means forever.\n\
743 -I io_type - Specifies io type: s - sync, p - polled async, a - async (def s)\n\
744 l - listio sync, L - listio async, r - random\n\
745 -l - loop forever (implied by -n 0).\n\
746 -n #writes - same as -i (for compatability).\n\
747 -p num_rpt - number of reads before a report\n\
748 -q - quiet mode, no PASS results are printed\n\
749 -s size - size of read and write (def 327)\n\
750 if size >= 4096, i/o will be in 4096 chuncks\n\
751 -w max_wait - max time (seconds) for sleep between writes.\n\
752 max_wait is interpreted as a double with ms accuracy.\n\
753 -W max_wait - max time (seconds) for sleep between reads\n\
754 max_wait is interpreted as a double with ms accuracy.\n\
755 -u - un-named pipe instead of named pipe\n\
756 -v - verbose mode, all writes/reads resutlts printed\n");
757
758 fflush(stdout);
plars865695b2001-08-27 22:15:12 +0000759}
760
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800761static void prt_buf(char **addr, char *buf, int length, int format)
plars865695b2001-08-27 22:15:12 +0000762{
plars865695b2001-08-27 22:15:12 +0000763 int i;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800764 int num_words = length / NBPW; /* given length in bytes, get length in words */
plars865695b2001-08-27 22:15:12 +0000765 int width; /* number of columns */
robbiew33abc162005-10-03 17:13:35 +0000766 int extra_words = 0; /* odd or even number of words */
plars865695b2001-08-27 22:15:12 +0000767 char *a = buf;
768 char b[NBPW];
Wanlong Gao354ebb42012-12-07 10:10:04 +0800769 char c[NBPW * 2];
plars865695b2001-08-27 22:15:12 +0000770 char *p;
771 long *word;
772
Wanlong Gao354ebb42012-12-07 10:10:04 +0800773 if (format == NO_OUT) /* if no output wanted, return */
plars865695b2001-08-27 22:15:12 +0000774 return;
775
Wanlong Gao354ebb42012-12-07 10:10:04 +0800776 if (length % NBPW)
777 ++num_words; /* is length in full words? */
plars865695b2001-08-27 22:15:12 +0000778 if (format == ASCII) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800779 width = 3;
plars865695b2001-08-27 22:15:12 +0000780 } else {
781 width = 2;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800782 /* do we have an odd number of words? */
783 extra_words = num_words % width;
plars865695b2001-08-27 22:15:12 +0000784 }
Wanlong Gao354ebb42012-12-07 10:10:04 +0800785 for (i = 0; i < num_words; ++i, a += NBPW, addr++) {
786 word = (long *)a;
787 if (!(i % width)) {
plars865695b2001-08-27 22:15:12 +0000788 if (i > 0 && format != ASCII) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800789 /*
790 * print the ascii equivalent of the data
791 * before beginning the next line of output.
792 */
793 memset(c, 0x00, width * NBPW);
794 /*
795 * get the last 2 words printed
796 */
797 memcpy(c, a - (width * NBPW), width * NBPW);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800798 for (p = c; (p - c) < (int)(width*NBPW); ++p) {
plars865695b2001-08-27 22:15:12 +0000799 if (*p < '!' || *p > '~')
800 *p = '.';
801 }
Wanlong Gao354ebb42012-12-07 10:10:04 +0800802 printf("\t%16.16s", c);
plars865695b2001-08-27 22:15:12 +0000803 }
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800804 printf("\n%p: ", addr);
plars865695b2001-08-27 22:15:12 +0000805 /***printf("\n%7o (%d): ",addr,i);***/
806 }
807
808 switch (format) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800809 case HEX:
810 printf("%16.16lx ", *word);
811 break;
812 case DECIMAL:
813 printf("%10.10ld ", *word);
814 break;
815 case ASCII:
816 memcpy(b, a, NBPW);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800817 for (p = b; (p - b) < (int)NBPW; ++p) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800818 if (*p < '!' || *p > '~')
819 *p = '.';
820 }
821 printf("%8.8s ", b);
822 break;
823 default:
824 printf("%22.22lo ", *word);
825 break;
plars865695b2001-08-27 22:15:12 +0000826 }
827 }
828 if (format != ASCII) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800829 /*
830 * print the ascii equivalent of the last words in the buffer
831 * before returning.
832 */
833 memset(c, 0x00, width * NBPW);
834 if (extra_words)
835 width = extra_words; /* odd number of words */
836 memcpy(c, a - (width * NBPW), width * NBPW);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800837 for (p = c; (p - c) < (int)(width * NBPW); ++p) {
plars865695b2001-08-27 22:15:12 +0000838 if (*p < '!' || *p > '~')
839 *p = '.';
840 }
subrata_modak4bb656a2009-02-26 12:02:09 +0000841 if (width == 2)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800842 printf("\t%16.16s", c);
plars865695b2001-08-27 22:15:12 +0000843 else
Wanlong Gao354ebb42012-12-07 10:10:04 +0800844 printf("\t\t%16.8s", c);
plars865695b2001-08-27 22:15:12 +0000845 }
846 printf("\n");
847 fflush(stdout);
848}
849
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800850static void prt_examples(void)
plars865695b2001-08-27 22:15:12 +0000851{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800852 printf("%s -c 5 -i 0 -s 4090 -b\n", TCID);
853 printf("%s -c 5 -i 0 -s 4090 -b -u \n", TCID);
854 printf("%s -c 5 -i 0 -s 4090 -b -W 3 -w 3 \n", TCID);
plars865695b2001-08-27 22:15:12 +0000855}
856
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800857static void sig_child(int sig)
plars865695b2001-08-27 22:15:12 +0000858{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800859 int status;
plars865695b2001-08-27 22:15:12 +0000860
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800861 nchildcompleted++;
plars865695b2001-08-27 22:15:12 +0000862#if DEBUG
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800863 #define STR "parent: received SIGCHLD\n"
864 write(STDOUT_FILENO, str, strlen(STR));
plars865695b2001-08-27 22:15:12 +0000865#endif
Wanlong Gao354ebb42012-12-07 10:10:04 +0800866 waitpid(-1, &status, WNOHANG);
Garrett Cooper47fa9242011-12-15 02:12:26 -0800867}