xref: /xnu-8019.80.24/tests/restart.c (revision a325d9c4a84054e40bbe985afedcb50ab80993ea) !
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