xref: /xnu-11215.61.5/tests/vm/posix_spawnattr_set_jetsam_ttr.c (revision 4f1223e81cd707a65cc109d0b8ad6653699da3c4)
1 #include <mach-o/dyld.h>
2 #include <spawn.h>
3 #include <spawn_private.h>
4 #include <stdlib.h>
5 #include <sys/spawn_internal.h>
6 #include <sys/sysctl.h>
7 
8 #include <darwintest.h>
9 #include <darwintest_utils.h>
10 
11 T_GLOBAL_META(
12 	T_META_NAMESPACE("xnu.vm"),
13 	T_META_RADAR_COMPONENT_NAME("xnu"),
14 	T_META_RADAR_COMPONENT_VERSION("VM"));
15 
16 static void
set_small_relaunch_values(posix_spawnattr_t * attrs)17 set_small_relaunch_values(posix_spawnattr_t *attrs)
18 {
19 	static const uint32_t kNumRelaunchValues = 16;
20 	static uint32_t relaunch_values[kNumRelaunchValues] = {0};
21 	int ret;
22 	/*
23 	 * Set the relaunch times to very small values (in m.s.).
24 	 * Everything under 5 seconds is expected to fall in the high relaunch behavior bucket.
25 	 */
26 	for (uint32_t i = 0; i < kNumRelaunchValues; i++) {
27 		relaunch_values[i] = i;
28 	}
29 	ret = posix_spawnattr_set_jetsam_ttr_np(attrs, kNumRelaunchValues, relaunch_values);
30 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "posix_spawnattr_set_jetsam_ttr_np");
31 }
32 
33 T_DECL(set_high_relaunch_behavior, "supply very small time to relaunch values", T_META_TAG_VM_PREFERRED)
34 {
35 	posix_spawnattr_t attrs;
36 	_posix_spawnattr_t psattr;
37 	uint32_t relaunch_flags = 0;
38 
39 	posix_spawnattr_init(&attrs);
40 	set_small_relaunch_values(&attrs);
41 
42 	psattr = *(_posix_spawnattr_t *)&attrs;
43 
44 	relaunch_flags = psattr->psa_jetsam_flags & POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_MASK;
45 	T_QUIET; T_ASSERT_EQ(relaunch_flags, POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_HIGH, "relaunch behavior is high");
46 
47 	posix_spawnattr_destroy(&attrs);
48 }
49 
50 T_DECL(set_medium_relaunch_behavior, "supply very large time to relaunch values", T_META_TAG_VM_PREFERRED)
51 {
52 	posix_spawnattr_t attrs;
53 	_posix_spawnattr_t psattr;
54 	int ret;
55 	static const uint32_t kNumRelaunchValues = 16;
56 	static uint32_t relaunch_values[kNumRelaunchValues] = {0};
57 	uint32_t relaunch_flags = 0;
58 
59 	posix_spawnattr_init(&attrs);
60 
61 	/*
62 	 * Set the relaunch times to medium large values (in m.s.).
63 	 * Everything over between 5 and 10 seconds is expected to fall in the medium relaunch behavior bucket.
64 	 */
65 	for (uint32_t i = 0; i < kNumRelaunchValues; i++) {
66 		relaunch_values[i] = 5000 + i;
67 	}
68 	ret = posix_spawnattr_set_jetsam_ttr_np(&attrs, kNumRelaunchValues, relaunch_values);
69 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "posix_spawnattr_set_jetsam_ttr_np");
70 
71 	psattr = *(_posix_spawnattr_t *)&attrs;
72 
73 	relaunch_flags = psattr->psa_jetsam_flags & POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_MASK;
74 	T_QUIET; T_ASSERT_EQ(relaunch_flags, POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_MED, "relaunch behavior is medium");
75 
76 	posix_spawnattr_destroy(&attrs);
77 }
78 
79 
80 T_DECL(set_low_relaunch_behavior, "supply very large time to relaunch values", T_META_TAG_VM_PREFERRED)
81 {
82 	posix_spawnattr_t attrs;
83 	_posix_spawnattr_t psattr;
84 	int ret;
85 	static const uint32_t kNumRelaunchValues = 16;
86 	static uint32_t relaunch_values[kNumRelaunchValues] = {0};
87 	uint32_t relaunch_flags = 0;
88 
89 	posix_spawnattr_init(&attrs);
90 
91 	/*
92 	 * Set the relaunch times to very large values (in m.s.).
93 	 * Everything over 10 seconds is expected to fall in the low relaunch behavior bucket.
94 	 */
95 	for (uint32_t i = 0; i < kNumRelaunchValues; i++) {
96 		relaunch_values[i] = 10000 + i;
97 	}
98 	ret = posix_spawnattr_set_jetsam_ttr_np(&attrs, kNumRelaunchValues, relaunch_values);
99 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "posix_spawnattr_set_jetsam_ttr_np");
100 
101 	psattr = *(_posix_spawnattr_t *)&attrs;
102 
103 	relaunch_flags = psattr->psa_jetsam_flags & POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_MASK;
104 	T_QUIET; T_ASSERT_EQ(relaunch_flags, POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_LOW, "relaunch behavior is low");
105 
106 	posix_spawnattr_destroy(&attrs);
107 }
108 
109 T_DECL(set_high_relaunch_with_mixed_histogram, "supply slightly more small values than large values", T_META_TAG_VM_PREFERRED)
110 {
111 	posix_spawnattr_t attrs;
112 	_posix_spawnattr_t psattr;
113 	int ret;
114 	static const uint32_t kNumRelaunchValues = 16;
115 	static uint32_t relaunch_values[kNumRelaunchValues] = {0};
116 	uint32_t relaunch_flags = 0;
117 
118 	posix_spawnattr_init(&attrs);
119 
120 	/*
121 	 * Make sure the high likelihood bucket (<5 seconds) is a bit larger than the others
122 	 */
123 	for (uint32_t i = 0; i < kNumRelaunchValues; i++) {
124 		if (i % 2 == 0) {
125 			relaunch_values[i] = i;
126 		} else {
127 			if (i % 3 == 0) {
128 				relaunch_values[i] = 10000 + i;
129 			} else {
130 				relaunch_values[i] = 5000 + i;
131 			}
132 		}
133 	}
134 	ret = posix_spawnattr_set_jetsam_ttr_np(&attrs, kNumRelaunchValues, relaunch_values);
135 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "posix_spawnattr_set_jetsam_ttr_np");
136 
137 	psattr = *(_posix_spawnattr_t *)&attrs;
138 
139 	relaunch_flags = psattr->psa_jetsam_flags & POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_MASK;
140 	T_QUIET; T_ASSERT_EQ(relaunch_flags, POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_HIGH, "relaunch behavior is high");
141 
142 	posix_spawnattr_destroy(&attrs);
143 }
144 
145 extern char **environ;
146 T_HELPER_DECL(check_relaunch_flags, "Check that we have the high relaunch likelihood flag set")
147 {
148 	int relaunch_flags;
149 	size_t size = sizeof(relaunch_flags);
150 	int ret = sysctlbyname("kern.memorystatus_relaunch_flags", &relaunch_flags, &size, NULL, 0);
151 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "failed to query vm.pagesize");
152 	T_QUIET; T_ASSERT_EQ(relaunch_flags, POSIX_SPAWN_JETSAM_RELAUNCH_BEHAVIOR_HIGH, "relaunch behavior is high");
153 }
154 
155 T_HELPER_DECL(exec_into_check_relaunch_flags, "Do an exec into check_relaunch_flags")
156 {
157 	posix_spawnattr_t attrs;
158 	int ret;
159 	char testpath[PATH_MAX];
160 	uint32_t testpath_buf_size;
161 	char **arguments;
162 
163 	testpath_buf_size = sizeof(testpath);
164 	ret = _NSGetExecutablePath(testpath, &testpath_buf_size);
165 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "_NSGetExecutablePath");
166 
167 	arguments = (char *[]) {
168 		testpath,
169 		"-n",
170 		"check_relaunch_flags",
171 		NULL
172 	};
173 	posix_spawnattr_init(&attrs);
174 	ret = posix_spawnattr_setflags(&attrs, POSIX_SPAWN_SETEXEC);
175 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "posix spawn set exec flag");
176 	ret = posix_spawn(NULL, testpath, NULL, &attrs, arguments, environ);
177 	T_FAIL("posix_spawn failed with %s\n", strerror(ret));
178 }
179 
180 static void
posix_spawn_helper_and_wait_for_exit(char * name)181 posix_spawn_helper_and_wait_for_exit(char *name)
182 {
183 	posix_spawnattr_t attrs;
184 	int ret;
185 	pid_t child_pid;
186 	char testpath[PATH_MAX];
187 	uint32_t testpath_buf_size;
188 	char **arguments;
189 
190 	testpath_buf_size = sizeof(testpath);
191 	ret = _NSGetExecutablePath(testpath, &testpath_buf_size);
192 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "_NSGetExecutablePath");
193 
194 	posix_spawnattr_init(&attrs);
195 	set_small_relaunch_values(&attrs);
196 
197 	arguments = (char *[]) {
198 		testpath,
199 		"-n",
200 		name,
201 		NULL
202 	};
203 
204 	ret = posix_spawn(&child_pid, testpath, NULL, &attrs, arguments, environ);
205 
206 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "posix_spawn");
207 
208 	while (true) {
209 		int status;
210 		pid_t rc = waitpid(child_pid, &status, 0);
211 		if (rc == -1 && errno == EINTR) {
212 			continue;
213 		}
214 		T_QUIET; T_ASSERT_EQ(rc, child_pid, "waitpid");
215 		T_QUIET; T_ASSERT_TRUE(WIFEXITED(status), "Exited cleanly");
216 		T_QUIET; T_ASSERT_EQ(WEXITSTATUS(status), 0, "return code was 0");
217 		break;
218 	}
219 
220 	posix_spawnattr_destroy(&attrs);
221 }
222 
223 T_DECL(posix_spawn_sets_relaunch_flags, "Check that posix_spawn sets the relaunch flags on the new proc", T_META_TAG_VM_PREFERRED)
224 {
225 	posix_spawn_helper_and_wait_for_exit("check_relaunch_flags");
226 }
227 
228 T_DECL(relaunch_flags_persist_across_exec, "Check that the relaunch flags persist across exec", T_META_TAG_VM_PREFERRED)
229 {
230 	posix_spawn_helper_and_wait_for_exit("exec_into_check_relaunch_flags");
231 }
232