blob: 479d5c845f003ff0ab7557f8de8a2a140b4c1936 [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 "usctest.h"
56#include "safe_macros.h"
robbiew92b688b2004-03-01 22:36:38 +000057
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +080058char *TCID = "pipeio";
59int TST_TOTAL = 1;
robbiew92b688b2004-03-01 22:36:38 +000060
Garrett Cooperdf3eb162010-11-28 22:44:32 -080061#define SAFE_FREE(p) { if (p) { free(p); (p)=NULL; } }
robbiew92b688b2004-03-01 22:36:38 +000062
mridgef7298c72005-12-05 19:14:37 +000063#if defined(__linux__)
Wanlong Gao354ebb42012-12-07 10:10:04 +080064#define NBPW sizeof(int)
plars865695b2001-08-27 22:15:12 +000065#endif
66
plars865695b2001-08-27 22:15:12 +000067#define OCTAL 'o'
68#define HEX 'x'
69#define DECIMAL 'd'
70#define ASCII 'a'
71#define NO_OUT 'n'
72
73#define PIPE_NAMED "named pipe,"
74#define PIPE_UNNAMED "sys pipe,"
75
76#define BLOCKING_IO "blking,"
77#define NON_BLOCKING_IO "non-blking,"
78#define UNNAMED_IO ""
79
subrata_modakea37be82008-12-11 13:17:49 +000080#define MAX_ERRS 16
81#define MAX_EMPTY 256
82
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +080083static int parse_options(int argc, char *argv[]);
84static void setup(int argc, char *argv[]);
85static void cleanup(void);
plars865695b2001-08-27 22:15:12 +000086
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +080087static void do_child(void);
88static void do_parent(void);
plars865695b2001-08-27 22:15:12 +000089
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +080090static void help(void), usage(void), prt_examples(void);
91static void prt_buf(char **addr, char *buf, int length, int format);
92static void sig_child(int sig);
93static int check_rw_buf(void);
plars865695b2001-08-27 22:15:12 +000094
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +080095static volatile sig_atomic_t nchildcompleted;
96
97/* variables may be modified in setup() */
98static int num_writers = 1; /* number of writers */
99static int num_writes = 1; /* number of writes per child */
100static int loop; /* loop indefinitely */
101static int exit_error = 1; /* exit on error #, zero means no exit */
102static int size = 327; /* default size */
103static int unpipe; /* un-named pipe if non-zero */
104static int verbose; /* verbose mode if set */
105static int quiet; /* quiet mode if set */
106static int num_rpt; /* ping number, how often to print message */
107static int chld_wait; /* max time to wait between writes, 1 == no wait */
108static int parent_wait; /* max time to wait between reads, 1 == no wait */
109static int ndelay = O_NDELAY; /* additional flag to open */
110static char *writebuf;
111static char *readbuf;
112static char pname[PATH_MAX]; /* contains the name of the named pipe */
113static char *blk_type = NON_BLOCKING_IO; /* blocking i/o or not */
114static char *pipe_type; /* type of pipe under test */
115static int format = HEX;
116static int format_size = -1;
117static int iotype; /* sync io */
118
119/* variables will be modified in running */
120static int error;
121static int count;
122static int read_fd;
123static int write_fd;
124static int empty_read;
125static int sem_id;
126
127static union semun {
128 int val;
129 struct semid_ds *buf;
130 unsigned short int *array;
131} u;
132
133int main(int ac, char *av[])
plars865695b2001-08-27 22:15:12 +0000134{
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800135 int i;
136 unsigned int j;
137 unsigned int uwait_iter = 1000, uwait_total = 5000000;
138 pid_t child;
Garrett Cooper2c282152010-12-16 00:55:50 -0800139
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800140 setup(ac, av);
plars865695b2001-08-27 22:15:12 +0000141
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800142 for (i = num_writers; i > 0; --i) {
143
144 child = tst_fork();
145 switch (child) {
146 case -1:
147 tst_brkm(TBROK | TERRNO, cleanup, "fork() failed");
148 case 0:
149 do_child();
150 exit(0);
151 default:
152 break;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800153 }
plars865695b2001-08-27 22:15:12 +0000154 }
155
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800156 do_parent();
157
158 if (empty_read)
159 tst_resm(TWARN, "%d empty reads", empty_read);
160
161 if (error) {
162 tst_resm(TFAIL, "%d data errors on pipe, read size = %d, %s %s",
163 error, size, pipe_type, blk_type);
164 } else if (!quiet) {
165 tst_resm(TPASS, "%d pipe reads complete, read size = %d, %s %s",
166 count + 1, size, pipe_type, blk_type);
167 }
168
169 /*
170 * wait for all children to finish, timeout after uwait_total
171 * semtimedop might not be available everywhere
172 */
173 for (j = 0; j < uwait_total; j += uwait_iter) {
174 if (semctl(sem_id, 1, GETVAL) == 0)
175 break;
176 usleep(uwait_iter);
177 }
178
179 if (j >= uwait_total) {
180 tst_resm(TWARN,
181 "Timed out waiting for child processes to exit");
182 }
183
184 cleanup();
185 tst_exit();
186}
187
188static int parse_options(int argc, char *argv[])
189{
190 char *cp;
191 int c;
192 int ret = 0;
193 static double d;
194
195 while ((c = getopt(argc, argv, "T:bc:D:he:Ef:i:I:ln:p:qs:uvW:w:"))
196 != -1) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800197 switch (c) {
robbiew92b688b2004-03-01 22:36:38 +0000198 case 'T':
199 TCID = optarg;
200 break;
plars865695b2001-08-27 22:15:12 +0000201 case 'h':
202 help();
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800203 ret = 1;
plars865695b2001-08-27 22:15:12 +0000204 break;
205 case 'D': /* pipe name */
206 strcpy(pname, optarg);
207 break;
plars865695b2001-08-27 22:15:12 +0000208 case 'b': /* blocked */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800209 ndelay = 0;
plars865695b2001-08-27 22:15:12 +0000210 blk_type = BLOCKING_IO;
211 break;
plars865695b2001-08-27 22:15:12 +0000212 case 'c': /* number childern */
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800213 if (sscanf(optarg, "%d", &num_writers) != 1) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800214 fprintf(stderr,
215 "%s: --c option invalid arg '%s'.\n",
216 TCID, optarg);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800217 ret = 1;
218 } else if (num_writers <= 0) {
219 fprintf(stderr, "%s: --c option must be "
220 "greater than zero.\n", TCID);
221 ret = 1;
plars865695b2001-08-27 22:15:12 +0000222 }
223 break;
224 case 'e': /* exit on error # */
225 if (sscanf(optarg, "%d", &exit_error) != 1) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800226 fprintf(stderr,
227 "%s: --e option invalid arg '%s'.\n",
228 TCID, optarg);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800229 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800230 } else if (exit_error < 0) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800231 fprintf(stderr, "%s: --e option must be "
232 "greater than zero.\n", TCID);
233 ret = 1;
plars865695b2001-08-27 22:15:12 +0000234 }
235 break;
plars865695b2001-08-27 22:15:12 +0000236 case 'E':
237 prt_examples();
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800238 ret = 1;
plars865695b2001-08-27 22:15:12 +0000239 break;
240 case 'f': /* format of buffer on error */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800241 switch (optarg[0]) {
plars865695b2001-08-27 22:15:12 +0000242 case 'x':
243 case 'X':
244 format = HEX;
245 break;
246 case 'o':
247 case 'O':
248 format = OCTAL;
249 break;
250 case 'd':
251 case 'D':
252 format = DECIMAL;
253 break;
254 case 'a':
255 case 'A':
256 format = ASCII;
257 break;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800258 case 'n': /* not output */
plars865695b2001-08-27 22:15:12 +0000259 case 'N':
260 format = NO_OUT;
261 break;
262
Wanlong Gao354ebb42012-12-07 10:10:04 +0800263 default:
plars865695b2001-08-27 22:15:12 +0000264 fprintf(stderr,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800265 "%s: --f option invalid arg '%s'.\n",
266 TCID, optarg);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800267 fprintf(stderr, "\tIt must be x(hex), o(octal),"
268 "d(decimal), a(ascii) or n(none) with "
269 "opt sz\n");
270 ret = 1;
plars865695b2001-08-27 22:15:12 +0000271 break;
272 }
273 cp = optarg;
274 cp++;
Garrett Cooperdf3eb162010-11-28 22:44:32 -0800275 if (*cp) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800276 if (sscanf(cp, "%i", &format_size) != 1) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800277 fprintf(stderr, "%s: --f option invalid"
278 "arg '%s'.\n", TCID, optarg);
279 fprintf(stderr, "\tIt must be x(hex),"
280 "o(octal), d(decimal), a(ascii)"
281 " or n(none) with opt sz\n");
282 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800283 break;
284 }
plars865695b2001-08-27 22:15:12 +0000285 }
286 break;
287
Wanlong Gao354ebb42012-12-07 10:10:04 +0800288 case 'I':
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800289 iotype = lio_parse_io_arg1(optarg);
290 if (iotype == -1) {
291 fprintf(stderr, "%s: --I arg is invalid, "
292 "must be s, p, f, a, l, L or r.\n",
Wanlong Gao354ebb42012-12-07 10:10:04 +0800293 TCID);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800294 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800295 }
plars865695b2001-08-27 22:15:12 +0000296 break;
297
298 case 'l': /* loop forever */
299 ++loop;
300 break;
301
302 case 'i':
303 case 'n': /* number writes per child */
304 if (sscanf(optarg, "%d", &num_writes) != 1) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800305 fprintf(stderr, "%s: --i/n option invalid "
306 "arg '%s'.\n", TCID, optarg);
307 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800308 } else if (num_writes < 0) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800309 fprintf(stderr, "%s: --i/n option must be "
310 "greater than equal to zero.\n",
Wanlong Gao354ebb42012-12-07 10:10:04 +0800311 TCID);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800312 ret = 1;
plars865695b2001-08-27 22:15:12 +0000313 }
314
315 if (num_writes == 0) /* loop forever */
316 ++loop;
plars865695b2001-08-27 22:15:12 +0000317 break;
318 case 'p': /* ping */
319 if (sscanf(optarg, "%d", &num_rpt) != 1) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800320 fprintf(stderr,
321 "%s: --p option invalid arg '%s'.\n",
322 TCID, optarg);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800323 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800324 } else if (num_rpt < 0) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800325 fprintf(stderr, "%s: --p option must be greater"
326 " than equal to zero.\n", TCID);
327 ret = 1;
plars865695b2001-08-27 22:15:12 +0000328 }
329 break;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800330 case 'q': /* Quiet - NOPASS */
331 quiet = 1;
plars865695b2001-08-27 22:15:12 +0000332 break;
333 case 's': /* size */
334 if (sscanf(optarg, "%d", &size) != 1) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800335 fprintf(stderr,
336 "%s: --s option invalid arg '%s'.\n",
337 TCID, optarg);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800338 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800339 } else if (size <= 0) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800340 fprintf(stderr, "%s: --s option must be greater"
341 " than zero.\n", TCID);
342 ret = 1;
plars865695b2001-08-27 22:15:12 +0000343 }
344 break;
345 case 'u':
Wanlong Gao354ebb42012-12-07 10:10:04 +0800346 unpipe = 1; /* un-named pipe */
plars865695b2001-08-27 22:15:12 +0000347 break;
348 case 'v': /* verbose */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800349 verbose = 1;
plars865695b2001-08-27 22:15:12 +0000350 break;
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800351 case 'W': /* max wait time between reads */
plars865695b2001-08-27 22:15:12 +0000352 d = strtod(optarg, &cp);
353 if (*cp != '\0') {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800354 fprintf(stderr,
355 "%s: --w option invalid arg '%s'.\n",
356 TCID, optarg);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800357 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800358 } else if (d < 0) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800359 fprintf(stderr, "%s: --w option must be greater"
360 " than zero.\n", TCID);
361 ret = 1;
plars865695b2001-08-27 22:15:12 +0000362 }
363 parent_wait = (int)(d * 1000000.0);
364 break;
365 case 'w': /* max wait time between writes */
366 d = strtod(optarg, &cp);
367 if (*cp != '\0') {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800368 fprintf(stderr,
369 "%s: --w option invalid arg '%s'.\n",
370 TCID, optarg);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800371 ret = 1;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800372 } else if (d < 0) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800373 fprintf(stderr, "%s: --w option must be greater"
374 " than zero.\n", TCID);
375 ret = 1;
plars865695b2001-08-27 22:15:12 +0000376 }
377 chld_wait = (int)(d * 1000000.0);
378 break;
379 case '?':
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800380 ret = 1;
plars865695b2001-08-27 22:15:12 +0000381 break;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800382 }
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800383
384 if (ret == 1) {
385 usage();
386 return ret;
387 }
plars865695b2001-08-27 22:15:12 +0000388 }
389
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800390 return ret;
391}
392
393static void setup(int argc, char *argv[])
394{
395 int ret;
396 char *toutput;
397 int fds[2];
398
399 tst_sig(FORK, DEF_HANDLER, cleanup);
400
401 TEST_PAUSE;
402
403 tst_tmpdir();
404
405 if (signal(SIGCHLD, sig_child) == SIG_ERR) {
406 tst_brkm(TBROK | TERRNO, cleanup,
407 "set signal handler for SIGCHLD failed");
408 }
409
410 toutput = getenv("TOUTPUT");
411 if (toutput != NULL && strcmp(toutput, "NOPASS") == 0)
412 quiet = 1;
413
414 sprintf(pname, "%s", "tpipe");
415
416 ret = parse_options(argc, argv);
417 if (ret == 1)
418 tst_brkm(TBROK, cleanup, "options parse error");
419
Garrett Cooper8fb1cdb2010-11-28 22:56:35 -0800420 if (format_size == -1)
plars865695b2001-08-27 22:15:12 +0000421 format_size = size;
422
423 /*
plars865695b2001-08-27 22:15:12 +0000424 * If there is more than one writer, all writes and reads
425 * must be the same size. Only writes of a size <= PIPE_BUF
426 * are atomic. T
427 * Therefore, if size is greater than PIPE_BUF, we will break
428 * the writes into PIPE_BUF chunks. We will also increase the
subrata_modak4bb656a2009-02-26 12:02:09 +0000429 * number of writes to ensure the same (or more) amount of
plars865695b2001-08-27 22:15:12 +0000430 * data is written. This is the same as erroring and telling
431 * the user the new cmd line to do the same thing.
432 * Example:
Wanlong Gao354ebb42012-12-07 10:10:04 +0800433 * pipeio -s 5000 -n 10 -c 5
434 * (each child will write at least 50000 bytes, since all
435 * writes have to be in 4096 chuncks or 13*4096 (53248)
436 * bytes will be written.) This is the same as:
plars865695b2001-08-27 22:15:12 +0000437 * pipeio -s 4096 -n 13 -c 5
438 */
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800439 if (size > PIPE_BUF && num_writers > 1) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800440 if (!loop) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800441 /*
442 * we must set num_writes*num_writers
443 * doesn't overflow later
444 */
445 num_writes = MIN(((long long)num_writes * size +
446 PIPE_BUF - 1) / PIPE_BUF,
447 INT_MAX / num_writers);
448 tst_resm(TINFO, "adjusting i/o size to %d, and # of "
449 "writes to %d", PIPE_BUF, num_writes);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800450 } else {
451 tst_resm(TINFO, "adjusting i/o size to %d", PIPE_BUF);
452 }
453 size = PIPE_BUF;
plars865695b2001-08-27 22:15:12 +0000454 }
455
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800456 writebuf = SAFE_MALLOC(cleanup, size);
457 readbuf = SAFE_MALLOC(cleanup, size);
plars865695b2001-08-27 22:15:12 +0000458
Wanlong Gao354ebb42012-12-07 10:10:04 +0800459 memset(writebuf, 'Z', size);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800460 writebuf[size - 1] = 'A';
plars865695b2001-08-27 22:15:12 +0000461
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800462 sem_id = semget(IPC_PRIVATE, 2, IPC_CREAT | S_IRWXU);
463 if (sem_id == -1) {
464 tst_brkm(TBROK | TERRNO, cleanup,
465 "Couldn't allocate semaphore");
subrata_modakea37be82008-12-11 13:17:49 +0000466 }
467
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800468 if (semctl(sem_id, 0, SETVAL, u) == -1) {
469 tst_brkm(TBROK | TERRNO, cleanup,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800470 "Couldn't initialize semaphore 0 value");
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800471 }
Jan Stancekc5bb3eb2011-12-15 10:35:27 +0100472
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800473 if (semctl(sem_id, 1, SETVAL, u) == -1) {
474 tst_brkm(TBROK | TERRNO, cleanup,
Wanlong Gao354ebb42012-12-07 10:10:04 +0800475 "Couldn't initialize semaphore 1 value");
plars865695b2001-08-27 22:15:12 +0000476 }
477
Garrett Cooperdf3eb162010-11-28 22:44:32 -0800478 if (unpipe) {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800479 SAFE_PIPE(cleanup, fds);
plars865695b2001-08-27 22:15:12 +0000480 read_fd = fds[0];
481 write_fd = fds[1];
482 pipe_type = PIPE_UNNAMED;
483 blk_type = UNNAMED_IO;
484 } else {
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800485 if (mkfifo(pname, 0777) == -1) {
486 tst_brkm(TBROK | TERRNO, cleanup,
487 "mkfifo(%s, 0777) failed", pname);
plars865695b2001-08-27 22:15:12 +0000488 }
489 pipe_type = PIPE_NAMED;
490 }
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800491}
plars865695b2001-08-27 22:15:12 +0000492
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800493static void cleanup(void)
494{
495 TEST_CLEANUP;
robbiew92b688b2004-03-01 22:36:38 +0000496
Wanlong Gao354ebb42012-12-07 10:10:04 +0800497 SAFE_FREE(writebuf);
subrata_modakbdbaec52009-02-26 12:14:51 +0000498 SAFE_FREE(readbuf);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800499
500 semctl(sem_id, 0, IPC_RMID);
501
502 if (!unpipe)
503 SAFE_UNLINK(NULL, pname);
504
505 tst_rmdir();
plars865695b2001-08-27 22:15:12 +0000506}
507
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800508static void do_child(void)
plars865695b2001-08-27 22:15:12 +0000509{
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800510 int *count_word; /* holds address where to write writers count */
511 int *pid_word; /* holds address where to write writers pid */
512 int nb, j;
513 long clock;
514 char *cp;
515 long int n;
516 struct sembuf sem_op;
517 pid_t self_pid = getpid();
plars865695b2001-08-27 22:15:12 +0000518
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800519 if (!unpipe) {
520 write_fd = open(pname, O_WRONLY);
521 if (write_fd == -1) {
522 fprintf(stderr, "child pipe open(%s, %#o) failed",
523 pname, O_WRONLY | ndelay);
524 exit(1);
525 }
526 if (ndelay && fcntl(write_fd, F_SETFL, O_NONBLOCK) == -1) {
527 fprintf(stderr, "Failed setting the pipe to "
528 "nonblocking mode");
529 exit(1);
530 }
531 } else {
532 close(read_fd);
533 }
534
535 sem_op = (struct sembuf) {
536 .sem_num = 0, .sem_op = 1, .sem_flg = 0};
537
538 if (semop(sem_id, &sem_op, 1) == -1) {
539 fprintf(stderr, "child: %d couldn't raise the semaphore 0",
540 self_pid);
541 exit(1);
542 }
543
544 pid_word = (int *)&writebuf[0];
545 count_word = (int *)&writebuf[NBPW];
546
547 for (j = 0; j < num_writes || loop; ++j) {
548 /*
549 * writes are only in one unit when the size of the write
550 * is <= PIPE_BUF.
551 * Therefore, if size is greater than PIPE_BUF, we will break
552 * the writes into PIPE_BUF chunks.
553 * All writes and read need to be same size.
554 */
555
556 /*
557 * write pid and count in first two
558 * words of buffer
559 */
560 *count_word = j;
561 *pid_word = self_pid;
562
563 nb = lio_write_buffer(write_fd, iotype, writebuf, size,
564 SIGUSR1, &cp, 0);
565 if (nb < 0) {
566 /*
567 * If lio_write_buffer returns a negative number,
568 * the return will be -errno.
569 */
570 fprintf(stderr, "pass %d: lio_write_buffer(%s) failed;"
571 " it returned %d: %s",
572 j, cp, nb, strerror(-nb));
573 exit(1);
574 } else if (nb != size) {
575 fprintf(stderr, "pass %d: lio_write_buffer(%s) failed,"
576 " write count %d, but expected to write %d",
577 j, cp, nb, size);
578 }
579 if (verbose) {
580 fprintf(stderr, "pass %d: pid %d: wrote %d bytes,"
581 "expected %d bytes",
582 j, self_pid, nb, size);
583 }
584
585 if (chld_wait) {
586 clock = time(0);
587 srand48(clock);
588 n = lrand48() % chld_wait;
589 usleep(n);
590 }
591 fflush(stderr);
592 }
593
594 /* child waits until parent completes open() */
595 sem_op = (struct sembuf) {
596 .sem_num = 1, .sem_op = -1, .sem_flg = 0};
597 if (semop(sem_id, &sem_op, 1) == -1)
598 fprintf(stderr, "Couldn't lower the semaphore 1");
599
600 exit(0);
plars865695b2001-08-27 22:15:12 +0000601}
602
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800603static int check_rw_buf(void)
604{
605 int i;
606
607 for (i = 2 * NBPW; i < size; ++i) {
608 if (writebuf[i] != readbuf[i]) {
609 ++error;
610 tst_resm(TFAIL,
611 "FAIL data error on byte %d; rd# %d, sz= %d, "
612 "%s %s empty_reads= %d, err= %d",
613 i, count, size, pipe_type, blk_type,
614 empty_read, error);
615 prt_buf(&readbuf, readbuf, format_size, format);
616 fflush(stdout);
617 return 1;
618 }
619 }
620
621 return 0;
622}
623
624static void do_parent(void)
625{
626 int i, nb;
627 long clock;
628 time_t start_time, current_time, diff_time;
629 char *cp;
630 long int n;
631 struct sembuf sem_op;
632
633 start_time = time(0);
634 if (!unpipe) {
635 read_fd = SAFE_OPEN(cleanup, pname, O_RDONLY);
636 if (ndelay && fcntl(read_fd, F_SETFL, O_NONBLOCK) == -1) {
637 tst_brkm(TBROK | TERRNO, cleanup,
638 "Failed setting the pipe to nonblocking mode");
639 }
640 } else {
641 SAFE_CLOSE(cleanup, write_fd);
642 }
643
644 /* raise semaphore so children can exit */
645 sem_op = (struct sembuf) {
646 .sem_num = 1, .sem_op = num_writers, .sem_flg = 0};
647 if (semop(sem_id, &sem_op, 1) == -1) {
648 tst_brkm(TBROK | TERRNO, cleanup,
649 "Couldn't raise the semaphore 1");
650 }
651
652 sem_op = (struct sembuf) {
653 .sem_num = 0, .sem_op = -num_writers, .sem_flg = 0};
654
655 while (nchildcompleted < num_writers
656 && semop(sem_id, &sem_op, 1) == -1) {
657 if (errno == EINTR)
658 continue;
659 tst_brkm(TBROK | TERRNO, cleanup,
660 "Couldn't wait on semaphore 0");
661 }
662
663 /* parent start to read pipe */
664 for (i = num_writers * num_writes; i > 0 || loop; --i) {
665 if (error >= MAX_ERRS || empty_read >= MAX_EMPTY)
666 break;
667 if (parent_wait) {
668 clock = time(0);
669 srand48(clock);
670 n = lrand48() % parent_wait;
671 usleep(n);
672 }
673 ++count;
674 nb = lio_read_buffer(read_fd, iotype, readbuf, size,
675 SIGUSR1, &cp, 0);
676 if (nb < 0) {
677 /*
678 * If lio_read_buffer returns a negative number,
679 * the return will be -errno.
680 */
681 tst_resm(TFAIL, "pass %d: lio_read_buffer(%s) failed; "
682 "returned %d: %s", i, cp, nb, strerror(-nb));
683 ++i;
684 count--;
685 error++;
686 continue;
687 } else {
688 if (nb == 0) {
689 if (nchildcompleted >= num_writers && !loop) {
690 tst_resm(TWARN, "The children have "
691 "died prematurely");
692 break; /* All children have died */
693 }
694 empty_read++;
695 ++i;
696 count--;
697 continue;
698 } else if (nb < size && size <= PIPE_BUF) {
699 tst_resm(TFAIL, "pass %d: partial read from the"
700 " pipe: read %d bytes, expected %d, "
701 "read count %d", i, nb, size, count);
702 ++error;
703 } else if (nb == size) {
704 check_rw_buf();
705 if (exit_error && exit_error == error)
706 return;
707 }
708
709 if (verbose || (num_rpt && !(count % num_rpt))) {
710 current_time = time(0);
711 diff_time = current_time - start_time;
712 tst_resm(TFAIL,
713 "(%d) rd# %d, sz= %d, %s %s "
714 "empty_reads= %d, err= %d\n",
715 (int)diff_time, count, size,
716 pipe_type, blk_type,
717 empty_read, error);
718 fflush(stdout);
719 }
720 }
721 }
722}
723
724static void usage(void)
725{
726 fprintf(stderr, "Usage: %s [-bEv][-c #writers][-D pname][-h]"
727 "[-e exit_num][-f fmt][-l][-i #writes][-n #writes][-p num_rpt]"
728 "\n\t[-s size][-W max_wait][-w max_wait][-u]\n", TCID);
729 fflush(stderr);
730}
731
732static void help(void)
plars865695b2001-08-27 22:15:12 +0000733{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800734 usage();
plars865695b2001-08-27 22:15:12 +0000735
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800736 printf(" -b - blocking reads and writes. default non-block\n\
plars865695b2001-08-27 22:15:12 +0000737 -c #writers - number of writers (childern)\n\
738 -D pname - name of fifo (def tpipe<pid>)\n\
plars865695b2001-08-27 22:15:12 +0000739 -h - print this help message\n\
740 -e exit_num - exit on error exit_num, 0 is ignore errors, 1 is default.\n\
741 -E - print cmd line examples and exit\n\
742 -f format - define format of bad buffer: h(hex), o(octal)\n\
743 d(decimal), a(ascii), n (none). hex is default\n\
744 option size can be added to control output\n\
745 -i #writes - number write per child, zero means forever.\n\
746 -I io_type - Specifies io type: s - sync, p - polled async, a - async (def s)\n\
747 l - listio sync, L - listio async, r - random\n\
748 -l - loop forever (implied by -n 0).\n\
749 -n #writes - same as -i (for compatability).\n\
750 -p num_rpt - number of reads before a report\n\
751 -q - quiet mode, no PASS results are printed\n\
752 -s size - size of read and write (def 327)\n\
753 if size >= 4096, i/o will be in 4096 chuncks\n\
754 -w max_wait - max time (seconds) for sleep between writes.\n\
755 max_wait is interpreted as a double with ms accuracy.\n\
756 -W max_wait - max time (seconds) for sleep between reads\n\
757 max_wait is interpreted as a double with ms accuracy.\n\
758 -u - un-named pipe instead of named pipe\n\
759 -v - verbose mode, all writes/reads resutlts printed\n");
760
761 fflush(stdout);
plars865695b2001-08-27 22:15:12 +0000762}
763
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800764static void prt_buf(char **addr, char *buf, int length, int format)
plars865695b2001-08-27 22:15:12 +0000765{
plars865695b2001-08-27 22:15:12 +0000766 int i;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800767 int num_words = length / NBPW; /* given length in bytes, get length in words */
plars865695b2001-08-27 22:15:12 +0000768 int width; /* number of columns */
robbiew33abc162005-10-03 17:13:35 +0000769 int extra_words = 0; /* odd or even number of words */
plars865695b2001-08-27 22:15:12 +0000770 char *a = buf;
771 char b[NBPW];
Wanlong Gao354ebb42012-12-07 10:10:04 +0800772 char c[NBPW * 2];
plars865695b2001-08-27 22:15:12 +0000773 char *p;
774 long *word;
775
Wanlong Gao354ebb42012-12-07 10:10:04 +0800776 if (format == NO_OUT) /* if no output wanted, return */
plars865695b2001-08-27 22:15:12 +0000777 return;
778
Wanlong Gao354ebb42012-12-07 10:10:04 +0800779 if (length % NBPW)
780 ++num_words; /* is length in full words? */
plars865695b2001-08-27 22:15:12 +0000781 if (format == ASCII) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800782 width = 3;
plars865695b2001-08-27 22:15:12 +0000783 } else {
784 width = 2;
Wanlong Gao354ebb42012-12-07 10:10:04 +0800785 /* do we have an odd number of words? */
786 extra_words = num_words % width;
plars865695b2001-08-27 22:15:12 +0000787 }
Wanlong Gao354ebb42012-12-07 10:10:04 +0800788 for (i = 0; i < num_words; ++i, a += NBPW, addr++) {
789 word = (long *)a;
790 if (!(i % width)) {
plars865695b2001-08-27 22:15:12 +0000791 if (i > 0 && format != ASCII) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800792 /*
793 * print the ascii equivalent of the data
794 * before beginning the next line of output.
795 */
796 memset(c, 0x00, width * NBPW);
797 /*
798 * get the last 2 words printed
799 */
800 memcpy(c, a - (width * NBPW), width * NBPW);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800801 for (p = c; (p - c) < (int)(width*NBPW); ++p) {
plars865695b2001-08-27 22:15:12 +0000802 if (*p < '!' || *p > '~')
803 *p = '.';
804 }
Wanlong Gao354ebb42012-12-07 10:10:04 +0800805 printf("\t%16.16s", c);
plars865695b2001-08-27 22:15:12 +0000806 }
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800807 printf("\n%p: ", addr);
plars865695b2001-08-27 22:15:12 +0000808 /***printf("\n%7o (%d): ",addr,i);***/
809 }
810
811 switch (format) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800812 case HEX:
813 printf("%16.16lx ", *word);
814 break;
815 case DECIMAL:
816 printf("%10.10ld ", *word);
817 break;
818 case ASCII:
819 memcpy(b, a, NBPW);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800820 for (p = b; (p - b) < (int)NBPW; ++p) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800821 if (*p < '!' || *p > '~')
822 *p = '.';
823 }
824 printf("%8.8s ", b);
825 break;
826 default:
827 printf("%22.22lo ", *word);
828 break;
plars865695b2001-08-27 22:15:12 +0000829 }
830 }
831 if (format != ASCII) {
Wanlong Gao354ebb42012-12-07 10:10:04 +0800832 /*
833 * print the ascii equivalent of the last words in the buffer
834 * before returning.
835 */
836 memset(c, 0x00, width * NBPW);
837 if (extra_words)
838 width = extra_words; /* odd number of words */
839 memcpy(c, a - (width * NBPW), width * NBPW);
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800840 for (p = c; (p - c) < (int)(width * NBPW); ++p) {
plars865695b2001-08-27 22:15:12 +0000841 if (*p < '!' || *p > '~')
842 *p = '.';
843 }
subrata_modak4bb656a2009-02-26 12:02:09 +0000844 if (width == 2)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800845 printf("\t%16.16s", c);
plars865695b2001-08-27 22:15:12 +0000846 else
Wanlong Gao354ebb42012-12-07 10:10:04 +0800847 printf("\t\t%16.8s", c);
plars865695b2001-08-27 22:15:12 +0000848 }
849 printf("\n");
850 fflush(stdout);
851}
852
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800853static void prt_examples(void)
plars865695b2001-08-27 22:15:12 +0000854{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800855 printf("%s -c 5 -i 0 -s 4090 -b\n", TCID);
856 printf("%s -c 5 -i 0 -s 4090 -b -u \n", TCID);
857 printf("%s -c 5 -i 0 -s 4090 -b -W 3 -w 3 \n", TCID);
plars865695b2001-08-27 22:15:12 +0000858}
859
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800860static void sig_child(int sig)
plars865695b2001-08-27 22:15:12 +0000861{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800862 int status;
plars865695b2001-08-27 22:15:12 +0000863
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800864 nchildcompleted++;
plars865695b2001-08-27 22:15:12 +0000865#if DEBUG
Xiaoguang Wange3c09dc2014-04-25 18:54:07 +0800866 #define STR "parent: received SIGCHLD\n"
867 write(STDOUT_FILENO, str, strlen(STR));
plars865695b2001-08-27 22:15:12 +0000868#endif
Wanlong Gao354ebb42012-12-07 10:10:04 +0800869 waitpid(-1, &status, WNOHANG);
Garrett Cooper47fa9242011-12-15 02:12:26 -0800870}