1 /*
2 * Copyright (C) 2013-2021 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 * This code is a complete clean re-write of the stress tool by
19 * Colin Ian King <colin.king@canonical.com> and attempts to be
20 * backwardly compatible with the stress tool by Amos Waterland
21 * <apw@rossby.metr.ou.edu> but has more stress tests and more
22 * functionality.
23 *
24 */
25 #include "stress-ng.h"
26
27 #define MAX_NANOSLEEP_THREADS (8)
28
29 #if defined(HAVE_LIB_PTHREAD) && \
30 defined(HAVE_NANOSLEEP)
31
32 typedef struct {
33 const stress_args_t *args;
34 uint64_t counter;
35 pthread_t pthread;
36 } stress_ctxt_t;
37
38 static volatile bool thread_terminate;
39 static sigset_t set;
40 #endif
41
42 static const stress_help_t help[] = {
43 { NULL, "nanosleep N", "start N workers performing short sleeps" },
44 { NULL, "nanosleep-ops N", "stop after N bogo sleep operations" },
45 { NULL, NULL, NULL }
46 };
47
48 #if defined(HAVE_LIB_PTHREAD)
49
stress_sigalrm_handler(int signum)50 static void MLOCKED_TEXT stress_sigalrm_handler(int signum)
51 {
52 (void)signum;
53
54 thread_terminate = true;
55 }
56
57 /*
58 * stress_pthread_func()
59 * pthread that performs different ranges of sleeps
60 */
stress_pthread_func(void * c)61 static void *stress_pthread_func(void *c)
62 {
63 static void *nowt = NULL;
64 stress_ctxt_t *ctxt = (stress_ctxt_t *)c;
65 const stress_args_t *args = ctxt->args;
66 const uint64_t max_ops =
67 args->max_ops ? (args->max_ops / MAX_NANOSLEEP_THREADS) + 1 : 0;
68
69 while (keep_stressing(args) &&
70 !thread_terminate &&
71 (!max_ops || (ctxt->counter < max_ops))) {
72 struct timespec tv;
73 unsigned long i;
74
75 for (i = 1 << 18; i > 0; i >>=1) {
76 tv.tv_sec = 0;
77 tv.tv_nsec = (stress_mwc32() % i) + 8;
78 if (nanosleep(&tv, NULL) < 0)
79 break;
80 }
81 ctxt->counter++;
82 }
83 return &nowt;
84 }
85
86 /*
87 * stress_nanosleep()
88 * stress nanosleep by many sleeping threads
89 */
stress_nanosleep(const stress_args_t * args)90 static int stress_nanosleep(const stress_args_t *args)
91 {
92 uint64_t i, n, limited = 0;
93 static stress_ctxt_t ctxts[MAX_NANOSLEEP_THREADS];
94 int ret = EXIT_SUCCESS;
95
96 if (stress_sighandler(args->name, SIGALRM, stress_sigalrm_handler, NULL) < 0)
97 return EXIT_FAILURE;
98
99 (void)memset(ctxts, 0, sizeof(ctxts));
100 (void)sigfillset(&set);
101
102 for (n = 0; n < MAX_NANOSLEEP_THREADS; n++) {
103 ctxts[n].args = args;
104 ret = pthread_create(&ctxts[n].pthread, NULL,
105 stress_pthread_func, &ctxts[n]);
106 if (ret) {
107 /* Out of resources, don't try any more */
108 if (ret == EAGAIN) {
109 limited++;
110 break;
111 }
112 /* Something really unexpected */
113 pr_fail("%s: pthread create failed, errno=%d (%s)\n",
114 args->name, ret, strerror(ret));
115 ret = EXIT_NO_RESOURCE;
116 goto tidy;
117 }
118 /* Timed out? abort! */
119 if (!keep_stressing_flag())
120 goto tidy;
121 }
122
123 stress_set_proc_state(args->name, STRESS_STATE_RUN);
124
125 do {
126 set_counter(args, 0);
127 (void)shim_usleep_interruptible(10000);
128 for (i = 0; i < n; i++)
129 add_counter(args, ctxts[i].counter);
130 } while (!thread_terminate && keep_stressing(args));
131
132 ret = EXIT_SUCCESS;
133 tidy:
134 stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
135
136 thread_terminate = true;
137 for (i = 0; i < n; i++) {
138 ret = pthread_join(ctxts[i].pthread, NULL);
139 (void)ret;
140 /*
141 if (ret)
142 pr_dbg("%s: pthread join, ret=%d\n", args->name, ret);
143 */
144 }
145
146 if (limited) {
147 pr_inf("%s: %.2f%% of iterations could not reach "
148 "requested %d threads (instance %"
149 PRIu32 ")\n",
150 args->name,
151 100.0 * (double)limited / (double)MAX_NANOSLEEP_THREADS,
152 MAX_NANOSLEEP_THREADS, args->instance);
153 }
154
155 return ret;
156 }
157
158 stressor_info_t stress_nanosleep_info = {
159 .stressor = stress_nanosleep,
160 .class = CLASS_INTERRUPT | CLASS_SCHEDULER | CLASS_OS,
161 .help = help
162 };
163 #else
164 stressor_info_t stress_nanosleep_info = {
165 .stressor = stress_not_implemented,
166 .class = CLASS_INTERRUPT | CLASS_SCHEDULER | CLASS_OS,
167 .help = help
168 };
169 #endif
170