1*5e3eaea3SApple OSS Distributions #include <darwintest.h>
2*5e3eaea3SApple OSS Distributions
3*5e3eaea3SApple OSS Distributions #include <assert.h>
4*5e3eaea3SApple OSS Distributions #include <mach/clock_types.h>
5*5e3eaea3SApple OSS Distributions #include <unistd.h>
6*5e3eaea3SApple OSS Distributions #include <stdlib.h>
7*5e3eaea3SApple OSS Distributions #include <stdio.h>
8*5e3eaea3SApple OSS Distributions #include <errno.h>
9*5e3eaea3SApple OSS Distributions #include <err.h>
10*5e3eaea3SApple OSS Distributions #include <sys/time.h>
11*5e3eaea3SApple OSS Distributions #include <mach/mach.h>
12*5e3eaea3SApple OSS Distributions #include <mach/mach_time.h>
13*5e3eaea3SApple OSS Distributions #include <pthread.h>
14*5e3eaea3SApple OSS Distributions #include <sys/sysctl.h>
15*5e3eaea3SApple OSS Distributions #include <sys/stat.h>
16*5e3eaea3SApple OSS Distributions #include <sys/mount.h>
17*5e3eaea3SApple OSS Distributions #include <stdbool.h>
18*5e3eaea3SApple OSS Distributions #include <signal.h>
19*5e3eaea3SApple OSS Distributions #include <sys/resource.h>
20*5e3eaea3SApple OSS Distributions #include <sys/resource_private.h>
21*5e3eaea3SApple OSS Distributions #include <os/atomic_private.h>
22*5e3eaea3SApple OSS Distributions #include <libproc.h>
23*5e3eaea3SApple OSS Distributions #include <TargetConditionals.h>
24*5e3eaea3SApple OSS Distributions
25*5e3eaea3SApple OSS Distributions #if __has_include(<mach/mach_time_private.h>)
26*5e3eaea3SApple OSS Distributions #include <mach/mach_time_private.h>
27*5e3eaea3SApple OSS Distributions #else
28*5e3eaea3SApple OSS Distributions kern_return_t mach_get_times(uint64_t* absolute_time,
29*5e3eaea3SApple OSS Distributions uint64_t* continuous_time,
30*5e3eaea3SApple OSS Distributions struct timespec *tp);
31*5e3eaea3SApple OSS Distributions #endif
32*5e3eaea3SApple OSS Distributions
33*5e3eaea3SApple OSS Distributions /*
34*5e3eaea3SApple OSS Distributions * This test program creates up to 8 worker threads performing
35*5e3eaea3SApple OSS Distributions * mixed workloads of system calls (which contribute to both
36*5e3eaea3SApple OSS Distributions * user and system time), as well as spins in userspace (which
37*5e3eaea3SApple OSS Distributions * only contribute to user time).
38*5e3eaea3SApple OSS Distributions *
39*5e3eaea3SApple OSS Distributions * setitimer(2) is used to program timers that fire signals
40*5e3eaea3SApple OSS Distributions * after various thresholds. The signal handler detects
41*5e3eaea3SApple OSS Distributions * which thread the signal was delivered on by matching the
42*5e3eaea3SApple OSS Distributions * stack pointer to ranges for each thread.
43*5e3eaea3SApple OSS Distributions *
44*5e3eaea3SApple OSS Distributions * After the test scenario is complete, the distribution of
45*5e3eaea3SApple OSS Distributions * threads which received interrupts is evaluated to match
46*5e3eaea3SApple OSS Distributions * expected heuristics.
47*5e3eaea3SApple OSS Distributions */
48*5e3eaea3SApple OSS Distributions
49*5e3eaea3SApple OSS Distributions T_GLOBAL_META(
50*5e3eaea3SApple OSS Distributions T_META_RUN_CONCURRENTLY(false),
51*5e3eaea3SApple OSS Distributions T_META_CHECK_LEAKS(false),
52*5e3eaea3SApple OSS Distributions T_META_ALL_VALID_ARCHS(true),
53*5e3eaea3SApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
54*5e3eaea3SApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("scheduler"),
55*5e3eaea3SApple OSS Distributions T_META_OWNER("chimene"),
56*5e3eaea3SApple OSS Distributions T_META_ENABLED(TARGET_OS_OSX)
57*5e3eaea3SApple OSS Distributions );
58*5e3eaea3SApple OSS Distributions
59*5e3eaea3SApple OSS Distributions static void *stat_thread(void *arg);
60*5e3eaea3SApple OSS Distributions static void *statfs_thread(void *arg);
61*5e3eaea3SApple OSS Distributions
62*5e3eaea3SApple OSS Distributions static void alrm_handler(int, struct __siginfo *, void *);
63*5e3eaea3SApple OSS Distributions
64*5e3eaea3SApple OSS Distributions static semaphore_t gMainWaitForWorkers;
65*5e3eaea3SApple OSS Distributions static semaphore_t gWorkersStart;
66*5e3eaea3SApple OSS Distributions
67*5e3eaea3SApple OSS Distributions static pthread_mutex_t gShouldExitMutex = PTHREAD_MUTEX_INITIALIZER;
68*5e3eaea3SApple OSS Distributions static pthread_cond_t gShouldExitCondition = PTHREAD_COND_INITIALIZER;
69*5e3eaea3SApple OSS Distributions
70*5e3eaea3SApple OSS Distributions static _Atomic bool gShouldExit = false;
71*5e3eaea3SApple OSS Distributions
72*5e3eaea3SApple OSS Distributions static const uint32_t max_threads = 9;
73*5e3eaea3SApple OSS Distributions
74*5e3eaea3SApple OSS Distributions static struct threadentry {
75*5e3eaea3SApple OSS Distributions pthread_t thread;
76*5e3eaea3SApple OSS Distributions uint64_t tid;
77*5e3eaea3SApple OSS Distributions void* stack_addr;
78*5e3eaea3SApple OSS Distributions size_t stack_size;
79*5e3eaea3SApple OSS Distributions bool expect_cpu_usage;
80*5e3eaea3SApple OSS Distributions uint32_t alrm_count;
81*5e3eaea3SApple OSS Distributions uint32_t vtalrm_count;
82*5e3eaea3SApple OSS Distributions uint32_t prof_count;
83*5e3eaea3SApple OSS Distributions uint32_t xcpu_count;
84*5e3eaea3SApple OSS Distributions struct thsc_time_cpi self_stats;
85*5e3eaea3SApple OSS Distributions } __attribute__((aligned(128))) gThreadList[max_threads];
86*5e3eaea3SApple OSS Distributions
87*5e3eaea3SApple OSS Distributions static uint32_t nworkers;
88*5e3eaea3SApple OSS Distributions static uint32_t nthreads;
89*5e3eaea3SApple OSS Distributions
90*5e3eaea3SApple OSS Distributions static double offcore_time_percent_threshold = 75.0;
91*5e3eaea3SApple OSS Distributions
92*5e3eaea3SApple OSS Distributions static bool is_rosetta = false;
93*5e3eaea3SApple OSS Distributions
94*5e3eaea3SApple OSS Distributions static mach_timebase_info_data_t timebase_info;
95*5e3eaea3SApple OSS Distributions
96*5e3eaea3SApple OSS Distributions static uint64_t
abs_to_nanos(uint64_t abs)97*5e3eaea3SApple OSS Distributions abs_to_nanos(uint64_t abs)
98*5e3eaea3SApple OSS Distributions {
99*5e3eaea3SApple OSS Distributions return abs * timebase_info.numer / timebase_info.denom;
100*5e3eaea3SApple OSS Distributions }
101*5e3eaea3SApple OSS Distributions
102*5e3eaea3SApple OSS Distributions /* Some statistics APIs return host abstime instead of Rosetta-translated abstime */
103*5e3eaea3SApple OSS Distributions static uint64_t
abs_to_nanos_host(uint64_t abstime)104*5e3eaea3SApple OSS Distributions abs_to_nanos_host(uint64_t abstime)
105*5e3eaea3SApple OSS Distributions {
106*5e3eaea3SApple OSS Distributions if (is_rosetta) {
107*5e3eaea3SApple OSS Distributions return abstime * 125 / 3;
108*5e3eaea3SApple OSS Distributions } else {
109*5e3eaea3SApple OSS Distributions return abs_to_nanos(abstime);
110*5e3eaea3SApple OSS Distributions }
111*5e3eaea3SApple OSS Distributions }
112*5e3eaea3SApple OSS Distributions
113*5e3eaea3SApple OSS Distributions static int
processIsTranslated(void)114*5e3eaea3SApple OSS Distributions processIsTranslated(void)
115*5e3eaea3SApple OSS Distributions {
116*5e3eaea3SApple OSS Distributions int ret = 0;
117*5e3eaea3SApple OSS Distributions size_t size = sizeof(ret);
118*5e3eaea3SApple OSS Distributions if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
119*5e3eaea3SApple OSS Distributions if (errno == ENOENT) {
120*5e3eaea3SApple OSS Distributions return 0;
121*5e3eaea3SApple OSS Distributions } else {
122*5e3eaea3SApple OSS Distributions return -1;
123*5e3eaea3SApple OSS Distributions }
124*5e3eaea3SApple OSS Distributions }
125*5e3eaea3SApple OSS Distributions return ret;
126*5e3eaea3SApple OSS Distributions }
127*5e3eaea3SApple OSS Distributions
128*5e3eaea3SApple OSS Distributions static void
fill_thread_stats(uint32_t i)129*5e3eaea3SApple OSS Distributions fill_thread_stats(uint32_t i)
130*5e3eaea3SApple OSS Distributions {
131*5e3eaea3SApple OSS Distributions struct threadentry *entry = &gThreadList[i];
132*5e3eaea3SApple OSS Distributions
133*5e3eaea3SApple OSS Distributions int rv = thread_selfcounts(THSC_TIME_CPI, &entry->self_stats, sizeof(entry->self_stats));
134*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "thread_selfcounts(THSC_TIME_CPI)");
135*5e3eaea3SApple OSS Distributions }
136*5e3eaea3SApple OSS Distributions
137*5e3eaea3SApple OSS Distributions T_DECL(setitimer,
138*5e3eaea3SApple OSS Distributions "Test various setitimer delivered signals to CPU-burning threads")
139*5e3eaea3SApple OSS Distributions {
140*5e3eaea3SApple OSS Distributions int rv;
141*5e3eaea3SApple OSS Distributions kern_return_t kr;
142*5e3eaea3SApple OSS Distributions uint32_t ncpu;
143*5e3eaea3SApple OSS Distributions size_t ncpu_size = sizeof(ncpu);
144*5e3eaea3SApple OSS Distributions
145*5e3eaea3SApple OSS Distributions struct sched_param self_param = {.sched_priority = 47};
146*5e3eaea3SApple OSS Distributions
147*5e3eaea3SApple OSS Distributions rv = pthread_setschedparam(pthread_self(), SCHED_FIFO, &self_param);
148*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_setschedparam");
149*5e3eaea3SApple OSS Distributions
150*5e3eaea3SApple OSS Distributions kr = mach_timebase_info(&timebase_info);
151*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_timebase_info");
152*5e3eaea3SApple OSS Distributions
153*5e3eaea3SApple OSS Distributions is_rosetta = processIsTranslated();
154*5e3eaea3SApple OSS Distributions
155*5e3eaea3SApple OSS Distributions rv = sysctlbyname("hw.ncpu", &ncpu, &ncpu_size, NULL, 0);
156*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "sysctlbyname(hw.ncpu)");
157*5e3eaea3SApple OSS Distributions
158*5e3eaea3SApple OSS Distributions if (ncpu < 2) {
159*5e3eaea3SApple OSS Distributions T_SKIP("%d CPUs not supported for test, returning success", ncpu);
160*5e3eaea3SApple OSS Distributions }
161*5e3eaea3SApple OSS Distributions
162*5e3eaea3SApple OSS Distributions nworkers = MIN(max_threads - 1, ncpu);
163*5e3eaea3SApple OSS Distributions nthreads = nworkers + 1;
164*5e3eaea3SApple OSS Distributions
165*5e3eaea3SApple OSS Distributions T_LOG("rosetta = %d\n", is_rosetta);
166*5e3eaea3SApple OSS Distributions T_LOG("hw.ncpu = %d\n", ncpu);
167*5e3eaea3SApple OSS Distributions T_LOG("nworkers = %d\n", nworkers);
168*5e3eaea3SApple OSS Distributions T_LOG("nthreads = %d\n", nthreads);
169*5e3eaea3SApple OSS Distributions
170*5e3eaea3SApple OSS Distributions kr = semaphore_create(mach_task_self(), &gMainWaitForWorkers, SYNC_POLICY_FIFO, 0);
171*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "semaphore_create()");
172*5e3eaea3SApple OSS Distributions
173*5e3eaea3SApple OSS Distributions kr = semaphore_create(mach_task_self(), &gWorkersStart, SYNC_POLICY_FIFO, 0);
174*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "semaphore_create()");
175*5e3eaea3SApple OSS Distributions
176*5e3eaea3SApple OSS Distributions pthread_attr_t attr;
177*5e3eaea3SApple OSS Distributions
178*5e3eaea3SApple OSS Distributions rv = pthread_attr_init(&attr);
179*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_attr_init");
180*5e3eaea3SApple OSS Distributions
181*5e3eaea3SApple OSS Distributions struct sched_param child_param = {.sched_priority = 37};
182*5e3eaea3SApple OSS Distributions
183*5e3eaea3SApple OSS Distributions rv = pthread_attr_setschedparam(&attr, &child_param);
184*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_attr_set_qos_class_np");
185*5e3eaea3SApple OSS Distributions
186*5e3eaea3SApple OSS Distributions for (uint32_t i = 0; i < nthreads; i++) {
187*5e3eaea3SApple OSS Distributions if (i == 0) {
188*5e3eaea3SApple OSS Distributions gThreadList[i].thread = pthread_self();
189*5e3eaea3SApple OSS Distributions } else {
190*5e3eaea3SApple OSS Distributions rv = pthread_create(&gThreadList[i].thread, &attr,
191*5e3eaea3SApple OSS Distributions i % 2 ? stat_thread : statfs_thread,
192*5e3eaea3SApple OSS Distributions (void *)(uintptr_t)i);
193*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_create");
194*5e3eaea3SApple OSS Distributions gThreadList[i].expect_cpu_usage = i % 2 == 0 ? true : false;
195*5e3eaea3SApple OSS Distributions }
196*5e3eaea3SApple OSS Distributions
197*5e3eaea3SApple OSS Distributions rv = pthread_threadid_np(gThreadList[i].thread, &gThreadList[i].tid);
198*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_threadid_np");
199*5e3eaea3SApple OSS Distributions
200*5e3eaea3SApple OSS Distributions gThreadList[i].stack_addr = pthread_get_stackaddr_np(gThreadList[i].thread);
201*5e3eaea3SApple OSS Distributions gThreadList[i].stack_size = pthread_get_stacksize_np(gThreadList[i].thread);
202*5e3eaea3SApple OSS Distributions }
203*5e3eaea3SApple OSS Distributions
204*5e3eaea3SApple OSS Distributions rv = pthread_attr_destroy(&attr);
205*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_attr_destroy");
206*5e3eaea3SApple OSS Distributions
207*5e3eaea3SApple OSS Distributions for (uint32_t i = 1; i < nthreads; i++) {
208*5e3eaea3SApple OSS Distributions kr = semaphore_wait(gMainWaitForWorkers);
209*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "semaphore_wait()");
210*5e3eaea3SApple OSS Distributions }
211*5e3eaea3SApple OSS Distributions
212*5e3eaea3SApple OSS Distributions for (uint32_t i = 0; i < nthreads; i++) {
213*5e3eaea3SApple OSS Distributions T_LOG("Thread %p (0x%llx) checked in, stack %p/%p\n",
214*5e3eaea3SApple OSS Distributions (void*)gThreadList[i].thread,
215*5e3eaea3SApple OSS Distributions gThreadList[i].tid,
216*5e3eaea3SApple OSS Distributions gThreadList[i].stack_addr,
217*5e3eaea3SApple OSS Distributions (void *)gThreadList[i].stack_size);
218*5e3eaea3SApple OSS Distributions }
219*5e3eaea3SApple OSS Distributions
220*5e3eaea3SApple OSS Distributions sigset_t sigmk;
221*5e3eaea3SApple OSS Distributions sigemptyset(&sigmk);
222*5e3eaea3SApple OSS Distributions
223*5e3eaea3SApple OSS Distributions struct sigaction sigact = {
224*5e3eaea3SApple OSS Distributions .sa_sigaction = alrm_handler,
225*5e3eaea3SApple OSS Distributions .sa_mask = sigmk,
226*5e3eaea3SApple OSS Distributions .sa_flags = SA_SIGINFO,
227*5e3eaea3SApple OSS Distributions };
228*5e3eaea3SApple OSS Distributions
229*5e3eaea3SApple OSS Distributions rv = sigaction(SIGALRM, &sigact, NULL);
230*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "sigaction(SIGALRM)");
231*5e3eaea3SApple OSS Distributions
232*5e3eaea3SApple OSS Distributions rv = sigaction(SIGVTALRM, &sigact, NULL);
233*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "sigaction(SIGVTALRM)");
234*5e3eaea3SApple OSS Distributions
235*5e3eaea3SApple OSS Distributions rv = sigaction(SIGPROF, &sigact, NULL);
236*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "sigaction(SIGPROF)");
237*5e3eaea3SApple OSS Distributions
238*5e3eaea3SApple OSS Distributions rv = sigaction(SIGXCPU, &sigact, NULL);
239*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "sigaction(SIGXCPU)");
240*5e3eaea3SApple OSS Distributions
241*5e3eaea3SApple OSS Distributions struct itimerval itime = {
242*5e3eaea3SApple OSS Distributions .it_interval.tv_sec = 0,
243*5e3eaea3SApple OSS Distributions .it_interval.tv_usec = 10000,
244*5e3eaea3SApple OSS Distributions .it_value.tv_sec = 0,
245*5e3eaea3SApple OSS Distributions .it_value.tv_usec = 10, /* immediately */
246*5e3eaea3SApple OSS Distributions };
247*5e3eaea3SApple OSS Distributions
248*5e3eaea3SApple OSS Distributions rv = setitimer(ITIMER_REAL, &itime, NULL);
249*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "setitimer(ITIMER_REAL)");
250*5e3eaea3SApple OSS Distributions
251*5e3eaea3SApple OSS Distributions rv = setitimer(ITIMER_VIRTUAL, &itime, NULL);
252*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "setitimer(ITIMER_REAL)");
253*5e3eaea3SApple OSS Distributions
254*5e3eaea3SApple OSS Distributions rv = setitimer(ITIMER_PROF, &itime, NULL);
255*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "setitimer(ITIMER_REAL)");
256*5e3eaea3SApple OSS Distributions
257*5e3eaea3SApple OSS Distributions struct rlimit rlim = {};
258*5e3eaea3SApple OSS Distributions
259*5e3eaea3SApple OSS Distributions rv = getrlimit(RLIMIT_CPU, &rlim);
260*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "getrlimit(RLIMIT_CPU)");
261*5e3eaea3SApple OSS Distributions
262*5e3eaea3SApple OSS Distributions rlim.rlim_cur = 1;
263*5e3eaea3SApple OSS Distributions rv = setrlimit(RLIMIT_CPU, &rlim);
264*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "setrlimit(RLIMIT_CPU)");
265*5e3eaea3SApple OSS Distributions
266*5e3eaea3SApple OSS Distributions rv = pthread_mutex_lock(&gShouldExitMutex);
267*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_mutex_lock(&gShouldExitMutex)");
268*5e3eaea3SApple OSS Distributions
269*5e3eaea3SApple OSS Distributions kr = semaphore_signal_all(gWorkersStart);
270*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "semaphore_signal_all()");
271*5e3eaea3SApple OSS Distributions
272*5e3eaea3SApple OSS Distributions struct timespec timenow = {};
273*5e3eaea3SApple OSS Distributions uint64_t time_start;
274*5e3eaea3SApple OSS Distributions
275*5e3eaea3SApple OSS Distributions kr = mach_get_times(&time_start, NULL, &timenow);
276*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_get_times()");
277*5e3eaea3SApple OSS Distributions
278*5e3eaea3SApple OSS Distributions struct timespec timeout = {
279*5e3eaea3SApple OSS Distributions .tv_sec = timenow.tv_sec + 10,
280*5e3eaea3SApple OSS Distributions .tv_nsec = timenow.tv_nsec,
281*5e3eaea3SApple OSS Distributions };
282*5e3eaea3SApple OSS Distributions
283*5e3eaea3SApple OSS Distributions uint64_t time_end = 0;
284*5e3eaea3SApple OSS Distributions
285*5e3eaea3SApple OSS Distributions do {
286*5e3eaea3SApple OSS Distributions assert(os_atomic_load(&gShouldExit, relaxed) == false);
287*5e3eaea3SApple OSS Distributions
288*5e3eaea3SApple OSS Distributions rv = pthread_cond_timedwait(&gShouldExitCondition, &gShouldExitMutex, &timeout);
289*5e3eaea3SApple OSS Distributions if (rv == ETIMEDOUT) {
290*5e3eaea3SApple OSS Distributions os_atomic_store(&gShouldExit, true, relaxed);
291*5e3eaea3SApple OSS Distributions
292*5e3eaea3SApple OSS Distributions time_end = mach_absolute_time();
293*5e3eaea3SApple OSS Distributions
294*5e3eaea3SApple OSS Distributions struct itimerval itime_stop = {
295*5e3eaea3SApple OSS Distributions .it_interval.tv_sec = 0,
296*5e3eaea3SApple OSS Distributions .it_interval.tv_usec = 0,
297*5e3eaea3SApple OSS Distributions .it_value.tv_sec = 0,
298*5e3eaea3SApple OSS Distributions .it_value.tv_usec = 0, /* stop immediately */
299*5e3eaea3SApple OSS Distributions };
300*5e3eaea3SApple OSS Distributions
301*5e3eaea3SApple OSS Distributions rv = setitimer(ITIMER_REAL, &itime_stop, NULL);
302*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "setitimer(ITIMER_REAL)");
303*5e3eaea3SApple OSS Distributions
304*5e3eaea3SApple OSS Distributions rv = setitimer(ITIMER_VIRTUAL, &itime_stop, NULL);
305*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "setitimer(ITIMER_VIRTUAL)");
306*5e3eaea3SApple OSS Distributions
307*5e3eaea3SApple OSS Distributions rv = setitimer(ITIMER_PROF, &itime_stop, NULL);
308*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "setitimer(ITIMER_PROF)");
309*5e3eaea3SApple OSS Distributions
310*5e3eaea3SApple OSS Distributions break;
311*5e3eaea3SApple OSS Distributions } else {
312*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_cond_timedwait(&gShouldExitCondition, ...)");
313*5e3eaea3SApple OSS Distributions }
314*5e3eaea3SApple OSS Distributions } while (true);
315*5e3eaea3SApple OSS Distributions
316*5e3eaea3SApple OSS Distributions rv = pthread_mutex_unlock(&gShouldExitMutex);
317*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_mutex_unlock(&gShouldExitMutex)");
318*5e3eaea3SApple OSS Distributions
319*5e3eaea3SApple OSS Distributions for (uint32_t i = 1; i < nthreads; i++) {
320*5e3eaea3SApple OSS Distributions rv = pthread_join(gThreadList[i].thread, NULL);
321*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_join");
322*5e3eaea3SApple OSS Distributions }
323*5e3eaea3SApple OSS Distributions
324*5e3eaea3SApple OSS Distributions uint64_t test_duration = time_end - time_start;
325*5e3eaea3SApple OSS Distributions uint64_t test_duration_ns = abs_to_nanos(test_duration);
326*5e3eaea3SApple OSS Distributions
327*5e3eaea3SApple OSS Distributions double elapsed_secs = (double) test_duration_ns / (uint64_t)NSEC_PER_SEC;
328*5e3eaea3SApple OSS Distributions
329*5e3eaea3SApple OSS Distributions T_LOG("test duration %3.3f seconds\n", elapsed_secs);
330*5e3eaea3SApple OSS Distributions
331*5e3eaea3SApple OSS Distributions fill_thread_stats(0);
332*5e3eaea3SApple OSS Distributions
333*5e3eaea3SApple OSS Distributions struct rusage_info_v6 ru = {};
334*5e3eaea3SApple OSS Distributions rv = proc_pid_rusage(getpid(), RUSAGE_INFO_V6, (rusage_info_t *)&ru);
335*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "proc_pid_rusage");
336*5e3eaea3SApple OSS Distributions
337*5e3eaea3SApple OSS Distributions uint64_t total_user_time_ns = abs_to_nanos_host(ru.ri_user_time);
338*5e3eaea3SApple OSS Distributions double total_user_time_s = (double)total_user_time_ns / (uint64_t)NSEC_PER_SEC;
339*5e3eaea3SApple OSS Distributions
340*5e3eaea3SApple OSS Distributions uint64_t total_system_time_ns = abs_to_nanos_host(ru.ri_system_time);
341*5e3eaea3SApple OSS Distributions double total_system_time_s = (double)total_system_time_ns / (uint64_t)NSEC_PER_SEC;
342*5e3eaea3SApple OSS Distributions
343*5e3eaea3SApple OSS Distributions uint64_t total_time_ns = (total_user_time_ns + total_system_time_ns);
344*5e3eaea3SApple OSS Distributions double total_time_s = (double)total_time_ns / (uint64_t)NSEC_PER_SEC;
345*5e3eaea3SApple OSS Distributions
346*5e3eaea3SApple OSS Distributions uint64_t total_runnable_time_ns = abs_to_nanos_host(ru.ri_runnable_time);
347*5e3eaea3SApple OSS Distributions double total_runnable_time_s = (double)total_runnable_time_ns / (uint64_t)NSEC_PER_SEC;
348*5e3eaea3SApple OSS Distributions
349*5e3eaea3SApple OSS Distributions uint64_t total_pending_time_ns = total_runnable_time_ns - (total_time_ns);
350*5e3eaea3SApple OSS Distributions double total_pending_time_s = (double)total_pending_time_ns / (uint64_t)NSEC_PER_SEC;
351*5e3eaea3SApple OSS Distributions
352*5e3eaea3SApple OSS Distributions uint64_t total_p_time_ns = abs_to_nanos_host(ru.ri_user_ptime + ru.ri_system_ptime);
353*5e3eaea3SApple OSS Distributions double total_p_time_s = (double)total_p_time_ns / (uint64_t)NSEC_PER_SEC;
354*5e3eaea3SApple OSS Distributions
355*5e3eaea3SApple OSS Distributions T_LOG("total usage: time: %3.3f user: %3.3f kernel: %3.3f runnable: %3.3f pending: %3.3f pcore: %3.3f\n",
356*5e3eaea3SApple OSS Distributions total_time_s, total_user_time_s, total_system_time_s,
357*5e3eaea3SApple OSS Distributions total_runnable_time_s, total_pending_time_s,
358*5e3eaea3SApple OSS Distributions total_p_time_s);
359*5e3eaea3SApple OSS Distributions
360*5e3eaea3SApple OSS Distributions /*
361*5e3eaea3SApple OSS Distributions * "Good" data looks like:
362*5e3eaea3SApple OSS Distributions *
363*5e3eaea3SApple OSS Distributions * total usage: time: 77.696 user: 16.570 kernel: 61.126 runnable: 79.951 pending: 2.255 pcore: 72.719
364*5e3eaea3SApple OSS Distributions * Thread ALRM VTALRM PROF XCPU inst cycle user kernel offcore type
365*5e3eaea3SApple OSS Distributions * 0x16f78f000 0 251 811 0 27680301973 28913501188 3706622958 ( 38.14%) 6012631083 ( 61.86%) 2.81% statfs
366*5e3eaea3SApple OSS Distributions * 0x16f81b000 0 2 889 0 27962710058 28780576123 439297291 ( 4.53%) 9259942583 ( 95.47%) 3.01% stat
367*5e3eaea3SApple OSS Distributions * 0x16f8a7000 0 251 836 0 27558331077 28889228535 3699010000 ( 38.08%) 6016015083 ( 61.92%) 2.85% statfs
368*5e3eaea3SApple OSS Distributions * 0x16f933000 0 0 939 0 28078084696 28880195679 443067500 ( 4.56%) 9269807666 ( 95.44%) 2.87% stat
369*5e3eaea3SApple OSS Distributions * 0x16f9bf000 0 283 874 0 27691851016 28969873070 3710916750 ( 38.16%) 6012783541 ( 61.84%) 2.76% statfs
370*5e3eaea3SApple OSS Distributions * 0x16fa4b000 0 2 908 1 27945063330 28769971396 438583000 ( 4.53%) 9252694291 ( 95.47%) 3.09% stat
371*5e3eaea3SApple OSS Distributions * 0x16fad7000 0 262 889 0 27328496429 28772748055 3689245375 ( 38.03%) 6011061458 ( 61.97%) 3.00% statfs
372*5e3eaea3SApple OSS Distributions * 0x16fb63000 0 0 914 0 27942195343 28757254100 439690166 ( 4.53%) 9256659500 ( 95.47%) 3.04% stat
373*5e3eaea3SApple OSS Distributions * 0x1fe2bb400 1001 0 3 0 72144372 102339334 3532125 ( 9.35%) 34249208 ( 90.65%) 99.62% main
374*5e3eaea3SApple OSS Distributions */
375*5e3eaea3SApple OSS Distributions uint32_t total_alrm = 0;
376*5e3eaea3SApple OSS Distributions uint32_t total_vtalrm = 0;
377*5e3eaea3SApple OSS Distributions uint32_t total_prof = 0;
378*5e3eaea3SApple OSS Distributions uint32_t total_xcpu = 0;
379*5e3eaea3SApple OSS Distributions uint32_t total_vtalrm_in_cpubound = 0;
380*5e3eaea3SApple OSS Distributions
381*5e3eaea3SApple OSS Distributions uint32_t total_threads_not_finding_cpus = 0;
382*5e3eaea3SApple OSS Distributions
383*5e3eaea3SApple OSS Distributions T_LOG("Thread ALRM VTALRM PROF XCPU "
384*5e3eaea3SApple OSS Distributions "inst cycle user kernel "
385*5e3eaea3SApple OSS Distributions "offcore type\n");
386*5e3eaea3SApple OSS Distributions
387*5e3eaea3SApple OSS Distributions for (uint32_t i = 0; i < nthreads; i++) {
388*5e3eaea3SApple OSS Distributions uint64_t user_time = abs_to_nanos_host(gThreadList[i].self_stats.ttci_user_time_mach);
389*5e3eaea3SApple OSS Distributions uint64_t system_time = abs_to_nanos_host(gThreadList[i].self_stats.ttci_system_time_mach);
390*5e3eaea3SApple OSS Distributions
391*5e3eaea3SApple OSS Distributions
392*5e3eaea3SApple OSS Distributions uint64_t total_time = user_time + system_time;
393*5e3eaea3SApple OSS Distributions
394*5e3eaea3SApple OSS Distributions double percentage_user = (double)user_time / (double) total_time * 100;
395*5e3eaea3SApple OSS Distributions double percentage_system = (double)system_time / (double) total_time * 100;
396*5e3eaea3SApple OSS Distributions double percentage_not_running = (double)(test_duration_ns - total_time) / (double) test_duration_ns * 100;
397*5e3eaea3SApple OSS Distributions
398*5e3eaea3SApple OSS Distributions char* thread_type_str = "";
399*5e3eaea3SApple OSS Distributions char* warning_str = "";
400*5e3eaea3SApple OSS Distributions
401*5e3eaea3SApple OSS Distributions if (i == 0) {
402*5e3eaea3SApple OSS Distributions thread_type_str = "main ";
403*5e3eaea3SApple OSS Distributions } else {
404*5e3eaea3SApple OSS Distributions thread_type_str = i % 2 ? "stat " : "statfs ";
405*5e3eaea3SApple OSS Distributions
406*5e3eaea3SApple OSS Distributions if (percentage_not_running > offcore_time_percent_threshold) {
407*5e3eaea3SApple OSS Distributions total_threads_not_finding_cpus++;
408*5e3eaea3SApple OSS Distributions warning_str = "** too much offcore time **";
409*5e3eaea3SApple OSS Distributions }
410*5e3eaea3SApple OSS Distributions }
411*5e3eaea3SApple OSS Distributions
412*5e3eaea3SApple OSS Distributions T_LOG("0x%010llx %6d %6d %6d %6d %12lld %12lld %12lld (%7.2f%%) %12lld (%7.2f%%) %7.2f%% %s%s\n",
413*5e3eaea3SApple OSS Distributions gThreadList[i].tid,
414*5e3eaea3SApple OSS Distributions gThreadList[i].alrm_count,
415*5e3eaea3SApple OSS Distributions gThreadList[i].vtalrm_count,
416*5e3eaea3SApple OSS Distributions gThreadList[i].prof_count,
417*5e3eaea3SApple OSS Distributions gThreadList[i].xcpu_count,
418*5e3eaea3SApple OSS Distributions gThreadList[i].self_stats.ttci_instructions,
419*5e3eaea3SApple OSS Distributions gThreadList[i].self_stats.ttci_cycles,
420*5e3eaea3SApple OSS Distributions user_time, percentage_user,
421*5e3eaea3SApple OSS Distributions system_time, percentage_system,
422*5e3eaea3SApple OSS Distributions percentage_not_running,
423*5e3eaea3SApple OSS Distributions thread_type_str, warning_str);
424*5e3eaea3SApple OSS Distributions
425*5e3eaea3SApple OSS Distributions total_alrm += gThreadList[i].alrm_count;
426*5e3eaea3SApple OSS Distributions total_vtalrm += gThreadList[i].vtalrm_count;
427*5e3eaea3SApple OSS Distributions total_prof += gThreadList[i].prof_count;
428*5e3eaea3SApple OSS Distributions total_xcpu += gThreadList[i].xcpu_count;
429*5e3eaea3SApple OSS Distributions
430*5e3eaea3SApple OSS Distributions if (gThreadList[i].expect_cpu_usage) {
431*5e3eaea3SApple OSS Distributions total_vtalrm_in_cpubound += gThreadList[i].vtalrm_count;
432*5e3eaea3SApple OSS Distributions }
433*5e3eaea3SApple OSS Distributions }
434*5e3eaea3SApple OSS Distributions
435*5e3eaea3SApple OSS Distributions /*
436*5e3eaea3SApple OSS Distributions * We expect all SIGALRM to go to the main thread, because it is the
437*5e3eaea3SApple OSS Distributions * first thread in the process with the signal unmasked, and we
438*5e3eaea3SApple OSS Distributions * never expect the signal handler itself to take >10ms
439*5e3eaea3SApple OSS Distributions *
440*5e3eaea3SApple OSS Distributions * This can happen if the main thread is preempted for the entire 10ms duration, though.
441*5e3eaea3SApple OSS Distributions * Being high priority, it shouldn't be delayed for more than 10ms too often.
442*5e3eaea3SApple OSS Distributions * Allow up to 10% to deliver to other threads.
443*5e3eaea3SApple OSS Distributions */
444*5e3eaea3SApple OSS Distributions if ((double)gThreadList[0].alrm_count * 100 / total_alrm < 90.0) {
445*5e3eaea3SApple OSS Distributions T_FAIL("SIGALRM delivered to non-main thread more than 10%% of the time (%d of %d)",
446*5e3eaea3SApple OSS Distributions gThreadList[0].alrm_count,
447*5e3eaea3SApple OSS Distributions total_alrm);
448*5e3eaea3SApple OSS Distributions }
449*5e3eaea3SApple OSS Distributions
450*5e3eaea3SApple OSS Distributions /* We expect all worker threads to find CPUs of their own for most of the test */
451*5e3eaea3SApple OSS Distributions if (total_threads_not_finding_cpus != 0) {
452*5e3eaea3SApple OSS Distributions T_FAIL("%d worker threads spent more than %2.0f%% of time off-core",
453*5e3eaea3SApple OSS Distributions total_threads_not_finding_cpus, offcore_time_percent_threshold);
454*5e3eaea3SApple OSS Distributions }
455*5e3eaea3SApple OSS Distributions
456*5e3eaea3SApple OSS Distributions /*
457*5e3eaea3SApple OSS Distributions * SIGVTALRM is delivered based on user time, and we expect the busy
458*5e3eaea3SApple OSS Distributions * threads to have an advantage and account for 80% (non-scientific) of events,
459*5e3eaea3SApple OSS Distributions * since the other threads will spend more time in kernel mode.
460*5e3eaea3SApple OSS Distributions */
461*5e3eaea3SApple OSS Distributions if (total_vtalrm_in_cpubound * 100 / total_vtalrm < 80) {
462*5e3eaea3SApple OSS Distributions T_FAIL("SIGVTALRM delivered to threads without extra userspace spin (only %d of %d)",
463*5e3eaea3SApple OSS Distributions total_vtalrm_in_cpubound, total_vtalrm);
464*5e3eaea3SApple OSS Distributions }
465*5e3eaea3SApple OSS Distributions
466*5e3eaea3SApple OSS Distributions /*
467*5e3eaea3SApple OSS Distributions * SIGPROF is delivered based on user+system time, and we expect it to be distributed
468*5e3eaea3SApple OSS Distributions * among non-blocked threads (so not the main thread, which only handles SIGALRM).
469*5e3eaea3SApple OSS Distributions */
470*5e3eaea3SApple OSS Distributions if (gThreadList[0].prof_count * 100 / total_prof > 1) {
471*5e3eaea3SApple OSS Distributions T_FAIL("SIGPROF delivered to main thread more than 1%% (%d of %d)",
472*5e3eaea3SApple OSS Distributions gThreadList[0].prof_count,
473*5e3eaea3SApple OSS Distributions total_prof);
474*5e3eaea3SApple OSS Distributions }
475*5e3eaea3SApple OSS Distributions
476*5e3eaea3SApple OSS Distributions /*
477*5e3eaea3SApple OSS Distributions * SIGXCPU should be delivered exactly once.
478*5e3eaea3SApple OSS Distributions */
479*5e3eaea3SApple OSS Distributions if (total_xcpu == 0) {
480*5e3eaea3SApple OSS Distributions T_FAIL("SIGXCPU delivered %d times (expected at least once)", total_xcpu);
481*5e3eaea3SApple OSS Distributions }
482*5e3eaea3SApple OSS Distributions }
483*5e3eaea3SApple OSS Distributions
484*5e3eaea3SApple OSS Distributions static void *
stat_thread(void * arg)485*5e3eaea3SApple OSS Distributions stat_thread(void *arg)
486*5e3eaea3SApple OSS Distributions {
487*5e3eaea3SApple OSS Distributions kern_return_t kr;
488*5e3eaea3SApple OSS Distributions int rv;
489*5e3eaea3SApple OSS Distributions
490*5e3eaea3SApple OSS Distributions /* This wait can be aborted by one of the signals, so we make sure to wait for the first iteration of main */
491*5e3eaea3SApple OSS Distributions kr = semaphore_wait_signal(gWorkersStart, gMainWaitForWorkers);
492*5e3eaea3SApple OSS Distributions if (kr != KERN_ABORTED) {
493*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "semaphore_wait_signal()");
494*5e3eaea3SApple OSS Distributions }
495*5e3eaea3SApple OSS Distributions
496*5e3eaea3SApple OSS Distributions rv = pthread_mutex_lock(&gShouldExitMutex);
497*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_mutex_lock(&gShouldExitMutex)");
498*5e3eaea3SApple OSS Distributions rv = pthread_mutex_unlock(&gShouldExitMutex);
499*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_mutex_unlock(&gShouldExitMutex)");
500*5e3eaea3SApple OSS Distributions
501*5e3eaea3SApple OSS Distributions do {
502*5e3eaea3SApple OSS Distributions struct stat sb;
503*5e3eaea3SApple OSS Distributions
504*5e3eaea3SApple OSS Distributions rv = stat("/", &sb);
505*5e3eaea3SApple OSS Distributions if (rv != 0) {
506*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "stat");
507*5e3eaea3SApple OSS Distributions }
508*5e3eaea3SApple OSS Distributions } while (os_atomic_load(&gShouldExit, relaxed) == false);
509*5e3eaea3SApple OSS Distributions
510*5e3eaea3SApple OSS Distributions fill_thread_stats((uint32_t)(uintptr_t)arg);
511*5e3eaea3SApple OSS Distributions
512*5e3eaea3SApple OSS Distributions return NULL;
513*5e3eaea3SApple OSS Distributions }
514*5e3eaea3SApple OSS Distributions
515*5e3eaea3SApple OSS Distributions static void *
statfs_thread(void * arg)516*5e3eaea3SApple OSS Distributions statfs_thread(void *arg)
517*5e3eaea3SApple OSS Distributions {
518*5e3eaea3SApple OSS Distributions kern_return_t kr;
519*5e3eaea3SApple OSS Distributions uint64_t previous_spin_timestamp;
520*5e3eaea3SApple OSS Distributions int iteration = 0;
521*5e3eaea3SApple OSS Distributions int rv;
522*5e3eaea3SApple OSS Distributions
523*5e3eaea3SApple OSS Distributions /* This wait can be aborted by one of the signals, so we make sure to wait for the first iteration of main */
524*5e3eaea3SApple OSS Distributions kr = semaphore_wait_signal(gWorkersStart, gMainWaitForWorkers);
525*5e3eaea3SApple OSS Distributions if (kr != KERN_ABORTED) {
526*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "semaphore_wait_signal()");
527*5e3eaea3SApple OSS Distributions }
528*5e3eaea3SApple OSS Distributions
529*5e3eaea3SApple OSS Distributions rv = pthread_mutex_lock(&gShouldExitMutex);
530*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_mutex_lock(&gShouldExitMutex)");
531*5e3eaea3SApple OSS Distributions rv = pthread_mutex_unlock(&gShouldExitMutex);
532*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_mutex_unlock(&gShouldExitMutex)");
533*5e3eaea3SApple OSS Distributions
534*5e3eaea3SApple OSS Distributions previous_spin_timestamp = mach_absolute_time();
535*5e3eaea3SApple OSS Distributions
536*5e3eaea3SApple OSS Distributions do {
537*5e3eaea3SApple OSS Distributions struct statfs sf;
538*5e3eaea3SApple OSS Distributions
539*5e3eaea3SApple OSS Distributions /*
540*5e3eaea3SApple OSS Distributions * Every so many system calls, inject a spin in userspace
541*5e3eaea3SApple OSS Distributions * proportional to how much time was spent performing the
542*5e3eaea3SApple OSS Distributions * system calls.
543*5e3eaea3SApple OSS Distributions */
544*5e3eaea3SApple OSS Distributions #define SYSCALL_ITERATIONS_BETWEEN_SPINS (10000)
545*5e3eaea3SApple OSS Distributions if (++iteration % SYSCALL_ITERATIONS_BETWEEN_SPINS == 0) {
546*5e3eaea3SApple OSS Distributions uint64_t now = mach_absolute_time();
547*5e3eaea3SApple OSS Distributions uint64_t spin_deadline = now + (now - previous_spin_timestamp) / 2;
548*5e3eaea3SApple OSS Distributions
549*5e3eaea3SApple OSS Distributions while (mach_absolute_time() < spin_deadline) {
550*5e3eaea3SApple OSS Distributions ;
551*5e3eaea3SApple OSS Distributions }
552*5e3eaea3SApple OSS Distributions
553*5e3eaea3SApple OSS Distributions previous_spin_timestamp = mach_absolute_time();
554*5e3eaea3SApple OSS Distributions }
555*5e3eaea3SApple OSS Distributions
556*5e3eaea3SApple OSS Distributions rv = statfs("/", &sf);
557*5e3eaea3SApple OSS Distributions if (rv != 0) {
558*5e3eaea3SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "statfs");
559*5e3eaea3SApple OSS Distributions }
560*5e3eaea3SApple OSS Distributions } while (os_atomic_load(&gShouldExit, relaxed) == false);
561*5e3eaea3SApple OSS Distributions
562*5e3eaea3SApple OSS Distributions fill_thread_stats((uint32_t)(uintptr_t)arg);
563*5e3eaea3SApple OSS Distributions
564*5e3eaea3SApple OSS Distributions return NULL;
565*5e3eaea3SApple OSS Distributions }
566*5e3eaea3SApple OSS Distributions
567*5e3eaea3SApple OSS Distributions static void
alrm_handler(int signum,struct __siginfo * info __unused,void * uap)568*5e3eaea3SApple OSS Distributions alrm_handler(int signum, struct __siginfo *info __unused, void *uap)
569*5e3eaea3SApple OSS Distributions {
570*5e3eaea3SApple OSS Distributions ucontext_t *context = (ucontext_t *)uap;
571*5e3eaea3SApple OSS Distributions struct threadentry *entry = NULL;
572*5e3eaea3SApple OSS Distributions void *sp;
573*5e3eaea3SApple OSS Distributions
574*5e3eaea3SApple OSS Distributions #if defined(__arm64__)
575*5e3eaea3SApple OSS Distributions sp = (void *)__darwin_arm_thread_state64_get_sp((context->uc_mcontext)->__ss);
576*5e3eaea3SApple OSS Distributions #elif defined(__i386__)
577*5e3eaea3SApple OSS Distributions sp = (void *)(context->uc_mcontext)->__ss.__esp;
578*5e3eaea3SApple OSS Distributions #elif defined(__x86_64__)
579*5e3eaea3SApple OSS Distributions sp = (void *)(context->uc_mcontext)->__ss.__rsp;
580*5e3eaea3SApple OSS Distributions #else
581*5e3eaea3SApple OSS Distributions #error Unrecognized architecture
582*5e3eaea3SApple OSS Distributions #endif
583*5e3eaea3SApple OSS Distributions
584*5e3eaea3SApple OSS Distributions for (uint32_t i = 0; i < nworkers + 1; i++) {
585*5e3eaea3SApple OSS Distributions struct threadentry *t = &gThreadList[i];
586*5e3eaea3SApple OSS Distributions if (((uintptr_t)sp >= ((uintptr_t)t->stack_addr - t->stack_size) &&
587*5e3eaea3SApple OSS Distributions ((uintptr_t)sp < (uintptr_t)t->stack_addr))) {
588*5e3eaea3SApple OSS Distributions entry = t;
589*5e3eaea3SApple OSS Distributions break;
590*5e3eaea3SApple OSS Distributions }
591*5e3eaea3SApple OSS Distributions }
592*5e3eaea3SApple OSS Distributions
593*5e3eaea3SApple OSS Distributions if (entry == NULL) {
594*5e3eaea3SApple OSS Distributions T_ASSERT_FAIL("Signal %d delivered to unknown thread, SP=%p", signum, sp);
595*5e3eaea3SApple OSS Distributions }
596*5e3eaea3SApple OSS Distributions
597*5e3eaea3SApple OSS Distributions switch (signum) {
598*5e3eaea3SApple OSS Distributions case SIGALRM:
599*5e3eaea3SApple OSS Distributions os_atomic_inc(&entry->alrm_count, relaxed);
600*5e3eaea3SApple OSS Distributions break;
601*5e3eaea3SApple OSS Distributions case SIGVTALRM:
602*5e3eaea3SApple OSS Distributions os_atomic_inc(&entry->vtalrm_count, relaxed);
603*5e3eaea3SApple OSS Distributions break;
604*5e3eaea3SApple OSS Distributions case SIGPROF:
605*5e3eaea3SApple OSS Distributions os_atomic_inc(&entry->prof_count, relaxed);
606*5e3eaea3SApple OSS Distributions break;
607*5e3eaea3SApple OSS Distributions case SIGXCPU:
608*5e3eaea3SApple OSS Distributions os_atomic_inc(&entry->xcpu_count, relaxed);
609*5e3eaea3SApple OSS Distributions break;
610*5e3eaea3SApple OSS Distributions }
611*5e3eaea3SApple OSS Distributions }
612