xref: /xnu-11417.140.69/tests/game_mode.c (revision 43a90889846e00bfb5cf1d255cdc0a701a1e05a4)
1*43a90889SApple OSS Distributions /*
2*43a90889SApple OSS Distributions  * Copyright (c) 2023 Apple Inc. All rights reserved.
3*43a90889SApple OSS Distributions  *
4*43a90889SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*43a90889SApple OSS Distributions  *
6*43a90889SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*43a90889SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*43a90889SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*43a90889SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*43a90889SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*43a90889SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*43a90889SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*43a90889SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*43a90889SApple OSS Distributions  *
15*43a90889SApple OSS Distributions  * Please obtain a copy of the License at
16*43a90889SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*43a90889SApple OSS Distributions  *
18*43a90889SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*43a90889SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*43a90889SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*43a90889SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*43a90889SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*43a90889SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*43a90889SApple OSS Distributions  * limitations under the License.
25*43a90889SApple OSS Distributions  *
26*43a90889SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*43a90889SApple OSS Distributions  */
28*43a90889SApple OSS Distributions 
29*43a90889SApple OSS Distributions /* test that the header doesn't implicitly depend on others */
30*43a90889SApple OSS Distributions #include <sys/resource_private.h>
31*43a90889SApple OSS Distributions #include <sys/resource.h>
32*43a90889SApple OSS Distributions 
33*43a90889SApple OSS Distributions #include <mach/coalition.h>
34*43a90889SApple OSS Distributions #include <sys/coalition.h>
35*43a90889SApple OSS Distributions #include <libproc.h>
36*43a90889SApple OSS Distributions 
37*43a90889SApple OSS Distributions #include <sys/types.h>
38*43a90889SApple OSS Distributions #include <unistd.h>
39*43a90889SApple OSS Distributions 
40*43a90889SApple OSS Distributions #include <darwintest.h>
41*43a90889SApple OSS Distributions #include <darwintest_utils.h>
42*43a90889SApple OSS Distributions 
43*43a90889SApple OSS Distributions /* TODO: can this come from the right header? */
44*43a90889SApple OSS Distributions #define THREAD_GROUP_FLAGS_GAME_MODE            0x800
45*43a90889SApple OSS Distributions 
46*43a90889SApple OSS Distributions T_GLOBAL_META(T_META_NAMESPACE("xnu.scheduler"),
47*43a90889SApple OSS Distributions     T_META_RADAR_COMPONENT_NAME("xnu"),
48*43a90889SApple OSS Distributions     T_META_RADAR_COMPONENT_VERSION("scheduler"),
49*43a90889SApple OSS Distributions     T_META_OWNER("chimene"),
50*43a90889SApple OSS Distributions     T_META_RUN_CONCURRENTLY(false),
51*43a90889SApple OSS Distributions     T_META_TAG_VM_PREFERRED);
52*43a90889SApple OSS Distributions 
53*43a90889SApple OSS Distributions static void
check_game_mode(bool expected_mode)54*43a90889SApple OSS Distributions check_game_mode(bool expected_mode)
55*43a90889SApple OSS Distributions {
56*43a90889SApple OSS Distributions 	int game_mode = getpriority(PRIO_DARWIN_GAME_MODE, 0);
57*43a90889SApple OSS Distributions 
58*43a90889SApple OSS Distributions 	T_QUIET;
59*43a90889SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(game_mode, "getpriority(PRIO_DARWIN_GAME_MODE)");
60*43a90889SApple OSS Distributions 
61*43a90889SApple OSS Distributions 	T_LOG("pid %d: game mode is: %d", getpid(), game_mode);
62*43a90889SApple OSS Distributions 
63*43a90889SApple OSS Distributions 	if (expected_mode) {
64*43a90889SApple OSS Distributions 		T_QUIET;
65*43a90889SApple OSS Distributions 		T_ASSERT_EQ(game_mode, PRIO_DARWIN_GAME_MODE_ON, "should be on");
66*43a90889SApple OSS Distributions 	} else {
67*43a90889SApple OSS Distributions 		T_QUIET;
68*43a90889SApple OSS Distributions 		T_ASSERT_EQ(game_mode, PRIO_DARWIN_GAME_MODE_OFF, "should be off");
69*43a90889SApple OSS Distributions 	}
70*43a90889SApple OSS Distributions }
71*43a90889SApple OSS Distributions 
72*43a90889SApple OSS Distributions T_DECL(entitled_game_mode, "game mode bit should be settable while entitled")
73*43a90889SApple OSS Distributions {
74*43a90889SApple OSS Distributions 	T_LOG("uid: %d", getuid());
75*43a90889SApple OSS Distributions 
76*43a90889SApple OSS Distributions 	check_game_mode(false);
77*43a90889SApple OSS Distributions 
78*43a90889SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_ON),
79*43a90889SApple OSS Distributions 	    "setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_ON)");
80*43a90889SApple OSS Distributions 
81*43a90889SApple OSS Distributions 	check_game_mode(true);
82*43a90889SApple OSS Distributions 
83*43a90889SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_OFF),
84*43a90889SApple OSS Distributions 	    "setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_OFF)");
85*43a90889SApple OSS Distributions 
86*43a90889SApple OSS Distributions 	check_game_mode(false);
87*43a90889SApple OSS Distributions }
88*43a90889SApple OSS Distributions 
89*43a90889SApple OSS Distributions T_DECL(entitled_game_mode_read_root, "game mode bit should be readable as root",
90*43a90889SApple OSS Distributions     T_META_ASROOT(true))
91*43a90889SApple OSS Distributions {
92*43a90889SApple OSS Distributions 	T_LOG("uid: %d", getuid());
93*43a90889SApple OSS Distributions 
94*43a90889SApple OSS Distributions 	check_game_mode(false);
95*43a90889SApple OSS Distributions }
96*43a90889SApple OSS Distributions 
97*43a90889SApple OSS Distributions T_DECL(entitled_game_mode_read_notroot, "game mode bit should be readable as not root but entitled",
98*43a90889SApple OSS Distributions     T_META_ASROOT(false))
99*43a90889SApple OSS Distributions {
100*43a90889SApple OSS Distributions 	T_LOG("uid: %d", getuid());
101*43a90889SApple OSS Distributions 
102*43a90889SApple OSS Distributions 	check_game_mode(false);
103*43a90889SApple OSS Distributions }
104*43a90889SApple OSS Distributions 
105*43a90889SApple OSS Distributions static struct coalinfo_debuginfo
get_coal_debuginfo(uint64_t coal_id,char * prefix)106*43a90889SApple OSS Distributions get_coal_debuginfo(uint64_t coal_id, char* prefix)
107*43a90889SApple OSS Distributions {
108*43a90889SApple OSS Distributions 	struct coalinfo_debuginfo coaldebuginfo = {};
109*43a90889SApple OSS Distributions 
110*43a90889SApple OSS Distributions 	int ret = coalition_info_debug_info(coal_id, &coaldebuginfo, sizeof(coaldebuginfo));
111*43a90889SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "coalition_info_debug_info");
112*43a90889SApple OSS Distributions 
113*43a90889SApple OSS Distributions 	T_LOG("coal(%s): %lld, game count %d, flags 0x%x (group 0x%llx, rec %d, focal: %d, nonfocal %d)",
114*43a90889SApple OSS Distributions 	    prefix, coal_id,
115*43a90889SApple OSS Distributions 	    coaldebuginfo.game_task_count, coaldebuginfo.thread_group_flags,
116*43a90889SApple OSS Distributions 	    coaldebuginfo.thread_group_id, coaldebuginfo.thread_group_recommendation,
117*43a90889SApple OSS Distributions 	    coaldebuginfo.focal_task_count, coaldebuginfo.nonfocal_task_count);
118*43a90889SApple OSS Distributions 
119*43a90889SApple OSS Distributions 	return coaldebuginfo;
120*43a90889SApple OSS Distributions }
121*43a90889SApple OSS Distributions 
122*43a90889SApple OSS Distributions static void
check_game_mode_count(uint32_t expected_count)123*43a90889SApple OSS Distributions check_game_mode_count(uint32_t expected_count)
124*43a90889SApple OSS Distributions {
125*43a90889SApple OSS Distributions 	struct proc_pidcoalitioninfo idinfo = {};
126*43a90889SApple OSS Distributions 
127*43a90889SApple OSS Distributions 	int ret = proc_pidinfo(getpid(), PROC_PIDCOALITIONINFO, 0,
128*43a90889SApple OSS Distributions 	    &idinfo, sizeof(idinfo));
129*43a90889SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "proc_pidinfo(... PROC_PIDCOALITIONINFO ...)");
130*43a90889SApple OSS Distributions 
131*43a90889SApple OSS Distributions 	uint64_t res_id = idinfo.coalition_id[COALITION_TYPE_RESOURCE];
132*43a90889SApple OSS Distributions 	uint64_t jet_id = idinfo.coalition_id[COALITION_TYPE_JETSAM];
133*43a90889SApple OSS Distributions 
134*43a90889SApple OSS Distributions 	struct coalinfo_debuginfo coaldebuginfo_res = get_coal_debuginfo(res_id, "res");
135*43a90889SApple OSS Distributions 	struct coalinfo_debuginfo coaldebuginfo_jet = get_coal_debuginfo(jet_id, "jet");
136*43a90889SApple OSS Distributions 
137*43a90889SApple OSS Distributions 	if (expected_count) {
138*43a90889SApple OSS Distributions 		// see COALITION_FOCAL_TASKS_ACCOUNTING for this difference
139*43a90889SApple OSS Distributions #if TARGET_OS_OSX
140*43a90889SApple OSS Distributions 		T_ASSERT_EQ(coaldebuginfo_res.game_task_count, expected_count, "should have game in res coalition");
141*43a90889SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(coaldebuginfo_jet.game_task_count, 0, "should not have game in jet coalition");
142*43a90889SApple OSS Distributions #else
143*43a90889SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(coaldebuginfo_res.game_task_count, 0, "should not have game in res coalition");
144*43a90889SApple OSS Distributions 		T_ASSERT_EQ(coaldebuginfo_jet.game_task_count, expected_count, "should have game in jet coalition");
145*43a90889SApple OSS Distributions #endif
146*43a90889SApple OSS Distributions 		T_ASSERT_BITS_SET(coaldebuginfo_jet.thread_group_flags, THREAD_GROUP_FLAGS_GAME_MODE,
147*43a90889SApple OSS Distributions 		    "should have game mode flag in jet coalition"); \
148*43a90889SApple OSS Distributions 	} else {
149*43a90889SApple OSS Distributions #if TARGET_OS_OSX
150*43a90889SApple OSS Distributions 		T_ASSERT_EQ(coaldebuginfo_res.game_task_count, 0, "should not have game in res coalition");
151*43a90889SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(coaldebuginfo_jet.game_task_count, 0, "should not have game in jet coalition");
152*43a90889SApple OSS Distributions #else
153*43a90889SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(coaldebuginfo_res.game_task_count, 0, "should not have game in res coalition");
154*43a90889SApple OSS Distributions 		T_ASSERT_EQ(coaldebuginfo_jet.game_task_count, 0, "should not have game in jet coalition");
155*43a90889SApple OSS Distributions #endif
156*43a90889SApple OSS Distributions 		T_ASSERT_BITS_NOTSET(coaldebuginfo_jet.thread_group_flags, THREAD_GROUP_FLAGS_GAME_MODE,
157*43a90889SApple OSS Distributions 		    "should not have game mode flag in jet coalition"); \
158*43a90889SApple OSS Distributions 	}
159*43a90889SApple OSS Distributions 
160*43a90889SApple OSS Distributions 	T_QUIET; T_ASSERT_BITS_NOTSET(coaldebuginfo_res.thread_group_flags, THREAD_GROUP_FLAGS_GAME_MODE,
161*43a90889SApple OSS Distributions 	    "should never have game mode flag in res coalition"); \
162*43a90889SApple OSS Distributions }
163*43a90889SApple OSS Distributions 
164*43a90889SApple OSS Distributions static void
skip_if_unsupported(void)165*43a90889SApple OSS Distributions skip_if_unsupported(void)
166*43a90889SApple OSS Distributions {
167*43a90889SApple OSS Distributions 	int r;
168*43a90889SApple OSS Distributions 	int supported = 0;
169*43a90889SApple OSS Distributions 	size_t supported_size = sizeof(supported);
170*43a90889SApple OSS Distributions 
171*43a90889SApple OSS Distributions 	r = sysctlbyname("kern.thread_groups_supported", &supported, &supported_size,
172*43a90889SApple OSS Distributions 	    NULL, 0);
173*43a90889SApple OSS Distributions 	if (r < 0) {
174*43a90889SApple OSS Distributions 		T_WITH_ERRNO;
175*43a90889SApple OSS Distributions 		T_SKIP("could not find \"kern.thread_groups_supported\" sysctl");
176*43a90889SApple OSS Distributions 	}
177*43a90889SApple OSS Distributions 
178*43a90889SApple OSS Distributions 	if (!supported) {
179*43a90889SApple OSS Distributions 		T_SKIP("test was run even though kern.thread_groups_supported is not 1, see rdar://111297938");
180*43a90889SApple OSS Distributions 	}
181*43a90889SApple OSS Distributions 
182*43a90889SApple OSS Distributions 	r = sysctlbyname("kern.development", &supported, &supported_size,
183*43a90889SApple OSS Distributions 	    NULL, 0);
184*43a90889SApple OSS Distributions 	if (r < 0) {
185*43a90889SApple OSS Distributions 		T_WITH_ERRNO;
186*43a90889SApple OSS Distributions 		T_SKIP("could not find \"kern.development\" sysctl");
187*43a90889SApple OSS Distributions 	}
188*43a90889SApple OSS Distributions 
189*43a90889SApple OSS Distributions 	if (!supported) {
190*43a90889SApple OSS Distributions 		T_SKIP("test was run even though kern.development is not 1, see rdar://111297938");
191*43a90889SApple OSS Distributions 	}
192*43a90889SApple OSS Distributions }
193*43a90889SApple OSS Distributions 
194*43a90889SApple OSS Distributions T_DECL(entitled_game_mode_check_count, "game mode bit should affect coalition thread group flags",
195*43a90889SApple OSS Distributions     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1), T_META_REQUIRES_SYSCTL_EQ("kern.thread_groups_supported", 1))
196*43a90889SApple OSS Distributions {
197*43a90889SApple OSS Distributions 	T_LOG("uid: %d", getuid());
198*43a90889SApple OSS Distributions 	skip_if_unsupported();
199*43a90889SApple OSS Distributions 
200*43a90889SApple OSS Distributions 	check_game_mode(false);
201*43a90889SApple OSS Distributions 	check_game_mode_count(0);
202*43a90889SApple OSS Distributions 
203*43a90889SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_ON),
204*43a90889SApple OSS Distributions 	    "setpriority(PRIO_DARWIN_GAME_MODE_ON)");
205*43a90889SApple OSS Distributions 
206*43a90889SApple OSS Distributions 	check_game_mode(true);
207*43a90889SApple OSS Distributions 	check_game_mode_count(1);
208*43a90889SApple OSS Distributions 
209*43a90889SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_OFF),
210*43a90889SApple OSS Distributions 	    "setpriority(PRIO_DARWIN_GAME_MODE_OFF)");
211*43a90889SApple OSS Distributions 
212*43a90889SApple OSS Distributions 	check_game_mode(false);
213*43a90889SApple OSS Distributions 	check_game_mode_count(0);
214*43a90889SApple OSS Distributions }
215*43a90889SApple OSS Distributions 
216*43a90889SApple OSS Distributions T_DECL(game_mode_child_exit, "game mode bit should disappear when child exits",
217*43a90889SApple OSS Distributions     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1), T_META_REQUIRES_SYSCTL_EQ("kern.thread_groups_supported", 1))
218*43a90889SApple OSS Distributions {
219*43a90889SApple OSS Distributions 	T_LOG("uid: %d", getuid());
220*43a90889SApple OSS Distributions 	skip_if_unsupported();
221*43a90889SApple OSS Distributions 
222*43a90889SApple OSS Distributions 	check_game_mode(false);
223*43a90889SApple OSS Distributions 	check_game_mode_count(0);
224*43a90889SApple OSS Distributions 
225*43a90889SApple OSS Distributions 	T_LOG("Spawning child");
226*43a90889SApple OSS Distributions 
227*43a90889SApple OSS Distributions 	pid_t child_pid = fork();
228*43a90889SApple OSS Distributions 
229*43a90889SApple OSS Distributions 	if (child_pid == 0) {
230*43a90889SApple OSS Distributions 		/* child process */
231*43a90889SApple OSS Distributions 
232*43a90889SApple OSS Distributions 		check_game_mode(false);
233*43a90889SApple OSS Distributions 		check_game_mode_count(0);
234*43a90889SApple OSS Distributions 
235*43a90889SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_ON),
236*43a90889SApple OSS Distributions 		    "setpriority(PRIO_DARWIN_GAME_MODE_ON)");
237*43a90889SApple OSS Distributions 
238*43a90889SApple OSS Distributions 		check_game_mode(true);
239*43a90889SApple OSS Distributions 		check_game_mode_count(1);
240*43a90889SApple OSS Distributions 
241*43a90889SApple OSS Distributions 		T_LOG("Exit pid %d with the game mode bit on", getpid());
242*43a90889SApple OSS Distributions 
243*43a90889SApple OSS Distributions 		exit(0);
244*43a90889SApple OSS Distributions 	} else {
245*43a90889SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(child_pid, "fork, pid %d", child_pid);
246*43a90889SApple OSS Distributions 
247*43a90889SApple OSS Distributions 		/* wait for child process to exit */
248*43a90889SApple OSS Distributions 		int exit_status = 0, signum = 0;
249*43a90889SApple OSS Distributions 
250*43a90889SApple OSS Distributions 		T_ASSERT_TRUE(dt_waitpid(child_pid, &exit_status, &signum, 5),
251*43a90889SApple OSS Distributions 		    "wait for child (%d) complete", child_pid);
252*43a90889SApple OSS Distributions 
253*43a90889SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(exit_status, 0, "dt_waitpid: exit_status");
254*43a90889SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(signum, 0, "dt_waitpid: signum");
255*43a90889SApple OSS Distributions 	}
256*43a90889SApple OSS Distributions 
257*43a90889SApple OSS Distributions 	check_game_mode(false);
258*43a90889SApple OSS Distributions 	check_game_mode_count(0);
259*43a90889SApple OSS Distributions }
260*43a90889SApple OSS Distributions 
261*43a90889SApple OSS Distributions 
262*43a90889SApple OSS Distributions T_DECL(game_mode_double_set_and_child_exit, "game mode bit on parent should stay when game mode child exits",
263*43a90889SApple OSS Distributions     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1), T_META_REQUIRES_SYSCTL_EQ("kern.thread_groups_supported", 1))
264*43a90889SApple OSS Distributions {
265*43a90889SApple OSS Distributions 	T_LOG("uid: %d", getuid());
266*43a90889SApple OSS Distributions 	skip_if_unsupported();
267*43a90889SApple OSS Distributions 
268*43a90889SApple OSS Distributions 	check_game_mode(false);
269*43a90889SApple OSS Distributions 	check_game_mode_count(0);
270*43a90889SApple OSS Distributions 
271*43a90889SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_ON),
272*43a90889SApple OSS Distributions 	    "setpriority(PRIO_DARWIN_GAME_MODE_ON)");
273*43a90889SApple OSS Distributions 
274*43a90889SApple OSS Distributions 	check_game_mode(true);
275*43a90889SApple OSS Distributions 	check_game_mode_count(1);
276*43a90889SApple OSS Distributions 
277*43a90889SApple OSS Distributions 	pid_t child_pid = fork();
278*43a90889SApple OSS Distributions 
279*43a90889SApple OSS Distributions 	if (child_pid == 0) {
280*43a90889SApple OSS Distributions 		/* child process */
281*43a90889SApple OSS Distributions 
282*43a90889SApple OSS Distributions 		check_game_mode(false);
283*43a90889SApple OSS Distributions 		check_game_mode_count(1);
284*43a90889SApple OSS Distributions 
285*43a90889SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_ON),
286*43a90889SApple OSS Distributions 		    "setpriority(PRIO_DARWIN_GAME_MODE_ON)");
287*43a90889SApple OSS Distributions 
288*43a90889SApple OSS Distributions 		check_game_mode(true);
289*43a90889SApple OSS Distributions 		check_game_mode_count(2);
290*43a90889SApple OSS Distributions 
291*43a90889SApple OSS Distributions 		T_LOG("Exit pid %d with the game mode bit on", getpid());
292*43a90889SApple OSS Distributions 		exit(0);
293*43a90889SApple OSS Distributions 	} else {
294*43a90889SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(child_pid, "fork, pid %d", child_pid);
295*43a90889SApple OSS Distributions 
296*43a90889SApple OSS Distributions 		/* wait for child process to exit */
297*43a90889SApple OSS Distributions 		int exit_status = 0, signum = 0;
298*43a90889SApple OSS Distributions 
299*43a90889SApple OSS Distributions 		T_ASSERT_TRUE(dt_waitpid(child_pid, &exit_status, &signum, 5),
300*43a90889SApple OSS Distributions 		    "wait for child (%d) complete", child_pid);
301*43a90889SApple OSS Distributions 
302*43a90889SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(exit_status, 0, "dt_waitpid: exit_status");
303*43a90889SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(signum, 0, "dt_waitpid: signum");
304*43a90889SApple OSS Distributions 	}
305*43a90889SApple OSS Distributions 
306*43a90889SApple OSS Distributions 	check_game_mode(true);
307*43a90889SApple OSS Distributions 	check_game_mode_count(1);
308*43a90889SApple OSS Distributions 
309*43a90889SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_OFF),
310*43a90889SApple OSS Distributions 	    "setpriority(PRIO_DARWIN_GAME_MODE_OFF)");
311*43a90889SApple OSS Distributions 
312*43a90889SApple OSS Distributions 	check_game_mode(false);
313*43a90889SApple OSS Distributions 	check_game_mode_count(0);
314*43a90889SApple OSS Distributions }
315*43a90889SApple OSS Distributions 
316*43a90889SApple OSS Distributions T_DECL(game_mode_double_set_and_child_unset, "game mode bit on parent should stay when game mode child unsets",
317*43a90889SApple OSS Distributions     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1), T_META_REQUIRES_SYSCTL_EQ("kern.thread_groups_supported", 1))
318*43a90889SApple OSS Distributions {
319*43a90889SApple OSS Distributions 	T_LOG("uid: %d", getuid());
320*43a90889SApple OSS Distributions 	skip_if_unsupported();
321*43a90889SApple OSS Distributions 
322*43a90889SApple OSS Distributions 	check_game_mode(false);
323*43a90889SApple OSS Distributions 	check_game_mode_count(0);
324*43a90889SApple OSS Distributions 
325*43a90889SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_ON),
326*43a90889SApple OSS Distributions 	    "setpriority(PRIO_DARWIN_GAME_MODE_ON)");
327*43a90889SApple OSS Distributions 
328*43a90889SApple OSS Distributions 	check_game_mode(true);
329*43a90889SApple OSS Distributions 	check_game_mode_count(1);
330*43a90889SApple OSS Distributions 
331*43a90889SApple OSS Distributions 	pid_t child_pid = fork();
332*43a90889SApple OSS Distributions 
333*43a90889SApple OSS Distributions 	if (child_pid == 0) {
334*43a90889SApple OSS Distributions 		/* child process */
335*43a90889SApple OSS Distributions 
336*43a90889SApple OSS Distributions 		check_game_mode(false);
337*43a90889SApple OSS Distributions 		check_game_mode_count(1);
338*43a90889SApple OSS Distributions 
339*43a90889SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_ON),
340*43a90889SApple OSS Distributions 		    "setpriority(PRIO_DARWIN_GAME_MODE_ON)");
341*43a90889SApple OSS Distributions 
342*43a90889SApple OSS Distributions 		check_game_mode(true);
343*43a90889SApple OSS Distributions 		check_game_mode_count(2);
344*43a90889SApple OSS Distributions 
345*43a90889SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_OFF),
346*43a90889SApple OSS Distributions 		    "setpriority(PRIO_DARWIN_GAME_MODE_OFF)");
347*43a90889SApple OSS Distributions 
348*43a90889SApple OSS Distributions 		check_game_mode(false);
349*43a90889SApple OSS Distributions 		check_game_mode_count(1);
350*43a90889SApple OSS Distributions 
351*43a90889SApple OSS Distributions 		T_LOG("Exit pid %d with the game mode bit off", getpid());
352*43a90889SApple OSS Distributions 		exit(0);
353*43a90889SApple OSS Distributions 	} else {
354*43a90889SApple OSS Distributions 		T_ASSERT_POSIX_SUCCESS(child_pid, "fork, pid %d", child_pid);
355*43a90889SApple OSS Distributions 
356*43a90889SApple OSS Distributions 		/* wait for child process to exit */
357*43a90889SApple OSS Distributions 		int exit_status = 0, signum = 0;
358*43a90889SApple OSS Distributions 
359*43a90889SApple OSS Distributions 		T_ASSERT_TRUE(dt_waitpid(child_pid, &exit_status, &signum, 5),
360*43a90889SApple OSS Distributions 		    "wait for child (%d) complete", child_pid);
361*43a90889SApple OSS Distributions 
362*43a90889SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(exit_status, 0, "dt_waitpid: exit_status");
363*43a90889SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(signum, 0, "dt_waitpid: signum");
364*43a90889SApple OSS Distributions 	}
365*43a90889SApple OSS Distributions 
366*43a90889SApple OSS Distributions 	check_game_mode(true);
367*43a90889SApple OSS Distributions 	check_game_mode_count(1);
368*43a90889SApple OSS Distributions 
369*43a90889SApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(setpriority(PRIO_DARWIN_GAME_MODE, 0, PRIO_DARWIN_GAME_MODE_OFF),
370*43a90889SApple OSS Distributions 	    "setpriority(PRIO_DARWIN_GAME_MODE_OFF)");
371*43a90889SApple OSS Distributions 
372*43a90889SApple OSS Distributions 	check_game_mode(false);
373*43a90889SApple OSS Distributions 	check_game_mode_count(0);
374*43a90889SApple OSS Distributions }
375