1*a325d9c4SApple OSS Distributions #include <mach/task.h>
2*a325d9c4SApple OSS Distributions #include <mach/mach.h>
3*a325d9c4SApple OSS Distributions #include <kern/restartable.h>
4*a325d9c4SApple OSS Distributions #include <stdbool.h>
5*a325d9c4SApple OSS Distributions #include <darwintest.h>
6*a325d9c4SApple OSS Distributions #include <pthread.h>
7*a325d9c4SApple OSS Distributions #include <unistd.h>
8*a325d9c4SApple OSS Distributions #include <signal.h>
9*a325d9c4SApple OSS Distributions
10*a325d9c4SApple OSS Distributions T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
11*a325d9c4SApple OSS Distributions
12*a325d9c4SApple OSS Distributions extern task_restartable_range_t range;
13*a325d9c4SApple OSS Distributions extern void restartable_function(int *);
14*a325d9c4SApple OSS Distributions static int step = 0;
15*a325d9c4SApple OSS Distributions
16*a325d9c4SApple OSS Distributions #if defined(__x86_64__)
17*a325d9c4SApple OSS Distributions __asm__(" .align 4\n"
18*a325d9c4SApple OSS Distributions " .text\n"
19*a325d9c4SApple OSS Distributions " .private_extern _restartable_function\n"
20*a325d9c4SApple OSS Distributions "_restartable_function:\n"
21*a325d9c4SApple OSS Distributions // this should use $arg1 but I don't know intel calling conventions
22*a325d9c4SApple OSS Distributions // so the argument to restartable_function() is actually ignored
23*a325d9c4SApple OSS Distributions // as we know what it is anyway, and Intel PC-relative addressing,
24*a325d9c4SApple OSS Distributions // unlike ARM, is pretty readable
25*a325d9c4SApple OSS Distributions " incl _step(%rip)\n"
26*a325d9c4SApple OSS Distributions "1:\n"
27*a325d9c4SApple OSS Distributions " pause\n"
28*a325d9c4SApple OSS Distributions " jmp 1b\n"
29*a325d9c4SApple OSS Distributions "LExit_restartable_function:\n"
30*a325d9c4SApple OSS Distributions " ret\n");
31*a325d9c4SApple OSS Distributions #elif defined(__arm64__)
32*a325d9c4SApple OSS Distributions __asm__(" .align 4\n"
33*a325d9c4SApple OSS Distributions " .text\n"
34*a325d9c4SApple OSS Distributions " .private_extern _restartable_function\n"
35*a325d9c4SApple OSS Distributions "_restartable_function:\n"
36*a325d9c4SApple OSS Distributions " ldr x11, [x0]\n"
37*a325d9c4SApple OSS Distributions " add x11, x11, #1\n"
38*a325d9c4SApple OSS Distributions " str x11, [x0]\n"
39*a325d9c4SApple OSS Distributions "1:\n"
40*a325d9c4SApple OSS Distributions " b 1b\n"
41*a325d9c4SApple OSS Distributions "LExit_restartable_function:\n"
42*a325d9c4SApple OSS Distributions " ret\n");
43*a325d9c4SApple OSS Distributions #elif defined(__arm__)
44*a325d9c4SApple OSS Distributions __asm__(" .align 4\n"
45*a325d9c4SApple OSS Distributions " .text\n"
46*a325d9c4SApple OSS Distributions " .thumb\n"
47*a325d9c4SApple OSS Distributions " .private_extern _restartable_function\n"
48*a325d9c4SApple OSS Distributions " .thumb_func\n"
49*a325d9c4SApple OSS Distributions "_restartable_function:\n"
50*a325d9c4SApple OSS Distributions "0:\n"
51*a325d9c4SApple OSS Distributions " ldr r12, [r0]\n"
52*a325d9c4SApple OSS Distributions " add r12, r12, #1\n"
53*a325d9c4SApple OSS Distributions " str r12, [r0]\n"
54*a325d9c4SApple OSS Distributions "1:\n"
55*a325d9c4SApple OSS Distributions " b 1b\n"
56*a325d9c4SApple OSS Distributions "LExit_restartable_function:\n"
57*a325d9c4SApple OSS Distributions " bx lr\n");
58*a325d9c4SApple OSS Distributions #elif defined(__i386__)
59*a325d9c4SApple OSS Distributions #define SKIP_TEST 1
60*a325d9c4SApple OSS Distributions #else
61*a325d9c4SApple OSS Distributions #error Architecture unsupported
62*a325d9c4SApple OSS Distributions #endif
63*a325d9c4SApple OSS Distributions
64*a325d9c4SApple OSS Distributions #ifndef SKIP_TEST
65*a325d9c4SApple OSS Distributions __asm__(" .align 4\n"
66*a325d9c4SApple OSS Distributions " .data\n"
67*a325d9c4SApple OSS Distributions " .private_extern _range\n"
68*a325d9c4SApple OSS Distributions "_range:\n"
69*a325d9c4SApple OSS Distributions #if __LP64__
70*a325d9c4SApple OSS Distributions " .quad _restartable_function\n"
71*a325d9c4SApple OSS Distributions #else
72*a325d9c4SApple OSS Distributions " .long _restartable_function\n"
73*a325d9c4SApple OSS Distributions " .long 0\n"
74*a325d9c4SApple OSS Distributions #endif
75*a325d9c4SApple OSS Distributions " .short LExit_restartable_function - _restartable_function\n"
76*a325d9c4SApple OSS Distributions " .short LExit_restartable_function - _restartable_function\n"
77*a325d9c4SApple OSS Distributions " .long 0\n");
78*a325d9c4SApple OSS Distributions #endif
79*a325d9c4SApple OSS Distributions
80*a325d9c4SApple OSS Distributions static void
noop_signal(int signo __unused)81*a325d9c4SApple OSS Distributions noop_signal(int signo __unused)
82*a325d9c4SApple OSS Distributions {
83*a325d9c4SApple OSS Distributions }
84*a325d9c4SApple OSS Distributions
85*a325d9c4SApple OSS Distributions static void *
task_restartable_ranges_thread(void * _ctx)86*a325d9c4SApple OSS Distributions task_restartable_ranges_thread(void *_ctx)
87*a325d9c4SApple OSS Distributions {
88*a325d9c4SApple OSS Distributions int *stepp = _ctx;
89*a325d9c4SApple OSS Distributions restartable_function(stepp); // increments step
90*a325d9c4SApple OSS Distributions T_PASS("was successfully restarted\n");
91*a325d9c4SApple OSS Distributions (*stepp)++;
92*a325d9c4SApple OSS Distributions return NULL;
93*a325d9c4SApple OSS Distributions }
94*a325d9c4SApple OSS Distributions
95*a325d9c4SApple OSS Distributions static void
wait_for_step(int which)96*a325d9c4SApple OSS Distributions wait_for_step(int which)
97*a325d9c4SApple OSS Distributions {
98*a325d9c4SApple OSS Distributions for (int i = 0; step != which && i < 10; i++) {
99*a325d9c4SApple OSS Distributions usleep(100000);
100*a325d9c4SApple OSS Distributions }
101*a325d9c4SApple OSS Distributions }
102*a325d9c4SApple OSS Distributions
103*a325d9c4SApple OSS Distributions T_DECL(task_restartable_ranges, "test task_restartable_ranges")
104*a325d9c4SApple OSS Distributions {
105*a325d9c4SApple OSS Distributions #ifdef SKIP_TEST
106*a325d9c4SApple OSS Distributions T_SKIP("Not supported");
107*a325d9c4SApple OSS Distributions #else
108*a325d9c4SApple OSS Distributions kern_return_t kr;
109*a325d9c4SApple OSS Distributions pthread_t th;
110*a325d9c4SApple OSS Distributions int rc;
111*a325d9c4SApple OSS Distributions
112*a325d9c4SApple OSS Distributions signal(SIGUSR1, noop_signal);
113*a325d9c4SApple OSS Distributions
114*a325d9c4SApple OSS Distributions kr = task_restartable_ranges_register(mach_task_self(), &range, 1);
115*a325d9c4SApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "task_restartable_ranges_register");
116*a325d9c4SApple OSS Distributions
117*a325d9c4SApple OSS Distributions {
118*a325d9c4SApple OSS Distributions rc = pthread_create(&th, NULL, &task_restartable_ranges_thread, &step);
119*a325d9c4SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(rc, "pthread_create");
120*a325d9c4SApple OSS Distributions
121*a325d9c4SApple OSS Distributions wait_for_step(1);
122*a325d9c4SApple OSS Distributions T_ASSERT_EQ(step, 1, "The thread started (sync)");
123*a325d9c4SApple OSS Distributions
124*a325d9c4SApple OSS Distributions kr = task_restartable_ranges_synchronize(mach_task_self());
125*a325d9c4SApple OSS Distributions T_ASSERT_MACH_SUCCESS(kr, "task_restartable_ranges_synchronize");
126*a325d9c4SApple OSS Distributions
127*a325d9c4SApple OSS Distributions T_LOG("wait for the function to be restarted (sync)");
128*a325d9c4SApple OSS Distributions wait_for_step(2);
129*a325d9c4SApple OSS Distributions T_ASSERT_EQ(step, 2, "The thread exited (sync)");
130*a325d9c4SApple OSS Distributions pthread_join(th, NULL);
131*a325d9c4SApple OSS Distributions }
132*a325d9c4SApple OSS Distributions
133*a325d9c4SApple OSS Distributions {
134*a325d9c4SApple OSS Distributions rc = pthread_create(&th, NULL, &task_restartable_ranges_thread, &step);
135*a325d9c4SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(rc, "pthread_create");
136*a325d9c4SApple OSS Distributions
137*a325d9c4SApple OSS Distributions wait_for_step(3);
138*a325d9c4SApple OSS Distributions T_ASSERT_EQ(step, 3, "The thread started (signal)");
139*a325d9c4SApple OSS Distributions
140*a325d9c4SApple OSS Distributions rc = pthread_kill(th, SIGUSR1);
141*a325d9c4SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(rc, "pthread_kill");
142*a325d9c4SApple OSS Distributions
143*a325d9c4SApple OSS Distributions T_LOG("wait for the function to be restarted (signal)");
144*a325d9c4SApple OSS Distributions wait_for_step(4);
145*a325d9c4SApple OSS Distributions T_ASSERT_EQ(step, 4, "The thread exited (signal)");
146*a325d9c4SApple OSS Distributions pthread_join(th, NULL);
147*a325d9c4SApple OSS Distributions }
148*a325d9c4SApple OSS Distributions #endif
149*a325d9c4SApple OSS Distributions }
150