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 typedef struct {
28 	double ts;		/* timestamp */
29 	uint32_t check0;	/* memory clobbering check canary */
30 	jmp_buf buf;		/* jmpbuf itself */
31 	uint32_t check1;	/* memory clobbering check canary */
32 } jmp_buf_check_t;
33 
34 static jmp_buf_check_t bufchk;
35 
36 static const stress_help_t help[] = {
37 	{ NULL,	"longjmp N",	 "start N workers exercising setjmp/longjmp" },
38 	{ NULL,	"longjmp-ops N", "stop after N longjmp bogo operations" },
39 	{ NULL,	NULL,		 NULL }
40 };
41 
stress_longjmp_func(void)42 static void OPTIMIZE1 NOINLINE NORETURN stress_longjmp_func(void)
43 {
44 	bufchk.ts = stress_time_now();
45 	longjmp(bufchk.buf, 1);	/* Jump out */
46 
47 	_exit(EXIT_FAILURE);	/* Never get here */
48 }
49 
50 /*
51  *  stress_jmp()
52  *	stress system by setjmp/longjmp calls
53  */
stress_longjmp(const stress_args_t * args)54 static int OPTIMIZE1 stress_longjmp(const stress_args_t *args)
55 {
56 	int ret;
57 	static uint32_t check0, check1;
58 	static double t_total;
59 	static uint64_t n = 0;
60 
61 	check0 = stress_mwc32();
62 	check1 = stress_mwc32();
63 
64 	bufchk.check0 = check0;
65 	bufchk.check1 = check1;
66 
67 	stress_set_proc_state(args->name, STRESS_STATE_RUN);
68 
69 	ret = setjmp(bufchk.buf);
70 
71 	if (ret) {
72 		static int c = 0;
73 
74 		t_total += (stress_time_now() - bufchk.ts);
75 		n++;
76 		/*
77 		 *  Sanity check to see if setjmp clobbers regions
78 		 *  before/after the jmpbuf
79 		 */
80 		if (bufchk.check0 != check0) {
81 			pr_err("%s: memory corrupted before jmpbuf region\n",
82 				args->name);
83 		}
84 		if (bufchk.check1 != check1) {
85 			pr_err("%s: memory corrupted before jmpbuf region\n",
86 				args->name);
87 		}
88 
89 		if (c++ >= 1000) {
90 			inc_counter(args);
91 			c = 0;
92 		}
93 	}
94 	if (keep_stressing(args))
95 		stress_longjmp_func();
96 
97 	if (n) {
98 		const double rate = (double)STRESS_NANOSECOND * t_total / (double)n;
99 		pr_dbg("%s: about %.3f nanoseconds per longjmp call\n",
100 			args->name, rate);
101 		stress_misc_stats_set(args->misc_stats, 0, "nanoseconds per longjmp call", rate);
102 	}
103 	stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
104 
105 	return EXIT_SUCCESS;
106 }
107 
108 stressor_info_t stress_longjmp_info = {
109 	.stressor = stress_longjmp,
110 	.class = CLASS_CPU,
111 	.help = help
112 };
113