xref: /xnu-10063.121.3/tests/sched_overloaded_runqueue.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
1*2c2f96dcSApple OSS Distributions // Copyright (c) 2023 Apple Inc.  All rights reserved.
2*2c2f96dcSApple OSS Distributions 
3*2c2f96dcSApple OSS Distributions #include <unistd.h>
4*2c2f96dcSApple OSS Distributions #include <stdlib.h>
5*2c2f96dcSApple OSS Distributions #include <stdio.h>
6*2c2f96dcSApple OSS Distributions #include <pthread.h>
7*2c2f96dcSApple OSS Distributions #include <string.h>
8*2c2f96dcSApple OSS Distributions #include <mach/mach.h>
9*2c2f96dcSApple OSS Distributions #include <mach/mach_time.h>
10*2c2f96dcSApple OSS Distributions #include <sys/stat.h>
11*2c2f96dcSApple OSS Distributions #include <sys/sysctl.h>
12*2c2f96dcSApple OSS Distributions #include <stdatomic.h>
13*2c2f96dcSApple OSS Distributions #include <sys/work_interval.h>
14*2c2f96dcSApple OSS Distributions #include <ktrace.h>
15*2c2f96dcSApple OSS Distributions #include <sys/kdebug.h>
16*2c2f96dcSApple OSS Distributions 
17*2c2f96dcSApple OSS Distributions #include <darwintest.h>
18*2c2f96dcSApple OSS Distributions #include <darwintest_utils.h>
19*2c2f96dcSApple OSS Distributions #include "test_utils.h"
20*2c2f96dcSApple OSS Distributions 
21*2c2f96dcSApple OSS Distributions T_GLOBAL_META(T_META_NAMESPACE("xnu.scheduler"),
22*2c2f96dcSApple OSS Distributions     T_META_RADAR_COMPONENT_NAME("xnu"),
23*2c2f96dcSApple OSS Distributions     T_META_RADAR_COMPONENT_VERSION("scheduler"));
24*2c2f96dcSApple OSS Distributions 
25*2c2f96dcSApple OSS Distributions static mach_timebase_info_data_t timebase_info;
26*2c2f96dcSApple OSS Distributions 
27*2c2f96dcSApple OSS Distributions static uint64_t
nanos_to_abs(uint64_t nanos)28*2c2f96dcSApple OSS Distributions nanos_to_abs(uint64_t nanos)
29*2c2f96dcSApple OSS Distributions {
30*2c2f96dcSApple OSS Distributions 	mach_timebase_info(&timebase_info);
31*2c2f96dcSApple OSS Distributions 	return nanos * timebase_info.denom / timebase_info.numer;
32*2c2f96dcSApple OSS Distributions }
33*2c2f96dcSApple OSS Distributions 
34*2c2f96dcSApple OSS Distributions static uint64_t
abs_to_nanos(uint64_t abs)35*2c2f96dcSApple OSS Distributions abs_to_nanos(uint64_t abs)
36*2c2f96dcSApple OSS Distributions {
37*2c2f96dcSApple OSS Distributions 	mach_timebase_info(&timebase_info);
38*2c2f96dcSApple OSS Distributions 	return abs * timebase_info.numer / timebase_info.denom;
39*2c2f96dcSApple OSS Distributions }
40*2c2f96dcSApple OSS Distributions 
41*2c2f96dcSApple OSS Distributions static int BACKGROUND_PRI;
42*2c2f96dcSApple OSS Distributions static int NUM_THREADS;
43*2c2f96dcSApple OSS Distributions static uint64_t SLEEP_SECONDS;
44*2c2f96dcSApple OSS Distributions static uint64_t INTERRUPT_DISABLE_TIMEOUT_NS;
45*2c2f96dcSApple OSS Distributions 
46*2c2f96dcSApple OSS Distributions static uint64_t start_timestamp = 0ULL;
47*2c2f96dcSApple OSS Distributions static volatile int sum = 0; // Keeps the spin-loop below from compiling-out
48*2c2f96dcSApple OSS Distributions 
49*2c2f96dcSApple OSS Distributions static void *
make_tg_and_spin(__unused void * arg)50*2c2f96dcSApple OSS Distributions make_tg_and_spin(__unused void *arg)
51*2c2f96dcSApple OSS Distributions {
52*2c2f96dcSApple OSS Distributions 	int ret;
53*2c2f96dcSApple OSS Distributions 	assert(SLEEP_SECONDS > 2);
54*2c2f96dcSApple OSS Distributions 
55*2c2f96dcSApple OSS Distributions 	/* Create and join a new thread group (TG) */
56*2c2f96dcSApple OSS Distributions 	work_interval_t wi_handle;
57*2c2f96dcSApple OSS Distributions 	ret = work_interval_create(&wi_handle, WORK_INTERVAL_FLAG_GROUP);
58*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, 0, "work_interval_create");
59*2c2f96dcSApple OSS Distributions 
60*2c2f96dcSApple OSS Distributions 	/* Allow other threads a chance to get on-core and create/join their own TGs */
61*2c2f96dcSApple OSS Distributions 	uint64_t yield_deadline = start_timestamp + nanos_to_abs(1 * NSEC_PER_SEC);
62*2c2f96dcSApple OSS Distributions 	while (mach_absolute_time() < yield_deadline) {
63*2c2f96dcSApple OSS Distributions 		sched_yield();
64*2c2f96dcSApple OSS Distributions 	}
65*2c2f96dcSApple OSS Distributions 
66*2c2f96dcSApple OSS Distributions 	/*
67*2c2f96dcSApple OSS Distributions 	 * Remain runnable long enough for the sched_maintenance_thread to scan the
68*2c2f96dcSApple OSS Distributions 	 * many created TGs all at the same time in one scheduler tick.
69*2c2f96dcSApple OSS Distributions 	 */
70*2c2f96dcSApple OSS Distributions 	uint64_t spin_deadline = start_timestamp + nanos_to_abs((SLEEP_SECONDS - 2) * NSEC_PER_SEC);
71*2c2f96dcSApple OSS Distributions 	while (mach_absolute_time() < spin_deadline) {
72*2c2f96dcSApple OSS Distributions 		sum++;
73*2c2f96dcSApple OSS Distributions 	}
74*2c2f96dcSApple OSS Distributions 
75*2c2f96dcSApple OSS Distributions 	/*
76*2c2f96dcSApple OSS Distributions 	 * Terminate with about a second to spare of SLEEP_SECONDS, so that we have
77*2c2f96dcSApple OSS Distributions 	 * time to bring down the number of runnable thread groups before the test
78*2c2f96dcSApple OSS Distributions 	 * case reenables the previous kern.interrupt_masked_debug_mode value.
79*2c2f96dcSApple OSS Distributions 	 * Otherwise, a system failing this test could panic.
80*2c2f96dcSApple OSS Distributions 	 */
81*2c2f96dcSApple OSS Distributions 	return NULL;
82*2c2f96dcSApple OSS Distributions }
83*2c2f96dcSApple OSS Distributions 
84*2c2f96dcSApple OSS Distributions static void
start_threads(pthread_t * threads,void * (* start_routine)(void *),int priority,int num_threads)85*2c2f96dcSApple OSS Distributions start_threads(pthread_t *threads, void *(*start_routine)(void *), int priority, int num_threads)
86*2c2f96dcSApple OSS Distributions {
87*2c2f96dcSApple OSS Distributions 	int rv;
88*2c2f96dcSApple OSS Distributions 	pthread_attr_t attr;
89*2c2f96dcSApple OSS Distributions 
90*2c2f96dcSApple OSS Distributions 	rv = pthread_attr_init(&attr);
91*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_attr_init");
92*2c2f96dcSApple OSS Distributions 
93*2c2f96dcSApple OSS Distributions 	for (int i = 0; i < num_threads; i++) {
94*2c2f96dcSApple OSS Distributions 		struct sched_param param = { .sched_priority = priority };
95*2c2f96dcSApple OSS Distributions 
96*2c2f96dcSApple OSS Distributions 		rv = pthread_attr_setschedparam(&attr, &param);
97*2c2f96dcSApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_attr_setschedparam");
98*2c2f96dcSApple OSS Distributions 
99*2c2f96dcSApple OSS Distributions 		rv = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
100*2c2f96dcSApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_attr_setdetachstate");
101*2c2f96dcSApple OSS Distributions 
102*2c2f96dcSApple OSS Distributions 		/* Make the thread stacks smaller, so pthread will let us make more */
103*2c2f96dcSApple OSS Distributions 		rv = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
104*2c2f96dcSApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_attr_setstacksize");
105*2c2f96dcSApple OSS Distributions 
106*2c2f96dcSApple OSS Distributions 		rv = pthread_create(&threads[i], &attr, start_routine, NULL);
107*2c2f96dcSApple OSS Distributions 		T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_create");
108*2c2f96dcSApple OSS Distributions 	}
109*2c2f96dcSApple OSS Distributions 
110*2c2f96dcSApple OSS Distributions 	rv = pthread_attr_destroy(&attr);
111*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(rv, "pthread_attr_destroy");
112*2c2f96dcSApple OSS Distributions }
113*2c2f96dcSApple OSS Distributions 
114*2c2f96dcSApple OSS Distributions static uint64_t old_preemption_debug_mode = 0;
115*2c2f96dcSApple OSS Distributions static size_t old_preemption_debug_mode_size = sizeof(old_preemption_debug_mode);
116*2c2f96dcSApple OSS Distributions 
117*2c2f96dcSApple OSS Distributions static void
restore_preemption_disable_debug_mode(void)118*2c2f96dcSApple OSS Distributions restore_preemption_disable_debug_mode(void)
119*2c2f96dcSApple OSS Distributions {
120*2c2f96dcSApple OSS Distributions 	int ret = sysctlbyname("kern.sched_preemption_disable_debug_mode", NULL, NULL,
121*2c2f96dcSApple OSS Distributions 	    &old_preemption_debug_mode, old_preemption_debug_mode_size);
122*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "kern.sched_preemption_disable_debug_mode");
123*2c2f96dcSApple OSS Distributions 	T_LOG("kern.sched_preemption_disable_debug_mode restored to previous value: %llu", old_preemption_debug_mode);
124*2c2f96dcSApple OSS Distributions }
125*2c2f96dcSApple OSS Distributions 
126*2c2f96dcSApple OSS Distributions static uint64_t old_interrupt_debug_mode = 0;
127*2c2f96dcSApple OSS Distributions static size_t old_interrupt_debug_mode_size = sizeof(old_interrupt_debug_mode);
128*2c2f96dcSApple OSS Distributions 
129*2c2f96dcSApple OSS Distributions static void
restore_interrupt_disable_debug_mode(void)130*2c2f96dcSApple OSS Distributions restore_interrupt_disable_debug_mode(void)
131*2c2f96dcSApple OSS Distributions {
132*2c2f96dcSApple OSS Distributions 	int ret = sysctlbyname("kern.interrupt_masked_debug_mode", NULL, NULL,
133*2c2f96dcSApple OSS Distributions 	    &old_interrupt_debug_mode, old_interrupt_debug_mode_size);
134*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "kern.interrupt_masked_debug_mode");
135*2c2f96dcSApple OSS Distributions 	T_LOG("kern.interrupt_masked_debug_mode restored to previous value: %llu", old_interrupt_debug_mode);
136*2c2f96dcSApple OSS Distributions }
137*2c2f96dcSApple OSS Distributions 
138*2c2f96dcSApple OSS Distributions static uint64_t old_interrupt_disable_timeout = 0;
139*2c2f96dcSApple OSS Distributions static size_t old_interrupt_disable_timeout_size = sizeof(old_interrupt_disable_timeout);
140*2c2f96dcSApple OSS Distributions 
141*2c2f96dcSApple OSS Distributions static void
restore_interrupt_disable_timeout(void)142*2c2f96dcSApple OSS Distributions restore_interrupt_disable_timeout(void)
143*2c2f96dcSApple OSS Distributions {
144*2c2f96dcSApple OSS Distributions 	int ret = sysctlbyname("kern.interrupt_masked_threshold_mt", NULL, NULL,
145*2c2f96dcSApple OSS Distributions 	    &old_interrupt_disable_timeout, old_interrupt_disable_timeout_size);
146*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "kern.interrupt_masked_threshold_mt");
147*2c2f96dcSApple OSS Distributions 	T_LOG("kern.interrupt_masked_threshold_mt restored to previous value: %llu", old_interrupt_disable_timeout);
148*2c2f96dcSApple OSS Distributions }
149*2c2f96dcSApple OSS Distributions 
150*2c2f96dcSApple OSS Distributions static const char *ktrace_file_short_name = "overload_runqueue_with_thread_groups.ktrace";
151*2c2f96dcSApple OSS Distributions 
152*2c2f96dcSApple OSS Distributions static void
save_collected_ktrace(char * trace_path)153*2c2f96dcSApple OSS Distributions save_collected_ktrace(char *trace_path)
154*2c2f96dcSApple OSS Distributions {
155*2c2f96dcSApple OSS Distributions 	int ret;
156*2c2f96dcSApple OSS Distributions 
157*2c2f96dcSApple OSS Distributions 	T_LOG("ktrace file saved at \"%s\"", trace_path);
158*2c2f96dcSApple OSS Distributions 	ret = chmod(trace_path, 0777);
159*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "chmod");
160*2c2f96dcSApple OSS Distributions 
161*2c2f96dcSApple OSS Distributions 	char compressed_path[MAXPATHLEN];
162*2c2f96dcSApple OSS Distributions 	snprintf(compressed_path, MAXPATHLEN, "%s.tar.gz", ktrace_file_short_name);
163*2c2f96dcSApple OSS Distributions 	ret = dt_resultfile(compressed_path, sizeof(compressed_path));
164*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "dt_resultfile marking \"%s\" for collection", compressed_path);
165*2c2f96dcSApple OSS Distributions 	T_LOG("\"%s\" marked for upload", compressed_path);
166*2c2f96dcSApple OSS Distributions 
167*2c2f96dcSApple OSS Distributions 	char *tar_args[] = {"/usr/bin/tar", "-czvf", compressed_path, trace_path, NULL};
168*2c2f96dcSApple OSS Distributions 	pid_t tar_pid = dt_launch_tool_pipe(tar_args, false, NULL,
169*2c2f96dcSApple OSS Distributions 	    ^bool (__unused char *data, __unused size_t data_size, __unused dt_pipe_data_handler_context_t *context) {
170*2c2f96dcSApple OSS Distributions 		return true;
171*2c2f96dcSApple OSS Distributions 	},
172*2c2f96dcSApple OSS Distributions 	    ^bool (char *data, __unused size_t data_size, __unused dt_pipe_data_handler_context_t *context) {
173*2c2f96dcSApple OSS Distributions 		T_LOG("[tar] Error msg: %s", data);
174*2c2f96dcSApple OSS Distributions 		return true;
175*2c2f96dcSApple OSS Distributions 	},
176*2c2f96dcSApple OSS Distributions 	    BUFFER_PATTERN_LINE, NULL);
177*2c2f96dcSApple OSS Distributions 
178*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_TRUE(tar_pid, "[tar] pid %d", tar_pid);
179*2c2f96dcSApple OSS Distributions 	ret = dt_waitpid(tar_pid, NULL, NULL, 0);
180*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "dt_waitpid");
181*2c2f96dcSApple OSS Distributions 
182*2c2f96dcSApple OSS Distributions 	ret = chmod(compressed_path, 0777);
183*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "chmod");
184*2c2f96dcSApple OSS Distributions }
185*2c2f96dcSApple OSS Distributions 
186*2c2f96dcSApple OSS Distributions /*
187*2c2f96dcSApple OSS Distributions  * Parse the recorded ktrace file to see if we crossed the set interrupt-disabled
188*2c2f96dcSApple OSS Distributions  * timeout and thus failed the test.
189*2c2f96dcSApple OSS Distributions  */
190*2c2f96dcSApple OSS Distributions static void
search_for_interrupt_disable_timeout_tracepoint(char * trace_path)191*2c2f96dcSApple OSS Distributions search_for_interrupt_disable_timeout_tracepoint(char *trace_path)
192*2c2f96dcSApple OSS Distributions {
193*2c2f96dcSApple OSS Distributions 	__block int ret;
194*2c2f96dcSApple OSS Distributions 	ktrace_session_t read_session = ktrace_session_create();
195*2c2f96dcSApple OSS Distributions 	ret = ktrace_set_file(read_session, trace_path);
196*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_set_file");
197*2c2f96dcSApple OSS Distributions 	__block const char *offending_thread = NULL;
198*2c2f96dcSApple OSS Distributions 
199*2c2f96dcSApple OSS Distributions 	ktrace_events_single(read_session, MACHDBG_CODE(DBG_MACH_SCHED, MACH_INT_MASKED_EXPIRED), ^(ktrace_event_t e) {
200*2c2f96dcSApple OSS Distributions 		if (offending_thread == NULL) {
201*2c2f96dcSApple OSS Distributions 		        T_LOG("Interrupts were held disabled for %llu ns, crossing the %llu ns threshold:", abs_to_nanos(e->arg1), INTERRUPT_DISABLE_TIMEOUT_NS);
202*2c2f96dcSApple OSS Distributions 		        ret = ktrace_print_trace_point(stdout, read_session, e, KTP_KIND_CSV,
203*2c2f96dcSApple OSS Distributions 		        KTP_FLAG_WALLTIME | KTP_FLAG_THREADNAME | KTP_FLAG_PID | KTP_FLAG_EVENTNAME | KTP_FLAG_EXECNAME);
204*2c2f96dcSApple OSS Distributions 		        T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "ktrace_print_trace_point output");
205*2c2f96dcSApple OSS Distributions 		        printf("\n"); // Flush output from ktrace_print_trace_point
206*2c2f96dcSApple OSS Distributions 		        offending_thread = ktrace_get_name_for_thread(read_session, e->threadid);
207*2c2f96dcSApple OSS Distributions 		        ktrace_end(read_session, 0);
208*2c2f96dcSApple OSS Distributions 		}
209*2c2f96dcSApple OSS Distributions 	});
210*2c2f96dcSApple OSS Distributions 
211*2c2f96dcSApple OSS Distributions 	ktrace_set_completion_handler(read_session, ^{
212*2c2f96dcSApple OSS Distributions 		if (offending_thread == NULL) {
213*2c2f96dcSApple OSS Distributions 		        T_PASS("Scheduler survived %d simulatenously runnable thread groups without disabling interrupts for more than %llu ns!", NUM_THREADS, INTERRUPT_DISABLE_TIMEOUT_NS);
214*2c2f96dcSApple OSS Distributions 		} else {
215*2c2f96dcSApple OSS Distributions 		        save_collected_ktrace(trace_path);
216*2c2f96dcSApple OSS Distributions 		        T_FAIL("Interrupts held disabled for more than %llu ns by thread \"%s\"", INTERRUPT_DISABLE_TIMEOUT_NS, offending_thread);
217*2c2f96dcSApple OSS Distributions 		}
218*2c2f96dcSApple OSS Distributions 		T_END;
219*2c2f96dcSApple OSS Distributions 	});
220*2c2f96dcSApple OSS Distributions 
221*2c2f96dcSApple OSS Distributions 	ret = ktrace_start(read_session, dispatch_get_main_queue());
222*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_start");
223*2c2f96dcSApple OSS Distributions }
224*2c2f96dcSApple OSS Distributions 
225*2c2f96dcSApple OSS Distributions T_DECL(overload_runqueue_with_thread_groups,
226*2c2f96dcSApple OSS Distributions     "Overload the runqueue with distinct thread groups to verify that the scheduler"
227*2c2f96dcSApple OSS Distributions     "does not trip an interrupts-disabled timeout whenever it scans the runqueue",
228*2c2f96dcSApple OSS Distributions     T_META_ASROOT(true), XNU_T_META_SOC_SPECIFIC, T_META_ENABLED(TARGET_OS_IOS))
229*2c2f96dcSApple OSS Distributions {
230*2c2f96dcSApple OSS Distributions 	BACKGROUND_PRI = 4;
231*2c2f96dcSApple OSS Distributions 	NUM_THREADS = 1000;
232*2c2f96dcSApple OSS Distributions 	SLEEP_SECONDS = 20;
233*2c2f96dcSApple OSS Distributions 	/* Matches DEFAULT_INTERRUPT_MASKED_TIMEOUT value in XNU */
234*2c2f96dcSApple OSS Distributions 	INTERRUPT_DISABLE_TIMEOUT_NS = 500 * NSEC_PER_USEC; // 500 microseconds
235*2c2f96dcSApple OSS Distributions 
236*2c2f96dcSApple OSS Distributions 	__block int ret;
237*2c2f96dcSApple OSS Distributions 
238*2c2f96dcSApple OSS Distributions 	/* Configure interrupts-disabled timeout to drop a ktracepoint */
239*2c2f96dcSApple OSS Distributions 	uint64_t emit_tracepoint_mode = 1;
240*2c2f96dcSApple OSS Distributions 	ret = sysctlbyname("kern.interrupt_masked_debug_mode",
241*2c2f96dcSApple OSS Distributions 	    &old_interrupt_debug_mode, &old_interrupt_debug_mode_size,
242*2c2f96dcSApple OSS Distributions 	    &emit_tracepoint_mode, sizeof(emit_tracepoint_mode));
243*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "kern.interrupt_masked_debug_mode");
244*2c2f96dcSApple OSS Distributions 	T_ATEND(restore_interrupt_disable_debug_mode);
245*2c2f96dcSApple OSS Distributions 	/* Configure the preemption-disabled debug mode as well, to avoid panicking if the test fails */
246*2c2f96dcSApple OSS Distributions 	ret = sysctlbyname("kern.sched_preemption_disable_debug_mode",
247*2c2f96dcSApple OSS Distributions 	    &old_preemption_debug_mode, &old_preemption_debug_mode_size,
248*2c2f96dcSApple OSS Distributions 	    &emit_tracepoint_mode, sizeof(emit_tracepoint_mode));
249*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "kern.sched_preemption_disable_debug_mode");
250*2c2f96dcSApple OSS Distributions 	T_ATEND(restore_preemption_disable_debug_mode);
251*2c2f96dcSApple OSS Distributions 
252*2c2f96dcSApple OSS Distributions 	/* Set interrupts-disabled timeout threshold */
253*2c2f96dcSApple OSS Distributions 	uint64_t disable_timeout = nanos_to_abs(INTERRUPT_DISABLE_TIMEOUT_NS);
254*2c2f96dcSApple OSS Distributions 	ret = sysctlbyname("kern.interrupt_masked_threshold_mt",
255*2c2f96dcSApple OSS Distributions 	    &old_interrupt_disable_timeout, &old_interrupt_disable_timeout_size,
256*2c2f96dcSApple OSS Distributions 	    &disable_timeout, sizeof(disable_timeout));
257*2c2f96dcSApple OSS Distributions 	T_QUIET; T_WITH_ERRNO; T_ASSERT_POSIX_ZERO(ret, "kern.interrupt_masked_threshold_mt");
258*2c2f96dcSApple OSS Distributions 	T_ATEND(restore_interrupt_disable_timeout);
259*2c2f96dcSApple OSS Distributions 
260*2c2f96dcSApple OSS Distributions 	/* Use ktrace to observe if the interrupt-disable timeout drops a tracepoint */
261*2c2f96dcSApple OSS Distributions 	ktrace_session_t session = ktrace_session_create();
262*2c2f96dcSApple OSS Distributions 	T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(session, "ktrace_session_create");
263*2c2f96dcSApple OSS Distributions 	char filepath_arr[MAXPATHLEN] = "";
264*2c2f96dcSApple OSS Distributions 	const char *tmp_dir = dt_tmpdir();
265*2c2f96dcSApple OSS Distributions 	strlcpy(filepath_arr, tmp_dir, sizeof(filepath_arr));
266*2c2f96dcSApple OSS Distributions 	strlcat(filepath_arr, "/", sizeof(filepath_arr));
267*2c2f96dcSApple OSS Distributions 	strlcat(filepath_arr, ktrace_file_short_name, sizeof(filepath_arr));
268*2c2f96dcSApple OSS Distributions 	ret = remove(filepath_arr);
269*2c2f96dcSApple OSS Distributions 	T_QUIET; T_WITH_ERRNO; T_ASSERT_TRUE((ret == 0) || (errno == ENOENT), "remove");
270*2c2f96dcSApple OSS Distributions 	char *filepath = filepath_arr;
271*2c2f96dcSApple OSS Distributions 	ret = ktrace_events_filter(session, "C0x01", ^(__unused ktrace_event_t event){}); // records scheduler tracepoints
272*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_events_filter");
273*2c2f96dcSApple OSS Distributions 	ktrace_set_completion_handler(session, ^{
274*2c2f96dcSApple OSS Distributions 		search_for_interrupt_disable_timeout_tracepoint(filepath);
275*2c2f96dcSApple OSS Distributions 	});
276*2c2f96dcSApple OSS Distributions 	ret = ktrace_start_writing_path(session, filepath, 0);
277*2c2f96dcSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_ZERO(ret, "ktrace_start_writing_path");
278*2c2f96dcSApple OSS Distributions 
279*2c2f96dcSApple OSS Distributions 	/* Spin up lots of threads, each creating and joining its own thread group */
280*2c2f96dcSApple OSS Distributions 	T_LOG("Creating %d threads at pri %d, each with a unique thread group", NUM_THREADS, BACKGROUND_PRI);
281*2c2f96dcSApple OSS Distributions 	start_timestamp = mach_absolute_time();
282*2c2f96dcSApple OSS Distributions 	pthread_t *bg_threads = malloc(sizeof(pthread_t) * (size_t)NUM_THREADS);
283*2c2f96dcSApple OSS Distributions 	start_threads(bg_threads, make_tg_and_spin, BACKGROUND_PRI, NUM_THREADS);
284*2c2f96dcSApple OSS Distributions 
285*2c2f96dcSApple OSS Distributions 	T_LOG("Waiting %llu seconds to see if the scheduler can handle it...", SLEEP_SECONDS);
286*2c2f96dcSApple OSS Distributions 	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(SLEEP_SECONDS * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
287*2c2f96dcSApple OSS Distributions 		ktrace_end(session, 0);
288*2c2f96dcSApple OSS Distributions 	});
289*2c2f96dcSApple OSS Distributions 	dispatch_main();
290*2c2f96dcSApple OSS Distributions }
291