1 /* A program to put stress on a POSIX system (stress). 2 * 3 * Copyright (C) 2001, 2002 Amos Waterland <awaterl (at) yahoo.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License as published by the Free 7 * Software Foundation; either version 2 of the License, or (at your option) 8 * any later version. 9 * 10 * This program is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 #include <ctype.h> 21 #include <errno.h> 22 #include <libgen.h> 23 #include <math.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <signal.h> 28 #include <time.h> 29 #include <unistd.h> 30 #include <sys/wait.h> 31 32 /* By default, print all messages of severity info and above. */ 33 static int global_debug = 2; 34 35 /* By default, just print warning for non-critical errors. */ 36 static int global_ignore = 1; 37 38 /* By default, retry on non-critical errors every 50ms. */ 39 static int global_retry = 50000; 40 41 /* By default, use this as backoff coefficient for good fork throughput. */ 42 static int global_backoff = 3000; 43 44 /* By default, do not timeout. */ 45 static int global_timeout = 0; 46 47 /* Name of this program */ 48 static char *global_progname = PACKAGE; 49 50 /* By default, do not hang after allocating memory. */ 51 static int global_vmhang = 0; 52 53 /* Implemention of runtime-selectable severity message printing. */ 54 #define dbg if (global_debug >= 3) \ 55 fprintf (stdout, "%s: debug: (%d) ", global_progname, __LINE__), \ 56 fprintf 57 #define out if (global_debug >= 2) \ 58 fprintf (stdout, "%s: info: ", global_progname), \ 59 fprintf 60 #define wrn if (global_debug >= 1) \ 61 fprintf (stderr, "%s: warn: (%d) ", global_progname, __LINE__), \ 62 fprintf 63 #define err if (global_debug >= 0) \ 64 fprintf (stderr, "%s: error: (%d) ", global_progname, __LINE__), \ 65 fprintf 66 67 /* Implementation of check for option argument correctness. */ 68 #define assert_arg(A) \ 69 if (++i == argc || ((arg = argv[i])[0] == '-' && \ 70 !isdigit ((int)arg[1]) )) \ 71 { \ 72 err (stderr, "missing argument to option '%s'\n", A); \ 73 exit (1); \ 74 } 75 76 /* Prototypes for utility functions. */ 77 int usage(int status); 78 int version(int status); 79 long long atoll_s(const char *nptr); 80 long long atoll_b(const char *nptr); 81 82 /* Prototypes for the worker functions. */ 83 int hogcpu(long long forks); 84 int hogio(long long forks); 85 int hogvm(long long forks, long long chunks, long long bytes); 86 int hoghdd(long long forks, int clean, long long files, long long bytes); 87 88 int main(int argc, char **argv) 89 { 90 int i, pid, children = 0, retval = 0; 91 long starttime, stoptime, runtime; 92 93 /* Variables that indicate which options have been selected. */ 94 int do_dryrun = 0; 95 int do_timeout = 0; 96 int do_cpu = 0; /* Default to 1 fork. */ 97 long long do_cpu_forks = 1; 98 int do_io = 0; /* Default to 1 fork. */ 99 long long do_io_forks = 1; 100 int do_vm = 0; /* Default to 1 fork, 1 chunk of 256MB. */ 101 long long do_vm_forks = 1; 102 long long do_vm_chunks = 1; 103 long long do_vm_bytes = 256 * 1024 * 1024; 104 int do_hdd = 0; /* Default to 1 fork, clean, 1 file of 1GB. */ 105 long long do_hdd_forks = 1; 106 int do_hdd_clean = 0; 107 long long do_hdd_files = 1; 108 long long do_hdd_bytes = 1024 * 1024 * 1024; 109 110 /* Record our start time. */ 111 if ((starttime = time(NULL)) == -1) { 112 err(stderr, "failed to acquire current time\n"); 113 exit(1); 114 } 115 116 /* SuSv3 does not define any error conditions for this function. */ 117 global_progname = basename(argv[0]); 118 119 /* For portability, parse command line options without getopt_long. */ 120 for (i = 1; i < argc; i++) { 121 char *arg = argv[i]; 122 123 if (strcmp(arg, "--help") == 0 || strcmp(arg, "-?") == 0) { 124 usage(0); 125 } else if (strcmp(arg, "--version") == 0) { 126 version(0); 127 } else if (strcmp(arg, "--verbose") == 0 128 || strcmp(arg, "-v") == 0) { 129 global_debug = 3; 130 } else if (strcmp(arg, "--quiet") == 0 131 || strcmp(arg, "-q") == 0) { 132 global_debug = 0; 133 } else if (strcmp(arg, "--dry-run") == 0 134 || strcmp(arg, "-n") == 0) { 135 do_dryrun = 1; 136 } else if (strcmp(arg, "--no-retry") == 0) { 137 global_ignore = 0; 138 dbg(stdout, 139 "turning off ignore of non-critical errors"); 140 } else if (strcmp(arg, "--retry-delay") == 0) { 141 assert_arg("--retry-delay"); 142 global_retry = atoll(arg); 143 dbg(stdout, "setting retry delay to %dus\n", 144 global_retry); 145 } else if (strcmp(arg, "--backoff") == 0) { 146 assert_arg("--backoff"); 147 global_backoff = atoll(arg); 148 if (global_backoff < 0) { 149 err(stderr, "invalid backoff factor: %i\n", 150 global_backoff); 151 exit(1); 152 } 153 dbg(stdout, "setting backoff coeffient to %dus\n", 154 global_backoff); 155 } else if (strcmp(arg, "--timeout") == 0 156 || strcmp(arg, "-t") == 0) { 157 do_timeout = 1; 158 assert_arg("--timeout"); 159 global_timeout = atoll_s(arg); 160 dbg(stdout, "setting timeout to %ds\n", global_timeout); 161 } else if (strcmp(arg, "--cpu") == 0 || strcmp(arg, "-c") == 0) { 162 do_cpu = 1; 163 assert_arg("--cpu"); 164 do_cpu_forks = atoll_b(arg); 165 } else if (strcmp(arg, "--io") == 0 || strcmp(arg, "-i") == 0) { 166 do_io = 1; 167 assert_arg("--io"); 168 do_io_forks = atoll_b(arg); 169 } else if (strcmp(arg, "--vm") == 0 || strcmp(arg, "-m") == 0) { 170 do_vm = 1; 171 assert_arg("--vm"); 172 do_vm_forks = atoll_b(arg); 173 } else if (strcmp(arg, "--vm-chunks") == 0) { 174 assert_arg("--vm-chunks"); 175 do_vm_chunks = atoll_b(arg); 176 } else if (strcmp(arg, "--vm-bytes") == 0) { 177 assert_arg("--vm-bytes"); 178 do_vm_bytes = atoll_b(arg); 179 } else if (strcmp(arg, "--vm-hang") == 0) { 180 global_vmhang = 1; 181 } else if (strcmp(arg, "--hdd") == 0 || strcmp(arg, "-d") == 0) { 182 do_hdd = 1; 183 assert_arg("--hdd"); 184 do_hdd_forks = atoll_b(arg); 185 } else if (strcmp(arg, "--hdd-noclean") == 0) { 186 do_hdd_clean = 2; 187 } else if (strcmp(arg, "--hdd-files") == 0) { 188 assert_arg("--hdd-files"); 189 do_hdd_files = atoll_b(arg); 190 } else if (strcmp(arg, "--hdd-bytes") == 0) { 191 assert_arg("--hdd-bytes"); 192 do_hdd_bytes = atoll_b(arg); 193 } else { 194 err(stderr, "unrecognized option: %s\n", arg); 195 exit(1); 196 } 197 } 198 199 /* Hog CPU option. */ 200 if (do_cpu) { 201 out(stdout, "dispatching %lli hogcpu forks\n", do_cpu_forks); 202 203 switch (pid = fork()) { 204 case 0: /* child */ 205 if (do_dryrun) 206 exit(0); 207 exit(hogcpu(do_cpu_forks)); 208 case -1: /* error */ 209 err(stderr, "hogcpu dispatcher fork failed\n"); 210 exit(1); 211 default: /* parent */ 212 children++; 213 dbg(stdout, "--> hogcpu dispatcher forked (%i)\n", pid); 214 } 215 } 216 217 /* Hog I/O option. */ 218 if (do_io) { 219 out(stdout, "dispatching %lli hogio forks\n", do_io_forks); 220 221 switch (pid = fork()) { 222 case 0: /* child */ 223 if (do_dryrun) 224 exit(0); 225 exit(hogio(do_io_forks)); 226 case -1: /* error */ 227 err(stderr, "hogio dispatcher fork failed\n"); 228 exit(1); 229 default: /* parent */ 230 children++; 231 dbg(stdout, "--> hogio dispatcher forked (%i)\n", pid); 232 } 233 } 234 235 /* Hog VM option. */ 236 if (do_vm) { 237 out(stdout, 238 "dispatching %lli hogvm forks, each %lli chunks of %lli bytes\n", 239 do_vm_forks, do_vm_chunks, do_vm_bytes); 240 241 switch (pid = fork()) { 242 case 0: /* child */ 243 if (do_dryrun) 244 exit(0); 245 exit(hogvm(do_vm_forks, do_vm_chunks, do_vm_bytes)); 246 case -1: /* error */ 247 err(stderr, "hogvm dispatcher fork failed\n"); 248 exit(1); 249 default: /* parent */ 250 children++; 251 dbg(stdout, "--> hogvm dispatcher forked (%i)\n", pid); 252 } 253 } 254 255 /* Hog HDD option. */ 256 if (do_hdd) { 257 out(stdout, "dispatching %lli hoghdd forks, each %lli files of " 258 "%lli bytes\n", do_hdd_forks, do_hdd_files, do_hdd_bytes); 259 260 switch (pid = fork()) { 261 case 0: /* child */ 262 if (do_dryrun) 263 exit(0); 264 exit(hoghdd 265 (do_hdd_forks, do_hdd_clean, do_hdd_files, 266 do_hdd_bytes)); 267 case -1: /* error */ 268 err(stderr, "hoghdd dispatcher fork failed\n"); 269 exit(1); 270 default: /* parent */ 271 children++; 272 dbg(stdout, "--> hoghdd dispatcher forked (%i)\n", pid); 273 } 274 } 275 276 /* We have no work to do, so bail out. */ 277 if (children == 0) 278 usage(0); 279 280 /* Wait for our children to exit. */ 281 while (children) { 282 int status, ret; 283 284 if ((pid = wait(&status)) > 0) { 285 if ((WIFEXITED(status)) != 0) { 286 if ((ret = WEXITSTATUS(status)) != 0) { 287 err(stderr, 288 "dispatcher %i returned error %i\n", 289 pid, ret); 290 retval += ret; 291 } else { 292 dbg(stdout, 293 "<-- dispatcher return (%i)\n", 294 pid); 295 } 296 } else { 297 err(stderr, 298 "dispatcher did not exit normally\n"); 299 ++retval; 300 } 301 302 --children; 303 } else { 304 dbg(stdout, "wait() returned error: %s\n", 305 strerror(errno)); 306 err(stderr, "detected missing dispatcher children\n"); 307 ++retval; 308 break; 309 } 310 } 311 312 /* Record our stop time. */ 313 if ((stoptime = time(NULL)) == -1) { 314 err(stderr, "failed to acquire current time\n"); 315 exit(1); 316 } 317 318 /* Calculate our runtime. */ 319 runtime = stoptime - starttime; 320 321 /* Print final status message. */ 322 if (retval) { 323 err(stderr, "failed run completed in %lis\n", runtime); 324 } else { 325 out(stdout, "successful run completed in %lis\n", runtime); 326 } 327 328 exit(retval); 329 } 330 331 int usage(int status) 332 { 333 char *mesg = 334 "`%s' imposes certain types of compute stress on your system\n\n" 335 "Usage: %s [OPTION [ARG]] ...\n\n" 336 " -?, --help show this help statement\n" 337 " --version show version statement\n" 338 " -v, --verbose be verbose\n" 339 " -q, --quiet be quiet\n" 340 " -n, --dry-run show what would have been done\n" 341 " --no-retry exit rather than retry non-critical errors\n" 342 " --retry-delay n wait n us before continuing past error\n" 343 " -t, --timeout n timeout after n seconds\n" 344 " --backoff n wait for factor of n us before starting work\n" 345 " -c, --cpu n spawn n procs spinning on sqrt()\n" 346 " -i, --io n spawn n procs spinning on sync()\n" 347 " -m, --vm n spawn n procs spinning on malloc()\n" 348 " --vm-chunks c malloc c chunks (default is 1)\n" 349 " --vm-bytes b malloc chunks of b bytes (default is 256MB)\n" 350 " --vm-hang hang in a sleep loop after memory allocated\n" 351 " -d, --hdd n spawn n procs spinning on write()\n" 352 " --hdd-noclean do not unlink file to which random data written\n" 353 " --hdd-files f write to f files (default is 1)\n" 354 " --hdd-bytes b write b bytes (default is 1GB)\n\n" 355 "Infinity is denoted with 0. For -m, -d: n=0 means infinite redo,\n" 356 "n<0 means redo abs(n) times. Valid suffixes are m,h,d,y for time;\n" 357 "k,m,g for size.\n\n"; 358 359 fprintf(stdout, mesg, global_progname, global_progname); 360 361 if (status <= 0) 362 exit(-1 * status); 363 364 return 0; 365 } 366 367 int version(int status) 368 { 369 char *mesg = "%s %s\n"; 370 371 fprintf(stdout, mesg, global_progname, VERSION); 372 373 if (status <= 0) 374 exit(-1 * status); 375 376 return 0; 377 } 378 379 /* Convert a string representation of a number with an optional size suffix 380 * to a long long. 381 */ 382 long long atoll_b(const char *nptr) 383 { 384 int pos; 385 char suffix; 386 long long factor = 1; 387 388 if ((pos = strlen(nptr) - 1) < 0) { 389 err(stderr, "invalid string\n"); 390 exit(1); 391 } 392 393 switch (suffix = nptr[pos]) { 394 case 'k': 395 case 'K': 396 factor = 1024; 397 break; 398 case 'm': 399 case 'M': 400 factor = 1024 * 1024; 401 break; 402 case 'g': 403 case 'G': 404 factor = 1024 * 1024 * 1024; 405 break; 406 default: 407 if (suffix < '0' || suffix > '9') { 408 err(stderr, "unrecognized suffix: %c\n", suffix); 409 exit(1); 410 } 411 } 412 413 factor = atoll(nptr) * factor; 414 415 return factor; 416 } 417 418 /* Convert a string representation of a number with an optional time suffix 419 * to a long long. 420 */ 421 long long atoll_s(const char *nptr) 422 { 423 int pos; 424 char suffix; 425 long long factor = 1; 426 427 if ((pos = strlen(nptr) - 1) < 0) { 428 err(stderr, "invalid string\n"); 429 exit(1); 430 } 431 432 switch (suffix = nptr[pos]) { 433 case 's': 434 case 'S': 435 factor = 1; 436 break; 437 case 'm': 438 case 'M': 439 factor = 60; 440 break; 441 case 'h': 442 case 'H': 443 factor = 60 * 60; 444 break; 445 case 'd': 446 case 'D': 447 factor = 60 * 60 * 24; 448 break; 449 case 'y': 450 case 'Y': 451 factor = 60 * 60 * 24 * 360; 452 break; 453 default: 454 if (suffix < '0' || suffix > '9') { 455 err(stderr, "unrecognized suffix: %c\n", suffix); 456 exit(1); 457 } 458 } 459 460 factor = atoll(nptr) * factor; 461 462 return factor; 463 } 464 465 int hogcpu(long long forks) 466 { 467 long long i; 468 double d; 469 int pid, retval = 0; 470 471 /* Make local copies of global variables. */ 472 int ignore = global_ignore; 473 int retry = global_retry; 474 int timeout = global_timeout; 475 long backoff = global_backoff * forks; 476 477 dbg(stdout, "using backoff sleep of %lius for hogcpu\n", backoff); 478 479 for (i = 0; forks == 0 || i < forks; i++) { 480 switch (pid = fork()) { 481 case 0: /* child */ 482 alarm(timeout); 483 484 /* Use a backoff sleep to ensure we get good fork throughput. */ 485 usleep(backoff); 486 487 while (1) 488 d = sqrt(rand()); 489 490 /* This case never falls through; alarm signal can cause exit. */ 491 case -1: /* error */ 492 if (ignore) { 493 ++retval; 494 wrn(stderr, 495 "hogcpu worker fork failed, continuing\n"); 496 usleep(retry); 497 continue; 498 } 499 500 err(stderr, "hogcpu worker fork failed\n"); 501 return 1; 502 default: /* parent */ 503 dbg(stdout, "--> hogcpu worker forked (%i)\n", pid); 504 } 505 } 506 507 /* Wait for our children to exit. */ 508 while (i) { 509 int status, ret; 510 511 if ((pid = wait(&status)) > 0) { 512 if ((WIFEXITED(status)) != 0) { 513 if ((ret = WEXITSTATUS(status)) != 0) { 514 err(stderr, 515 "hogcpu worker %i exited %i\n", pid, 516 ret); 517 retval += ret; 518 } else { 519 dbg(stdout, 520 "<-- hogcpu worker exited (%i)\n", 521 pid); 522 } 523 } else { 524 dbg(stdout, 525 "<-- hogcpu worker signalled (%i)\n", pid); 526 } 527 528 --i; 529 } else { 530 dbg(stdout, "wait() returned error: %s\n", 531 strerror(errno)); 532 err(stderr, 533 "detected missing hogcpu worker children\n"); 534 ++retval; 535 break; 536 } 537 } 538 539 return retval; 540 } 541 542 int hogio(long long forks) 543 { 544 long long i; 545 int pid, retval = 0; 546 547 /* Make local copies of global variables. */ 548 int ignore = global_ignore; 549 int retry = global_retry; 550 int timeout = global_timeout; 551 long backoff = global_backoff * forks; 552 553 dbg(stdout, "using backoff sleep of %lius for hogio\n", backoff); 554 555 for (i = 0; forks == 0 || i < forks; i++) { 556 switch (pid = fork()) { 557 case 0: /* child */ 558 alarm(timeout); 559 560 /* Use a backoff sleep to ensure we get good fork throughput. */ 561 usleep(backoff); 562 563 while (1) 564 sync(); 565 566 /* This case never falls through; alarm signal can cause exit. */ 567 case -1: /* error */ 568 if (ignore) { 569 ++retval; 570 wrn(stderr, 571 "hogio worker fork failed, continuing\n"); 572 usleep(retry); 573 continue; 574 } 575 576 err(stderr, "hogio worker fork failed\n"); 577 return 1; 578 default: /* parent */ 579 dbg(stdout, "--> hogio worker forked (%i)\n", pid); 580 } 581 } 582 583 /* Wait for our children to exit. */ 584 while (i) { 585 int status, ret; 586 587 if ((pid = wait(&status)) > 0) { 588 if ((WIFEXITED(status)) != 0) { 589 if ((ret = WEXITSTATUS(status)) != 0) { 590 err(stderr, 591 "hogio worker %i exited %i\n", pid, 592 ret); 593 retval += ret; 594 } else { 595 dbg(stdout, 596 "<-- hogio worker exited (%i)\n", 597 pid); 598 } 599 } else { 600 dbg(stdout, "<-- hogio worker signalled (%i)\n", 601 pid); 602 } 603 604 --i; 605 } else { 606 dbg(stdout, "wait() returned error: %s\n", 607 strerror(errno)); 608 err(stderr, "detected missing hogio worker children\n"); 609 ++retval; 610 break; 611 } 612 } 613 614 return retval; 615 } 616 617 int hogvm(long long forks, long long chunks, long long bytes) 618 { 619 long long i, j, k; 620 int pid, retval = 0; 621 char **ptr; 622 623 /* Make local copies of global variables. */ 624 int ignore = global_ignore; 625 int retry = global_retry; 626 int timeout = global_timeout; 627 long backoff = global_backoff * forks; 628 629 dbg(stdout, "using backoff sleep of %lius for hogvm\n", backoff); 630 631 if (bytes == 0) { 632 /* 512MB is guess at the largest value can than be malloced at once. */ 633 bytes = 512 * 1024 * 1024; 634 } 635 636 for (i = 0; forks == 0 || i < forks; i++) { 637 switch (pid = fork()) { 638 case 0: /* child */ 639 alarm(timeout); 640 641 /* Use a backoff sleep to ensure we get good fork throughput. */ 642 usleep(backoff); 643 644 while (1) { 645 ptr = (char **)malloc(chunks * 2); 646 for (j = 0; chunks == 0 || j < chunks; j++) { 647 if ((ptr[j] = 648 (char *)malloc(bytes * 649 sizeof(char)))) { 650 for (k = 0; k < bytes; k++) 651 ptr[j][k] = 'Z'; /* Ensure that COW happens. */ 652 dbg(stdout, 653 "hogvm worker malloced %lli bytes\n", 654 k); 655 } else if (ignore) { 656 ++retval; 657 wrn(stderr, 658 "hogvm malloc failed, continuing\n"); 659 usleep(retry); 660 continue; 661 } else { 662 ++retval; 663 err(stderr, 664 "hogvm malloc failed\n"); 665 break; 666 } 667 } 668 if (global_vmhang && retval == 0) { 669 dbg(stdout, 670 "sleeping forever with allocated memory\n"); 671 while (1) 672 sleep(1024); 673 } 674 if (retval == 0) { 675 dbg(stdout, 676 "hogvm worker freeing memory and starting over\n"); 677 for (j = 0; chunks == 0 || j < chunks; 678 j++) { 679 free(ptr[j]); 680 } 681 free(ptr); 682 continue; 683 } 684 685 exit(retval); 686 } 687 688 /* This case never falls through; alarm signal can cause exit. */ 689 case -1: /* error */ 690 if (ignore) { 691 ++retval; 692 wrn(stderr, 693 "hogvm worker fork failed, continuing\n"); 694 usleep(retry); 695 continue; 696 } 697 698 err(stderr, "hogvm worker fork failed\n"); 699 return 1; 700 default: /* parent */ 701 dbg(stdout, "--> hogvm worker forked (%i)\n", pid); 702 } 703 } 704 705 /* Wait for our children to exit. */ 706 while (i) { 707 int status, ret; 708 709 if ((pid = wait(&status)) > 0) { 710 if ((WIFEXITED(status)) != 0) { 711 if ((ret = WEXITSTATUS(status)) != 0) { 712 err(stderr, 713 "hogvm worker %i exited %i\n", pid, 714 ret); 715 retval += ret; 716 } else { 717 dbg(stdout, 718 "<-- hogvm worker exited (%i)\n", 719 pid); 720 } 721 } else { 722 dbg(stdout, "<-- hogvm worker signalled (%i)\n", 723 pid); 724 } 725 726 --i; 727 } else { 728 dbg(stdout, "wait() returned error: %s\n", 729 strerror(errno)); 730 err(stderr, "detected missing hogvm worker children\n"); 731 ++retval; 732 break; 733 } 734 } 735 736 return retval; 737 } 738 739 int hoghdd(long long forks, int clean, long long files, long long bytes) 740 { 741 long long i, j; 742 int fd, pid, retval = 0; 743 int chunk = (1024 * 1024) - 1; /* Minimize slow writing. */ 744 char buff[chunk]; 745 746 /* Make local copies of global variables. */ 747 int ignore = global_ignore; 748 int retry = global_retry; 749 int timeout = global_timeout; 750 long backoff = global_backoff * forks; 751 752 /* Initialize buffer with some random ASCII data. */ 753 dbg(stdout, "seeding buffer with random data\n"); 754 for (i = 0; i < chunk - 1; i++) { 755 j = rand(); 756 j = (j < 0) ? -j : j; 757 j %= 95; 758 j += 32; 759 buff[i] = j; 760 } 761 buff[i] = '\n'; 762 763 dbg(stdout, "using backoff sleep of %lius for hoghdd\n", backoff); 764 765 for (i = 0; forks == 0 || i < forks; i++) { 766 switch (pid = fork()) { 767 case 0: /* child */ 768 alarm(timeout); 769 770 /* Use a backoff sleep to ensure we get good fork throughput. */ 771 usleep(backoff); 772 773 while (1) { 774 for (i = 0; i < files; i++) { 775 char name[] = "./stress.XXXXXX"; 776 777 if ((fd = mkstemp(name)) < 0) { 778 perror("mkstemp"); 779 err(stderr, "mkstemp failed\n"); 780 exit(1); 781 } 782 783 if (clean == 0) { 784 dbg(stdout, "unlinking %s\n", 785 name); 786 if (unlink(name)) { 787 err(stderr, 788 "unlink failed\n"); 789 exit(1); 790 } 791 } 792 793 dbg(stdout, "fast writing to %s\n", 794 name); 795 for (j = 0; 796 bytes == 0 || j + chunk < bytes; 797 j += chunk) { 798 if (write(fd, buff, chunk) != 799 chunk) { 800 err(stderr, 801 "write failed\n"); 802 exit(1); 803 } 804 } 805 806 dbg(stdout, "slow writing to %s\n", 807 name); 808 for (; bytes == 0 || j < bytes - 1; j++) { 809 if (write(fd, "Z", 1) != 1) { 810 err(stderr, 811 "write failed\n"); 812 exit(1); 813 } 814 } 815 if (write(fd, "\n", 1) != 1) { 816 err(stderr, "write failed\n"); 817 exit(1); 818 } 819 ++j; 820 821 dbg(stdout, 822 "closing %s after writing %lli bytes\n", 823 name, j); 824 close(fd); 825 826 if (clean == 1) { 827 if (unlink(name)) { 828 err(stderr, 829 "unlink failed\n"); 830 exit(1); 831 } 832 } 833 } 834 if (retval == 0) { 835 dbg(stdout, 836 "hoghdd worker starting over\n"); 837 continue; 838 } 839 840 exit(retval); 841 } 842 843 /* This case never falls through; alarm signal can cause exit. */ 844 case -1: /* error */ 845 if (ignore) { 846 ++retval; 847 wrn(stderr, 848 "hoghdd worker fork failed, continuing\n"); 849 usleep(retry); 850 continue; 851 } 852 853 err(stderr, "hoghdd worker fork failed\n"); 854 return 1; 855 default: /* parent */ 856 dbg(stdout, "--> hoghdd worker forked (%i)\n", pid); 857 } 858 } 859 860 /* Wait for our children to exit. */ 861 while (i) { 862 int status, ret; 863 864 if ((pid = wait(&status)) > 0) { 865 if ((WIFEXITED(status)) != 0) { 866 if ((ret = WEXITSTATUS(status)) != 0) { 867 err(stderr, 868 "hoghdd worker %i exited %i\n", pid, 869 ret); 870 retval += ret; 871 } else { 872 dbg(stdout, 873 "<-- hoghdd worker exited (%i)\n", 874 pid); 875 } 876 } else { 877 dbg(stdout, 878 "<-- hoghdd worker signalled (%i)\n", pid); 879 } 880 881 --i; 882 } else { 883 dbg(stdout, "wait() returned error: %s\n", 884 strerror(errno)); 885 err(stderr, 886 "detected missing hoghdd worker children\n"); 887 ++retval; 888 break; 889 } 890 } 891 892 return retval; 893 } 894