/* * stress_userfaultfd_child() * generate page faults for parent to handle */ static int stress_userfaultfd_child(void *arg) { context_t *c = (context_t *)arg; const args_t *args = c->args; (void)setpgid(0, g_pgrp); stress_parent_died_alarm(); if (stress_sighandler(args->name, SIGALRM, stress_child_alarm_handler, NULL) < 0) return EXIT_NO_RESOURCE; do { uint8_t *ptr, *end = c->data + c->sz; /* hint we don't need these pages */ if (shim_madvise(c->data, c->sz, MADV_DONTNEED) < 0) { pr_fail_err("userfaultfd madvise failed"); (void)kill(c->parent, SIGALRM); return -1; } /* and trigger some page faults */ for (ptr = c->data; ptr < end; ptr += c->page_size) *ptr = 0xff; } while (keep_stressing()); return 0; }
/* * stress_sigq * stress by heavy sigqueue message sending */ static int stress_sigq(const args_t *args) { pid_t pid; if (stress_sighandler(args->name, SIGUSR1, stress_sigqhandler, NULL) < 0) return EXIT_FAILURE; again: pid = fork(); if (pid < 0) { if (g_keep_stressing_flag && (errno == EAGAIN)) goto again; pr_fail_dbg("fork"); return EXIT_FAILURE; } else if (pid == 0) { sigset_t mask; (void)setpgid(0, g_pgrp); stress_parent_died_alarm(); (void)sigemptyset(&mask); (void)sigaddset(&mask, SIGUSR1); while (g_keep_stressing_flag) { siginfo_t info; if (sigwaitinfo(&mask, &info) < 0) break; if (info.si_value.sival_int) break; } pr_dbg("%s: child got termination notice\n", args->name); pr_dbg("%s: exited on pid [%d] (instance %" PRIu32 ")\n", args->name, (int)getpid(), args->instance); _exit(0); } else { /* Parent */ union sigval s; int status; do { (void)memset(&s, 0, sizeof(s)); s.sival_int = 0; (void)sigqueue(pid, SIGUSR1, s); inc_counter(args); } while (keep_stressing()); pr_dbg("%s: parent sent termination notice\n", args->name); (void)memset(&s, 0, sizeof(s)); s.sival_int = 1; (void)sigqueue(pid, SIGUSR1, s); (void)shim_usleep(250); /* And ensure child is really dead */ (void)kill(pid, SIGKILL); (void)shim_waitpid(pid, &status, 0); } return EXIT_SUCCESS; }
/* * stress_timer * stress timers */ static int stress_timer(const args_t *args) { struct sigevent sev; struct itimerspec timer; sigset_t mask; uint64_t timer_freq = DEFAULT_TIMER_FREQ; (void)sigemptyset(&mask); (void)sigaddset(&mask, SIGINT); (void)sigprocmask(SIG_SETMASK, &mask, NULL); max_ops = args->max_ops; start = time_now(); if (!get_setting("timer-freq", &timer_freq)) { if (g_opt_flags & OPT_FLAGS_MAXIMIZE) timer_freq = MAX_TIMER_FREQ; if (g_opt_flags & OPT_FLAGS_MINIMIZE) timer_freq = MIN_TIMER_FREQ; } rate_ns = timer_freq ? 1000000000.0 / timer_freq : 1000000000.0; if (stress_sighandler(args->name, SIGRTMIN, stress_timer_handler, NULL) < 0) return EXIT_FAILURE; sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGRTMIN; sev.sigev_value.sival_ptr = &timerid; if (timer_create(CLOCK_REALTIME, &sev, &timerid) < 0) { pr_fail_err("timer_create"); return EXIT_FAILURE; } stress_timer_set(&timer); if (timer_settime(timerid, 0, &timer, NULL) < 0) { pr_fail_err("timer_settime"); return EXIT_FAILURE; } do { struct timespec req; req.tv_sec = 0; req.tv_nsec = 10000000; (void)nanosleep(&req, NULL); set_counter(args, timer_counter); } while (keep_stressing()); if (timer_delete(timerid) < 0) { pr_fail_err("timer_delete"); return EXIT_FAILURE; } pr_dbg("%s: %" PRIu64 " timer overruns (instance %" PRIu32 ")\n", args->name, overruns, args->instance); return EXIT_SUCCESS; }
/* * stress_msync() * stress msync */ int stress_msync( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { uint8_t *buf = NULL; const size_t page_size = stress_get_pagesize(); const size_t min_size = 2 * page_size; size_t sz = min_size; ssize_t ret, rc = EXIT_SUCCESS; const pid_t pid = getpid(); int fd = -1; char filename[PATH_MAX]; ret = sigsetjmp(jmp_env, 1); if (ret) { pr_fail_err(name, "sigsetjmp"); return EXIT_FAILURE; } if (stress_sighandler(name, SIGBUS, stress_sigbus_handler, NULL) < 0) return EXIT_FAILURE; if (!set_msync_bytes) { if (opt_flags & OPT_FLAGS_MAXIMIZE) opt_msync_bytes = MAX_MSYNC_BYTES; if (opt_flags & OPT_FLAGS_MINIMIZE) opt_msync_bytes = MIN_MSYNC_BYTES; } sz = opt_msync_bytes & ~(page_size - 1); if (sz < min_size) sz = min_size; /* Make sure this is killable by OOM killer */ set_oom_adjustment(name, true); rc = stress_temp_dir_mk(name, pid, instance); if (rc < 0) return exit_status(-rc); (void)stress_temp_filename(filename, sizeof(filename), name, pid, instance, mwc32()); (void)umask(0077); if ((fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) { rc = exit_status(errno); pr_fail_err(name, "open"); (void)unlink(filename); (void)stress_temp_dir_rm(name, pid, instance); return rc; } (void)unlink(filename); if (ftruncate(fd, sz) < 0) { pr_err(stderr, "%s: ftruncate failed, errno=%d (%s)\n", name, errno, strerror(errno)); (void)close(fd); (void)stress_temp_dir_rm(name, pid, instance); return EXIT_FAILURE; } buf = (uint8_t *)mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (buf == MAP_FAILED) { pr_err(stderr, "%s: failed to mmap memory, errno=%d (%s)\n", name, errno, strerror(errno)); rc = EXIT_NO_RESOURCE; goto err; } do { off_t offset; uint8_t val, data[page_size]; ret = sigsetjmp(jmp_env, 1); if (ret) { /* Try again */ continue; } /* * Change data in memory, msync to disk */ offset = (mwc64() % (sz - page_size)) & ~(page_size - 1); val = mwc8(); memset(buf + offset, val, page_size); ret = msync(buf + offset, page_size, MS_SYNC); if (ret < 0) { pr_fail(stderr, "%s: msync MS_SYNC on " "offset %jd failed, errno=%d (%s)", name, (intmax_t)offset, errno, strerror(errno)); goto do_invalidate; } ret = lseek(fd, offset, SEEK_SET); if (ret == (off_t)-1) { pr_err(stderr, "%s: cannot seet to offset %jd, " "errno=%d (%s)\n", name, (intmax_t)offset, errno, strerror(errno)); rc = EXIT_NO_RESOURCE; break; } ret = read(fd, data, sizeof(data)); if (ret < (ssize_t)sizeof(data)) { pr_fail(stderr, "%s: read failed, errno=%d (%s)\n", name, errno, strerror(errno)); goto do_invalidate; } if (stress_page_check(data, val, sizeof(data)) < 0) { pr_fail(stderr, "%s: msync'd data in file different " "to data in memory\n", name); } do_invalidate: /* * Now change data on disc, msync invalidate */ offset = (mwc64() % (sz - page_size)) & ~(page_size - 1); val = mwc8(); memset(buf + offset, val, page_size); ret = lseek(fd, offset, SEEK_SET); if (ret == (off_t)-1) { pr_err(stderr, "%s: cannot seet to offset %jd, errno=%d (%s)\n", name, (intmax_t)offset, errno, strerror(errno)); rc = EXIT_NO_RESOURCE; break; } ret = read(fd, data, sizeof(data)); if (ret < (ssize_t)sizeof(data)) { pr_fail(stderr, "%s: read failed, errno=%d (%s)\n", name, errno, strerror(errno)); goto do_next; } ret = msync(buf + offset, page_size, MS_INVALIDATE); if (ret < 0) { pr_fail(stderr, "%s: msync MS_INVALIDATE on " "offset %jd failed, errno=%d (%s)", name, (intmax_t)offset, errno, strerror(errno)); goto do_next; } if (stress_page_check(buf + offset, val, sizeof(data)) < 0) { pr_fail(stderr, "%s: msync'd data in memory " "different to data in file\n", name); } do_next: (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); (void)munmap((void *)buf, sz); err: (void)close(fd); (void)stress_temp_dir_rm(name, pid, instance); if (sigbus_count) pr_inf(stdout, "%s: caught %" PRIu64 " SIGBUS signals\n", name, sigbus_count); return rc; }
/* * stress_fault() * stress min and max page faulting */ static int stress_fault(const args_t *args) { #if !defined(__HAIKU__) struct rusage usage; #endif char filename[PATH_MAX]; int ret; NOCLOBBER int i; ret = stress_temp_dir_mk_args(args); if (ret < 0) return exit_status(-ret); (void)stress_temp_filename_args(args, filename, sizeof(filename), mwc32()); i = 0; if (stress_sighandler(args->name, SIGSEGV, stress_segvhandler, NULL) < 0) return EXIT_FAILURE; if (stress_sighandler(args->name, SIGBUS, stress_segvhandler, NULL) < 0) return EXIT_FAILURE; do { char *ptr; int fd; ret = sigsetjmp(jmp_env, 1); if (ret) { do_jmp = false; pr_err("%s: unexpected segmentation fault\n", args->name); break; } fd = open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd < 0) { if ((errno == ENOSPC) || (errno == ENOMEM)) continue; /* Try again */ pr_fail_err("open"); break; } #if defined(HAVE_POSIX_FALLOCATE) if (posix_fallocate(fd, 0, 1) < 0) { if (errno == ENOSPC) { (void)close(fd); continue; /* Try again */ } (void)close(fd); pr_fail_err("posix_fallocate"); break; } #else { char buffer[1]; redo: if (g_keep_stressing_flag && (write(fd, buffer, sizeof(buffer)) < 0)) { if ((errno == EAGAIN) || (errno == EINTR)) goto redo; if (errno == ENOSPC) { (void)close(fd); continue; } (void)close(fd); pr_fail_err("write"); break; } } #endif ret = sigsetjmp(jmp_env, 1); if (ret) { if (!keep_stressing()) do_jmp = false; if (fd != -1) (void)close(fd); goto next; } /* * Removing file here causes major fault when we touch * ptr later */ if (i & 1) (void)unlink(filename); ptr = mmap(NULL, 1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); (void)close(fd); fd = -1; (void)fd; if (ptr == MAP_FAILED) { if ((errno == EAGAIN) || (errno == ENOMEM) || (errno == ENFILE)) goto next; pr_err("%s: mmap failed: errno=%d (%s)\n", args->name, errno, strerror(errno)); break; } *ptr = 0; /* Cause the page fault */ if (munmap(ptr, 1) < 0) { pr_err("%s: munmap failed: errno=%d (%s)\n", args->name, errno, strerror(errno)); break; } next: /* Remove file on-non major fault case */ if (!(i & 1)) (void)unlink(filename); i++; inc_counter(args); } while (keep_stressing()); /* Clean up, most times this is redundant */ (void)unlink(filename); (void)stress_temp_dir_rm_args(args); #if !defined(__HAIKU__) if (!getrusage(RUSAGE_SELF, &usage)) { pr_dbg("%s: page faults: minor: %lu, major: %lu\n", args->name, usage.ru_minflt, usage.ru_majflt); } #endif return EXIT_SUCCESS; }
/* * stress_mergesort() * stress mergesort */ static int stress_mergesort(const args_t *args) { uint64_t mergesort_size = DEFAULT_MERGESORT_SIZE; int32_t *data, *ptr; size_t n, i; struct sigaction old_action; int ret; if (!get_setting("mergesort-size", &mergesort_size)) { if (g_opt_flags & OPT_FLAGS_MAXIMIZE) mergesort_size = MAX_MERGESORT_SIZE; if (g_opt_flags & OPT_FLAGS_MINIMIZE) mergesort_size = MIN_MERGESORT_SIZE; } n = (size_t)mergesort_size; if ((data = calloc(n, sizeof(*data))) == NULL) { pr_fail_dbg("malloc"); return EXIT_NO_RESOURCE; } if (stress_sighandler(args->name, SIGALRM, stress_mergesort_handler, &old_action) < 0) { free(data); return EXIT_FAILURE; } ret = sigsetjmp(jmp_env, 1); if (ret) { /* * We return here if SIGALRM jmp'd back */ (void)stress_sigrestore(args->name, SIGALRM, &old_action); goto tidy; } /* This is expensive, do it once */ for (ptr = data, i = 0; i < n; i++) *ptr++ = mwc32(); do { /* Sort "random" data */ if (mergesort(data, n, sizeof(*data), stress_mergesort_cmp_1) < 0) { pr_fail("%s: mergesort of random data failed: %d (%s)\n", args->name, errno, strerror(errno)); } else { if (g_opt_flags & OPT_FLAGS_VERIFY) { for (ptr = data, i = 0; i < n - 1; i++, ptr++) { if (*ptr > *(ptr+1)) { pr_fail("%s: sort error " "detected, incorrect ordering " "found\n", args->name); break; } } } } if (!g_keep_stressing_flag) break; /* Reverse sort */ if (mergesort(data, n, sizeof(*data), stress_mergesort_cmp_2) < 0) { pr_fail("%s: reversed mergesort of random data failed: %d (%s)\n", args->name, errno, strerror(errno)); } else { if (g_opt_flags & OPT_FLAGS_VERIFY) { for (ptr = data, i = 0; i < n - 1; i++, ptr++) { if (*ptr < *(ptr+1)) { pr_fail("%s: reverse sort " "error detected, incorrect " "ordering found\n", args->name); break; } } } } if (!g_keep_stressing_flag) break; /* And re-order by random compare to remix the data */ if (mergesort(data, n, sizeof(*data), stress_mergesort_cmp_3) < 0) { pr_fail("%s: mergesort failed: %d (%s)\n", args->name, errno, strerror(errno)); } /* Reverse sort this again */ if (mergesort(data, n, sizeof(*data), stress_mergesort_cmp_2) < 0) { pr_fail("%s: reversed mergesort of random data failed: %d (%s)\n", args->name, errno, strerror(errno)); } if (g_opt_flags & OPT_FLAGS_VERIFY) { for (ptr = data, i = 0; i < n - 1; i++, ptr++) { if (*ptr < *(ptr+1)) { pr_fail("%s: reverse sort " "error detected, incorrect " "ordering found\n", args->name); break; } } } if (!g_keep_stressing_flag) break; inc_counter(args); } while (keep_stressing()); do_jmp = false; (void)stress_sigrestore(args->name, SIGALRM, &old_action); tidy: free(data); return EXIT_SUCCESS; }
/* * epoll_server() * wait on connections and read data */ static void epoll_server( const int child, uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name, const pid_t ppid) { int efd = -1, sfd = -1, rc = EXIT_SUCCESS; int so_reuseaddr = 1; int port = opt_epoll_port + child + (max_servers * instance); struct epoll_event *events = NULL; struct sockaddr *addr = NULL; socklen_t addr_len = 0; if (stress_sighandler(name, SIGALRM, handle_socket_sigalrm, NULL) < 0) { rc = EXIT_FAILURE; goto die; } if ((sfd = socket(opt_epoll_domain, SOCK_STREAM, 0)) < 0) { pr_fail_err(name, "socket"); rc = EXIT_FAILURE; goto die; } if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr, sizeof(so_reuseaddr)) < 0) { pr_fail_err(name, "setsockopt"); rc = EXIT_FAILURE; goto die_close; } stress_set_sockaddr(name, instance, ppid, opt_epoll_domain, port, &addr, &addr_len); if (bind(sfd, addr, addr_len) < 0) { pr_fail_err(name, "bind"); rc = EXIT_FAILURE; goto die_close; } if (epoll_set_fd_nonblock(sfd) < 0) { pr_fail_err(name, "setting socket to non-blocking"); rc = EXIT_FAILURE; goto die_close; } if (listen(sfd, SOMAXCONN) < 0) { pr_fail_err(name, "listen"); rc = EXIT_FAILURE; goto die_close; } if ((efd = epoll_create1(0)) < 0) { pr_fail_err(name, "epoll_create1"); rc = EXIT_FAILURE; goto die_close; } if (epoll_ctl_add(efd, sfd) < 0) { pr_fail_err(name, "epoll ctl add"); rc = EXIT_FAILURE; goto die_close; } if ((events = calloc(MAX_EPOLL_EVENTS, sizeof(struct epoll_event))) == NULL) { pr_fail_err(name, "epoll ctl add"); rc = EXIT_FAILURE; goto die_close; } do { int n, i; memset(events, 0, MAX_EPOLL_EVENTS * sizeof(struct epoll_event)); errno = 0; /* * Wait for 100ms for an event, allowing us to * to break out if opt_do_run has been changed */ n = epoll_wait(efd, events, MAX_EPOLL_EVENTS, 100); if (n < 0) { if (errno != EINTR) { pr_fail_err(name, "epoll_wait"); rc = EXIT_FAILURE; goto die_close; } break; } for (i = 0; i < n; i++) { if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) { /* * Error has occurred or fd is not * for reading anymore.. so reap fd */ (void)close(events[i].data.fd); } else if (sfd == events[i].data.fd) { /* * The listening socket has notification(s) * pending, so handle incoming connections */ if (epoll_notification(name, efd, sfd) < 0) break; } else { /* * The fd has data available, so read it */ epoll_recv_data(events[i].data.fd); } } } while (opt_do_run && (!max_ops || *counter < max_ops)); die_close: if (efd != -1) (void)close(efd); if (sfd != -1) (void)close(sfd); die: #ifdef AF_UNIX if (addr && (opt_epoll_domain == AF_UNIX)) { struct sockaddr_un *addr_un = (struct sockaddr_un *)addr; (void)unlink(addr_un->sun_path); } #endif free(events); exit(rc); }
/* * stress_socket_server() * server writer */ static int stress_socket_server( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name, const pid_t pid, const pid_t ppid) { char buf[SOCKET_BUF]; int fd, status; int so_reuseaddr = 1; socklen_t addr_len = 0; struct sockaddr *addr; uint64_t msgs = 0; int rc = EXIT_SUCCESS; setpgid(pid, pgrp); if (stress_sighandler(name, SIGALRM, handle_socket_sigalrm, NULL) < 0) { rc = EXIT_FAILURE; goto die; } if ((fd = socket(opt_socket_domain, SOCK_STREAM, 0)) < 0) { rc = exit_status(errno); pr_fail_dbg(name, "socket"); goto die; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr, sizeof(so_reuseaddr)) < 0) { pr_fail_dbg(name, "setsockopt"); rc = EXIT_FAILURE; goto die_close; } stress_set_sockaddr(name, instance, ppid, opt_socket_domain, opt_socket_port, &addr, &addr_len); if (bind(fd, addr, addr_len) < 0) { rc = exit_status(errno); pr_fail_dbg(name, "bind"); goto die_close; } if (listen(fd, 10) < 0) { pr_fail_dbg(name, "listen"); rc = EXIT_FAILURE; goto die_close; } do { int sfd = accept(fd, (struct sockaddr *)NULL, NULL); if (sfd >= 0) { size_t i, j; struct sockaddr addr; socklen_t len; int sndbuf; struct msghdr msg; struct iovec vec[sizeof(buf)/16]; #if defined(HAVE_SENDMMSG) struct mmsghdr msgvec[MSGVEC_SIZE]; unsigned int msg_len = 0; #endif #if defined(SOCKET_NODELAY) int one = 1; #endif len = sizeof(addr); if (getsockname(fd, &addr, &len) < 0) { pr_fail_dbg(name, "getsockname"); (void)close(sfd); break; } len = sizeof(sndbuf); if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, &len) < 0) { pr_fail_dbg(name, "getsockopt"); (void)close(sfd); break; } #if defined(SOCKET_NODELAY) if (opt_flags & OPT_FLAGS_SOCKET_NODELAY) { if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) { pr_inf(stderr, "%s: setsockopt TCP_NODELAY " "failed and disabled, errno=%d (%s)\n", name, errno, strerror(errno)); opt_flags &= ~OPT_FLAGS_SOCKET_NODELAY; } } #endif memset(buf, 'A' + (*counter % 26), sizeof(buf)); switch (opt_socket_opts) { case SOCKET_OPT_SEND: for (i = 16; i < sizeof(buf); i += 16) { ssize_t ret = send(sfd, buf, i, 0); if (ret < 0) { if (errno != EINTR) pr_fail_dbg(name, "send"); break; } else msgs++; } break; case SOCKET_OPT_SENDMSG: for (j = 0, i = 16; i < sizeof(buf); i += 16, j++) { vec[j].iov_base = buf; vec[j].iov_len = i; } memset(&msg, 0, sizeof(msg)); msg.msg_iov = vec; msg.msg_iovlen = j; if (sendmsg(sfd, &msg, 0) < 0) { if (errno != EINTR) pr_fail_dbg(name, "sendmsg"); } else msgs += j; break; #if defined(HAVE_SENDMMSG) case SOCKET_OPT_SENDMMSG: memset(msgvec, 0, sizeof(msgvec)); for (j = 0, i = 16; i < sizeof(buf); i += 16, j++) { vec[j].iov_base = buf; vec[j].iov_len = i; msg_len += i; } for (i = 0; i < MSGVEC_SIZE; i++) { msgvec[i].msg_hdr.msg_iov = vec; msgvec[i].msg_hdr.msg_iovlen = j; } if (sendmmsg(sfd, msgvec, MSGVEC_SIZE, 0) < 0) { if (errno != EINTR) pr_fail_dbg(name, "sendmmsg"); } else msgs += (MSGVEC_SIZE * j); break; #endif default: /* Should never happen */ pr_err(stderr, "%s: bad option %d\n", name, opt_socket_opts); (void)close(sfd); goto die_close; } if (getpeername(sfd, &addr, &len) < 0) { pr_fail_dbg(name, "getpeername"); } (void)close(sfd); } (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); die_close: (void)close(fd); die: #ifdef AF_UNIX if (opt_socket_domain == AF_UNIX) { struct sockaddr_un *addr_un = (struct sockaddr_un *)addr; (void)unlink(addr_un->sun_path); } #endif if (pid) { (void)kill(pid, SIGKILL); (void)waitpid(pid, &status, 0); } pr_dbg(stderr, "%s: %" PRIu64 " messages sent\n", name, msgs); return rc; }
/* * epoll_client() * rapidly try to connect to server(s) and * send a relatively short message */ static int epoll_client( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name, const pid_t ppid) { int port_counter = 0; uint64_t connect_timeouts = 0; struct sigevent sev; struct itimerspec timer; struct sockaddr *addr = NULL; if (stress_sighandler(name, SIGRTMIN, epoll_timer_handler, NULL) < 0) return -1; do { char buf[4096]; int fd, saved_errno; int retries = 0; int ret = -1; int port = opt_epoll_port + port_counter + (max_servers * instance); socklen_t addr_len = 0; /* Cycle through the servers */ port_counter = (port_counter + 1) % max_servers; retry: if (!opt_do_run) break; if ((fd = socket(opt_epoll_domain, SOCK_STREAM, 0)) < 0) { pr_fail_dbg(name, "socket"); return -1; } sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGRTMIN; sev.sigev_value.sival_ptr = &epoll_timerid; if (timer_create(CLOCK_REALTIME, &sev, &epoll_timerid) < 0) { pr_fail_err(name, "timer_create"); (void)close(fd); return -1; } /* * Allow 1 second for connection to occur, * connect can block if the connection table * fills up because we're waiting for TIME-OUTs * to occur on previously closed connections */ timer.it_value.tv_sec = 0; timer.it_value.tv_nsec = 250000000; timer.it_interval.tv_sec = timer.it_value.tv_sec; timer.it_interval.tv_nsec = timer.it_value.tv_nsec; if (timer_settime(epoll_timerid, 0, &timer, NULL) < 0) { pr_fail_err(name, "timer_settime"); (void)close(fd); return -1; } stress_set_sockaddr(name, instance, ppid, opt_epoll_domain, port, &addr, &addr_len); errno = 0; ret = connect(fd, addr, addr_len); saved_errno = errno; /* No longer need timer */ if (timer_delete(epoll_timerid) < 0) { pr_fail_err(name, "timer_delete"); (void)close(fd); return -1; } if (ret < 0) { switch (saved_errno) { case EINTR: connect_timeouts++; break; case ECONNREFUSED: /* No servers yet running */ case ENOENT: /* unix domain not yet created */ break; default: pr_dbg(stderr, "%s: connect failed: %d (%s)\n", name, saved_errno, strerror(saved_errno)); break; } (void)close(fd); usleep(100000); /* Twiddle fingers for a moment */ retries++; if (retries > 1000) { /* Sigh, give up.. */ errno = saved_errno; pr_fail_dbg(name, "too many connects"); return -1; } goto retry; } memset(buf, 'A' + (*counter % 26), sizeof(buf)); if (send(fd, buf, sizeof(buf), 0) < 0) { (void)close(fd); pr_fail_dbg(name, "send"); break; } (void)close(fd); #if defined(_POSIX_PRIORITY_SCHEDULING) sched_yield(); #endif (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); #ifdef AF_UNIX if (addr && (opt_epoll_domain == AF_UNIX)) { struct sockaddr_un *addr_un = (struct sockaddr_un *)addr; (void)unlink(addr_un->sun_path); } #endif if (connect_timeouts) pr_dbg(stderr, "%s: %" PRIu64 " x 0.25 second connect timeouts, " "connection table full (instance %" PRIu32 ")\n", name, connect_timeouts, instance); return EXIT_SUCCESS; }
/* * stress_sigq * stress by heavy sigqueue message sending */ int stress_sigq( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { pid_t pid; if (stress_sighandler(name, SIGUSR1, stress_sigqhandler, NULL) < 0) return EXIT_FAILURE; again: pid = fork(); if (pid < 0) { if (opt_do_run && (errno == EAGAIN)) goto again; pr_fail_dbg(name, "fork"); return EXIT_FAILURE; } else if (pid == 0) { sigset_t mask; setpgid(0, pgrp); stress_parent_died_alarm(); sigemptyset(&mask); sigaddset(&mask, SIGUSR1); while (opt_do_run) { siginfo_t info; sigwaitinfo(&mask, &info); if (info.si_value.sival_int) break; } pr_dbg(stderr, "%s: child got termination notice\n", name); pr_dbg(stderr, "%s: exited on pid [%d] (instance %" PRIu32 ")\n", name, getpid(), instance); _exit(0); } else { /* Parent */ union sigval s; int status; do { memset(&s, 0, sizeof(s)); s.sival_int = 0; sigqueue(pid, SIGUSR1, s); (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); pr_dbg(stderr, "%s: parent sent termination notice\n", name); memset(&s, 0, sizeof(s)); s.sival_int = 1; sigqueue(pid, SIGUSR1, s); usleep(250); /* And ensure child is really dead */ (void)kill(pid, SIGKILL); (void)waitpid(pid, &status, 0); } return EXIT_SUCCESS; }
/* * stress_lease * stress by fcntl lease activity */ static int stress_lease(const args_t *args) { char filename[PATH_MAX]; int ret, fd, status; pid_t l_pids[MAX_LEASE_BREAKERS]; uint64_t i, lease_breakers = DEFAULT_LEASE_BREAKERS; if (!get_setting("lease-breakers", &lease_breakers)) { if (g_opt_flags & OPT_FLAGS_MAXIMIZE) lease_breakers = MAX_LEASE_BREAKERS; if (g_opt_flags & OPT_FLAGS_MINIMIZE) lease_breakers = MIN_LEASE_BREAKERS; } (void)memset(l_pids, 0, sizeof(l_pids)); if (stress_sighandler(args->name, SIGIO, stress_lease_handler, NULL) < 0) return EXIT_FAILURE; ret = stress_temp_dir_mk_args(args); if (ret < 0) return exit_status(-ret); (void)stress_temp_filename_args(args, filename, sizeof(filename), mwc32()); fd = creat(filename, S_IRUSR | S_IWUSR); if (fd < 0) { ret = exit_status(errno); pr_err("%s: creat failed: errno=%d: (%s)\n", args->name, errno, strerror(errno)); (void)stress_temp_dir_rm_args(args); return ret; } (void)close(fd); for (i = 0; i < lease_breakers; i++) { l_pids[i] = stress_lease_spawn(args, filename); if (l_pids[i] < 0) { pr_err("%s: failed to start all the lease breaker processes\n", args->name); goto reap; } } do { fd = open(filename, O_WRONLY | O_APPEND, S_IRUSR | S_IWUSR); if (fd < 0) { ret = exit_status(errno); pr_err("%s: open failed (parent): errno=%d: (%s)\n", args->name, errno, strerror(errno)); goto reap; } while (fcntl(fd, F_SETLEASE, F_WRLCK) < 0) { if (!g_keep_stressing_flag) { (void)close(fd); goto reap; } } inc_counter(args); (void)shim_sched_yield(); if (fcntl(fd, F_SETLEASE, F_UNLCK) < 0) { pr_err("%s: fcntl failed: errno=%d: (%s)\n", args->name, errno, strerror(errno)); (void)close(fd); break; } (void)close(fd); } while (keep_stressing()); ret = EXIT_SUCCESS; reap: for (i = 0; i < lease_breakers; i++) { if (l_pids[i]) { (void)kill(l_pids[i], SIGKILL); (void)shim_waitpid(l_pids[i], &status, 0); } } (void)unlink(filename); (void)stress_temp_dir_rm_args(args); pr_dbg("%s: %" PRIu64 " lease sigio interrupts caught\n", args->name, lease_sigio); return ret; }
/* * stress_mergesort() * stress mergesort */ int stress_mergesort( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { int32_t *data, *ptr; size_t n, i; struct sigaction old_action; int ret; (void)instance; if (!set_mergesort_size) { if (opt_flags & OPT_FLAGS_MAXIMIZE) opt_mergesort_size = MAX_MERGESORT_SIZE; if (opt_flags & OPT_FLAGS_MINIMIZE) opt_mergesort_size = MIN_MERGESORT_SIZE; } n = (size_t)opt_mergesort_size; if ((data = calloc(n, sizeof(int32_t))) == NULL) { pr_fail_dbg(name, "malloc"); return EXIT_FAILURE; } if (stress_sighandler(name, SIGALRM, stress_mergesort_handler, &old_action) < 0) { free(data); return EXIT_FAILURE; } ret = sigsetjmp(jmp_env, 1); if (ret) { /* * We return here if SIGALRM jmp'd back */ (void)stress_sigrestore(name, SIGALRM, &old_action); goto tidy; } /* This is expensive, do it once */ for (ptr = data, i = 0; i < n; i++) *ptr++ = mwc32(); do { /* Sort "random" data */ mergesort(data, n, sizeof(uint32_t), stress_mergesort_cmp_1); if (opt_flags & OPT_FLAGS_VERIFY) { for (ptr = data, i = 0; i < n - 1; i++, ptr++) { if (*ptr > *(ptr+1)) { pr_fail(stderr, "%s: sort error " "detected, incorrect ordering " "found\n", name); break; } } } if (!opt_do_run) break; /* Reverse sort */ mergesort(data, n, sizeof(uint32_t), stress_mergesort_cmp_2); if (opt_flags & OPT_FLAGS_VERIFY) { for (ptr = data, i = 0; i < n - 1; i++, ptr++) { if (*ptr < *(ptr+1)) { pr_fail(stderr, "%s: reverse sort " "error detected, incorrect " "ordering found\n", name); break; } } } if (!opt_do_run) break; /* And re-order by byte compare */ mergesort(data, n * 4, sizeof(uint8_t), stress_mergesort_cmp_3); /* Reverse sort this again */ mergesort(data, n, sizeof(uint32_t), stress_mergesort_cmp_2); if (opt_flags & OPT_FLAGS_VERIFY) { for (ptr = data, i = 0; i < n - 1; i++, ptr++) { if (*ptr < *(ptr+1)) { pr_fail(stderr, "%s: reverse sort " "error detected, incorrect " "ordering found\n", name); break; } } } if (!opt_do_run) break; (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); do_jmp = false; (void)stress_sigrestore(name, SIGALRM, &old_action); tidy: free(data); return EXIT_SUCCESS; }
/* * stress_fault() * stress min and max page faulting */ int stress_fault( uint64_t *const counter, const uint32_t instance, const uint64_t max_ops, const char *name) { struct rusage usage; char filename[PATH_MAX]; int ret, i; const pid_t pid = getpid(); ret = stress_temp_dir_mk(name, pid, instance); if (ret < 0) return exit_status(-ret); (void)stress_temp_filename(filename, sizeof(filename), name, pid, instance, mwc32()); (void)umask(0077); i = 0; if (stress_sighandler(name, SIGSEGV, stress_segvhandler, NULL) < 0) return EXIT_FAILURE; do { char *ptr; int fd; ret = sigsetjmp(jmp_env, 1); if (ret) { do_jmp = false; pr_err(stderr, "%s: unexpected segmentation fault\n", name); break; } fd = open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd < 0) { if ((errno == ENOSPC) || (errno == ENOMEM)) continue; /* Try again */ pr_err(stderr, "%s: open failed: errno=%d (%s)\n", name, errno, strerror(errno)); break; } #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L if (posix_fallocate(fd, 0, 1) < 0) { if (errno == ENOSPC) { (void)close(fd); continue; /* Try again */ } (void)close(fd); pr_err(stderr, "%s: posix_fallocate failed: errno=%d (%s)\n", name, errno, strerror(errno)); break; } #else { char buffer[1]; redo: if (opt_do_run && (write(fd, buffer, sizeof(buffer)) < 0)) { if ((errno == EAGAIN) || (errno == EINTR)) goto redo; if (errno == ENOSPC) { (void)close(fd); continue; } (void)close(fd); pr_err(stderr, "%s: write failed: errno=%d (%s)\n", name, errno, strerror(errno)); break; } } #endif ret = sigsetjmp(jmp_env, 1); if (ret) { if (!opt_do_run || (max_ops && *counter >= max_ops)) do_jmp = false; if (fd != -1) (void)close(fd); goto next; } /* * Removing file here causes major fault when we touch * ptr later */ if (i & 1) (void)unlink(filename); ptr = mmap(NULL, 1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); (void)close(fd); fd = -1; if (ptr == MAP_FAILED) { pr_err(stderr, "%s: mmap failed: errno=%d (%s)\n", name, errno, strerror(errno)); break; } *ptr = 0; /* Cause the page fault */ if (munmap(ptr, 1) < 0) { pr_err(stderr, "%s: munmap failed: errno=%d (%s)\n", name, errno, strerror(errno)); break; } next: /* Remove file on-non major fault case */ if (!(i & 1)) (void)unlink(filename); i++; (*counter)++; } while (opt_do_run && (!max_ops || *counter < max_ops)); /* Clean up, most times this is redundant */ (void)unlink(filename); (void)stress_temp_dir_rm(name, pid, instance); if (!getrusage(RUSAGE_SELF, &usage)) { pr_dbg(stderr, "%s: page faults: minor: %lu, major: %lu\n", name, usage.ru_minflt, usage.ru_majflt); } return EXIT_SUCCESS; }