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