plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 1 | /* |
nstraz | f471e11 | 2002-10-31 15:57:48 +0000 | [diff] [blame] | 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 |
Wanlong Gao | fed9641 | 2012-10-24 10:10:29 +0800 | [diff] [blame] | 20 | * with this program; if not, write the Free Software Foundation, Inc., |
| 21 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
nstraz | f471e11 | 2002-10-31 15:57:48 +0000 | [diff] [blame] | 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 | * |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 32 | */ |
subrata_modak | 25e2187 | 2009-03-19 07:10:02 +0000 | [diff] [blame] | 33 | /* $Header: /cvsroot/ltp/ltp/testcases/kernel/ipc/pipeio/pipeio.c,v 1.18 2009/03/19 07:10:02 subrata_modak Exp $ */ |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 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> |
robbiew | 045fd16 | 2002-12-04 18:42:53 +0000 | [diff] [blame] | 45 | #include <time.h> |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 46 | #include <errno.h> |
| 47 | #include <string.h> |
| 48 | #include <signal.h> |
| 49 | #include <sys/stat.h> |
subrata_modak | ea37be8 | 2008-12-11 13:17:49 +0000 | [diff] [blame] | 50 | #include <sys/sem.h> |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 51 | |
| 52 | #include "tlibio.h" |
| 53 | |
robbiew | 92b688b | 2004-03-01 22:36:38 +0000 | [diff] [blame] | 54 | #include "test.h" |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 55 | #include "safe_macros.h" |
robbiew | 92b688b | 2004-03-01 22:36:38 +0000 | [diff] [blame] | 56 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 57 | char *TCID = "pipeio"; |
| 58 | int TST_TOTAL = 1; |
robbiew | 92b688b | 2004-03-01 22:36:38 +0000 | [diff] [blame] | 59 | |
Garrett Cooper | df3eb16 | 2010-11-28 22:44:32 -0800 | [diff] [blame] | 60 | #define SAFE_FREE(p) { if (p) { free(p); (p)=NULL; } } |
robbiew | 92b688b | 2004-03-01 22:36:38 +0000 | [diff] [blame] | 61 | |
mridge | f7298c7 | 2005-12-05 19:14:37 +0000 | [diff] [blame] | 62 | #if defined(__linux__) |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 63 | #define NBPW sizeof(int) |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 64 | #endif |
| 65 | |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 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 | |
subrata_modak | ea37be8 | 2008-12-11 13:17:49 +0000 | [diff] [blame] | 79 | #define MAX_ERRS 16 |
| 80 | #define MAX_EMPTY 256 |
| 81 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 82 | static int parse_options(int argc, char *argv[]); |
| 83 | static void setup(int argc, char *argv[]); |
| 84 | static void cleanup(void); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 85 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 86 | static void do_child(void); |
| 87 | static void do_parent(void); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 88 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 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); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 93 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 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 { |
| 127 | int val; |
| 128 | struct semid_ds *buf; |
| 129 | unsigned short int *array; |
| 130 | } u; |
| 131 | |
| 132 | int main(int ac, char *av[]) |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 133 | { |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 134 | int i; |
| 135 | unsigned int j; |
| 136 | unsigned int uwait_iter = 1000, uwait_total = 5000000; |
| 137 | pid_t child; |
Garrett Cooper | 2c28215 | 2010-12-16 00:55:50 -0800 | [diff] [blame] | 138 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 139 | setup(ac, av); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 140 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 141 | 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 Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 152 | } |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 153 | } |
| 154 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 155 | 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 | |
| 187 | static 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 Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 196 | switch (c) { |
robbiew | 92b688b | 2004-03-01 22:36:38 +0000 | [diff] [blame] | 197 | case 'T': |
| 198 | TCID = optarg; |
| 199 | break; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 200 | case 'h': |
| 201 | help(); |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 202 | ret = 1; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 203 | break; |
| 204 | case 'D': /* pipe name */ |
| 205 | strcpy(pname, optarg); |
| 206 | break; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 207 | case 'b': /* blocked */ |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 208 | ndelay = 0; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 209 | blk_type = BLOCKING_IO; |
| 210 | break; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 211 | case 'c': /* number childern */ |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 212 | if (sscanf(optarg, "%d", &num_writers) != 1) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 213 | fprintf(stderr, |
| 214 | "%s: --c option invalid arg '%s'.\n", |
| 215 | TCID, optarg); |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 216 | 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; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 221 | } |
| 222 | break; |
| 223 | case 'e': /* exit on error # */ |
| 224 | if (sscanf(optarg, "%d", &exit_error) != 1) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 225 | fprintf(stderr, |
| 226 | "%s: --e option invalid arg '%s'.\n", |
| 227 | TCID, optarg); |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 228 | ret = 1; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 229 | } else if (exit_error < 0) { |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 230 | fprintf(stderr, "%s: --e option must be " |
| 231 | "greater than zero.\n", TCID); |
| 232 | ret = 1; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 233 | } |
| 234 | break; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 235 | case 'E': |
| 236 | prt_examples(); |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 237 | ret = 1; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 238 | break; |
| 239 | case 'f': /* format of buffer on error */ |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 240 | switch (optarg[0]) { |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 241 | 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 Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 257 | case 'n': /* not output */ |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 258 | case 'N': |
| 259 | format = NO_OUT; |
| 260 | break; |
| 261 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 262 | default: |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 263 | fprintf(stderr, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 264 | "%s: --f option invalid arg '%s'.\n", |
| 265 | TCID, optarg); |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 266 | 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; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 270 | break; |
| 271 | } |
| 272 | cp = optarg; |
| 273 | cp++; |
Garrett Cooper | df3eb16 | 2010-11-28 22:44:32 -0800 | [diff] [blame] | 274 | if (*cp) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 275 | if (sscanf(cp, "%i", &format_size) != 1) { |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 276 | 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 Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 282 | break; |
| 283 | } |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 284 | } |
| 285 | break; |
| 286 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 287 | case 'I': |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 288 | 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 Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 292 | TCID); |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 293 | ret = 1; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 294 | } |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 295 | 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 Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 304 | fprintf(stderr, "%s: --i/n option invalid " |
| 305 | "arg '%s'.\n", TCID, optarg); |
| 306 | ret = 1; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 307 | } else if (num_writes < 0) { |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 308 | fprintf(stderr, "%s: --i/n option must be " |
| 309 | "greater than equal to zero.\n", |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 310 | TCID); |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 311 | ret = 1; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 312 | } |
| 313 | |
| 314 | if (num_writes == 0) /* loop forever */ |
| 315 | ++loop; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 316 | break; |
| 317 | case 'p': /* ping */ |
| 318 | if (sscanf(optarg, "%d", &num_rpt) != 1) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 319 | fprintf(stderr, |
| 320 | "%s: --p option invalid arg '%s'.\n", |
| 321 | TCID, optarg); |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 322 | ret = 1; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 323 | } else if (num_rpt < 0) { |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 324 | fprintf(stderr, "%s: --p option must be greater" |
| 325 | " than equal to zero.\n", TCID); |
| 326 | ret = 1; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 327 | } |
| 328 | break; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 329 | case 'q': /* Quiet - NOPASS */ |
| 330 | quiet = 1; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 331 | break; |
| 332 | case 's': /* size */ |
| 333 | if (sscanf(optarg, "%d", &size) != 1) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 334 | fprintf(stderr, |
| 335 | "%s: --s option invalid arg '%s'.\n", |
| 336 | TCID, optarg); |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 337 | ret = 1; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 338 | } else if (size <= 0) { |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 339 | fprintf(stderr, "%s: --s option must be greater" |
| 340 | " than zero.\n", TCID); |
| 341 | ret = 1; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 342 | } |
| 343 | break; |
| 344 | case 'u': |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 345 | unpipe = 1; /* un-named pipe */ |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 346 | break; |
| 347 | case 'v': /* verbose */ |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 348 | verbose = 1; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 349 | break; |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 350 | case 'W': /* max wait time between reads */ |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 351 | d = strtod(optarg, &cp); |
| 352 | if (*cp != '\0') { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 353 | fprintf(stderr, |
| 354 | "%s: --w option invalid arg '%s'.\n", |
| 355 | TCID, optarg); |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 356 | ret = 1; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 357 | } else if (d < 0) { |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 358 | fprintf(stderr, "%s: --w option must be greater" |
| 359 | " than zero.\n", TCID); |
| 360 | ret = 1; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 361 | } |
| 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 Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 367 | fprintf(stderr, |
| 368 | "%s: --w option invalid arg '%s'.\n", |
| 369 | TCID, optarg); |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 370 | ret = 1; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 371 | } else if (d < 0) { |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 372 | fprintf(stderr, "%s: --w option must be greater" |
| 373 | " than zero.\n", TCID); |
| 374 | ret = 1; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 375 | } |
| 376 | chld_wait = (int)(d * 1000000.0); |
| 377 | break; |
| 378 | case '?': |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 379 | ret = 1; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 380 | break; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 381 | } |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 382 | |
| 383 | if (ret == 1) { |
| 384 | usage(); |
| 385 | return ret; |
| 386 | } |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 387 | } |
| 388 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 389 | return ret; |
| 390 | } |
| 391 | |
| 392 | static 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 Cooper | 8fb1cdb | 2010-11-28 22:56:35 -0800 | [diff] [blame] | 419 | if (format_size == -1) |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 420 | format_size = size; |
| 421 | |
| 422 | /* |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 423 | * 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_modak | 4bb656a | 2009-02-26 12:02:09 +0000 | [diff] [blame] | 428 | * number of writes to ensure the same (or more) amount of |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 429 | * 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 Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 432 | * 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: |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 436 | * pipeio -s 4096 -n 13 -c 5 |
| 437 | */ |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 438 | if (size > PIPE_BUF && num_writers > 1) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 439 | if (!loop) { |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 440 | /* |
| 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 Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 449 | } else { |
| 450 | tst_resm(TINFO, "adjusting i/o size to %d", PIPE_BUF); |
| 451 | } |
| 452 | size = PIPE_BUF; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 453 | } |
| 454 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 455 | writebuf = SAFE_MALLOC(cleanup, size); |
| 456 | readbuf = SAFE_MALLOC(cleanup, size); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 457 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 458 | memset(writebuf, 'Z', size); |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 459 | writebuf[size - 1] = 'A'; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 460 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 461 | 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_modak | ea37be8 | 2008-12-11 13:17:49 +0000 | [diff] [blame] | 465 | } |
| 466 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 467 | if (semctl(sem_id, 0, SETVAL, u) == -1) { |
| 468 | tst_brkm(TBROK | TERRNO, cleanup, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 469 | "Couldn't initialize semaphore 0 value"); |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 470 | } |
Jan Stancek | c5bb3eb | 2011-12-15 10:35:27 +0100 | [diff] [blame] | 471 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 472 | if (semctl(sem_id, 1, SETVAL, u) == -1) { |
| 473 | tst_brkm(TBROK | TERRNO, cleanup, |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 474 | "Couldn't initialize semaphore 1 value"); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 475 | } |
| 476 | |
Garrett Cooper | df3eb16 | 2010-11-28 22:44:32 -0800 | [diff] [blame] | 477 | if (unpipe) { |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 478 | SAFE_PIPE(cleanup, fds); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 479 | read_fd = fds[0]; |
| 480 | write_fd = fds[1]; |
| 481 | pipe_type = PIPE_UNNAMED; |
| 482 | blk_type = UNNAMED_IO; |
| 483 | } else { |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 484 | if (mkfifo(pname, 0777) == -1) { |
| 485 | tst_brkm(TBROK | TERRNO, cleanup, |
| 486 | "mkfifo(%s, 0777) failed", pname); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 487 | } |
| 488 | pipe_type = PIPE_NAMED; |
| 489 | } |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 490 | } |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 491 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 492 | static void cleanup(void) |
| 493 | { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 494 | SAFE_FREE(writebuf); |
subrata_modak | bdbaec5 | 2009-02-26 12:14:51 +0000 | [diff] [blame] | 495 | SAFE_FREE(readbuf); |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 496 | |
| 497 | semctl(sem_id, 0, IPC_RMID); |
| 498 | |
| 499 | if (!unpipe) |
| 500 | SAFE_UNLINK(NULL, pname); |
| 501 | |
| 502 | tst_rmdir(); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 503 | } |
| 504 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 505 | static void do_child(void) |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 506 | { |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 507 | 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(); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 515 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 516 | 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); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 598 | } |
| 599 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 600 | static 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 | |
| 621 | static 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 | |
| 721 | static 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 | |
| 729 | static void help(void) |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 730 | { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 731 | usage(); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 732 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 733 | printf(" -b - blocking reads and writes. default non-block\n\ |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 734 | -c #writers - number of writers (childern)\n\ |
| 735 | -D pname - name of fifo (def tpipe<pid>)\n\ |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 736 | -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); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 759 | } |
| 760 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 761 | static void prt_buf(char **addr, char *buf, int length, int format) |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 762 | { |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 763 | int i; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 764 | int num_words = length / NBPW; /* given length in bytes, get length in words */ |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 765 | int width; /* number of columns */ |
robbiew | 33abc16 | 2005-10-03 17:13:35 +0000 | [diff] [blame] | 766 | int extra_words = 0; /* odd or even number of words */ |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 767 | char *a = buf; |
| 768 | char b[NBPW]; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 769 | char c[NBPW * 2]; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 770 | char *p; |
| 771 | long *word; |
| 772 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 773 | if (format == NO_OUT) /* if no output wanted, return */ |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 774 | return; |
| 775 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 776 | if (length % NBPW) |
| 777 | ++num_words; /* is length in full words? */ |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 778 | if (format == ASCII) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 779 | width = 3; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 780 | } else { |
| 781 | width = 2; |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 782 | /* do we have an odd number of words? */ |
| 783 | extra_words = num_words % width; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 784 | } |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 785 | for (i = 0; i < num_words; ++i, a += NBPW, addr++) { |
| 786 | word = (long *)a; |
| 787 | if (!(i % width)) { |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 788 | if (i > 0 && format != ASCII) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 789 | /* |
| 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 Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 798 | for (p = c; (p - c) < (int)(width*NBPW); ++p) { |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 799 | if (*p < '!' || *p > '~') |
| 800 | *p = '.'; |
| 801 | } |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 802 | printf("\t%16.16s", c); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 803 | } |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 804 | printf("\n%p: ", addr); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 805 | /***printf("\n%7o (%d): ",addr,i);***/ |
| 806 | } |
| 807 | |
| 808 | switch (format) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 809 | 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 Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 817 | for (p = b; (p - b) < (int)NBPW; ++p) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 818 | if (*p < '!' || *p > '~') |
| 819 | *p = '.'; |
| 820 | } |
| 821 | printf("%8.8s ", b); |
| 822 | break; |
| 823 | default: |
| 824 | printf("%22.22lo ", *word); |
| 825 | break; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 826 | } |
| 827 | } |
| 828 | if (format != ASCII) { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 829 | /* |
| 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 Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 837 | for (p = c; (p - c) < (int)(width * NBPW); ++p) { |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 838 | if (*p < '!' || *p > '~') |
| 839 | *p = '.'; |
| 840 | } |
subrata_modak | 4bb656a | 2009-02-26 12:02:09 +0000 | [diff] [blame] | 841 | if (width == 2) |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 842 | printf("\t%16.16s", c); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 843 | else |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 844 | printf("\t\t%16.8s", c); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 845 | } |
| 846 | printf("\n"); |
| 847 | fflush(stdout); |
| 848 | } |
| 849 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 850 | static void prt_examples(void) |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 851 | { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 852 | 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); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 855 | } |
| 856 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 857 | static void sig_child(int sig) |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 858 | { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 859 | int status; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 860 | |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 861 | nchildcompleted++; |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 862 | #if DEBUG |
Xiaoguang Wang | e3c09dc | 2014-04-25 18:54:07 +0800 | [diff] [blame] | 863 | #define STR "parent: received SIGCHLD\n" |
| 864 | write(STDOUT_FILENO, str, strlen(STR)); |
plars | 865695b | 2001-08-27 22:15:12 +0000 | [diff] [blame] | 865 | #endif |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 866 | waitpid(-1, &status, WNOHANG); |
Garrett Cooper | 47fa924 | 2011-12-15 02:12:26 -0800 | [diff] [blame] | 867 | } |