Skip to content

Commit 6d9702d

Browse files
committed
Add context switching tests to the WASIX tests
1 parent d082fe3 commit 6d9702d

2 files changed

Lines changed: 362 additions & 0 deletions

File tree

Lines changed: 354 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,354 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <unistd.h>
4+
#include <string.h>
5+
#include <fcntl.h>
6+
#include <errno.h>
7+
#include <sys/wait.h>
8+
#include <assert.h>
9+
#include <spawn.h>
10+
#include <wasix/context.h>
11+
12+
wasix_context_id_t ctx1;
13+
int was_in_two = 0;
14+
15+
void context2_fn(void) {
16+
was_in_two++;
17+
wasix_context_switch(ctx1);
18+
assert(0 && "Should not return to context 2");
19+
}
20+
21+
void context1_fn(void) {
22+
wasix_context_id_t ctx2;
23+
int ret = wasix_context_create(&ctx2, context2_fn);
24+
assert(ret == 0 && "Failed to create context 2");
25+
wasix_context_switch(ctx2);
26+
wasix_context_destroy(ctx2);
27+
wasix_context_switch(wasix_context_main);
28+
}
29+
30+
int was_in_context_fn_switch_to_main = 0;
31+
void context_fn_switch_to_main(void) {
32+
was_in_context_fn_switch_to_main = 1;
33+
wasix_context_switch(wasix_context_main);
34+
assert(0);
35+
}
36+
37+
// Test a simple context switching scenario
38+
int test_basic_switching() {
39+
// Create three contexts
40+
int ret = wasix_context_create(&ctx1, context1_fn);
41+
assert(ret == 0 && "Failed to create context 1");
42+
43+
wasix_context_switch(ctx1);
44+
45+
assert(was_in_two == 1 && "Context 2 was not executed exactly once");
46+
47+
return 0;
48+
}
49+
50+
51+
52+
int vfork_exec()
53+
{
54+
int pid = vfork();
55+
56+
if (pid == 0)
57+
{
58+
execl("./main.wasm", "main.wasm", "subprocess", NULL);
59+
perror("execl");
60+
exit(10);
61+
}
62+
else
63+
{
64+
int status;
65+
waitpid(pid, &status, 0);
66+
if (WEXITSTATUS(status) != 20)
67+
{
68+
printf("Expected exit code 20 from subprocess, got %d\n", WEXITSTATUS(status));
69+
return 1;
70+
}
71+
72+
return 0;
73+
}
74+
}
75+
76+
// Test that vfork works even after other contexts are active
77+
int vfork_after_switching()
78+
{
79+
wasix_context_id_t ctx;
80+
int ret = wasix_context_create(&ctx, context_fn_switch_to_main);
81+
assert(ret == 0 && "Failed to create context");
82+
wasix_context_switch(ctx);
83+
84+
int pid = vfork();
85+
86+
if (pid == 0)
87+
{
88+
execl("./main.wasm", "main.wasm", "subprocess", NULL);
89+
perror("execl");
90+
exit(10);
91+
}
92+
else
93+
{
94+
int status;
95+
waitpid(pid, &status, 0);
96+
if (WEXITSTATUS(status) != 20)
97+
{
98+
printf("Expected exit code 20 from subprocess, got %d\n", WEXITSTATUS(status));
99+
return 1;
100+
}
101+
102+
return 0;
103+
}
104+
}
105+
106+
// Test that vfork works even after other contexts are active
107+
int vfork_after_switching2()
108+
{
109+
// Create two contexts. One is to verify switching works now and the other to verify it works later on.
110+
wasix_context_id_t ctx_a, ctx_b;
111+
int ret = wasix_context_create(&ctx_a, context_fn_switch_to_main);
112+
assert(ret == 0 && "Failed to create context");
113+
ret = wasix_context_create(&ctx_b, context_fn_switch_to_main);
114+
assert(ret == 0 && "Failed to create context");
115+
116+
// Verify that switching works before vfork
117+
was_in_context_fn_switch_to_main = 0;
118+
wasix_context_switch(ctx_a);
119+
assert(was_in_context_fn_switch_to_main == 1 && "Context function was not executed");
120+
121+
int pid = vfork();
122+
123+
if (pid == 0)
124+
{
125+
// The process created by vfork should not have a context switching environment
126+
// so we get a ENOSYS here
127+
int ret = wasix_context_switch(ctx_b);
128+
if (ret != -1) {
129+
exit(11);
130+
}
131+
if (errno != ENOTSUP) {
132+
exit(12);
133+
}
134+
135+
execl("./main.wasm", "main.wasm", "subprocess_with_switching", NULL);
136+
perror("execl");
137+
exit(10);
138+
}
139+
else
140+
{
141+
// The parent should still be in the same context switching environment
142+
was_in_context_fn_switch_to_main = 0;
143+
wasix_context_switch(ctx_b);
144+
assert(was_in_context_fn_switch_to_main == 1 && "Context function was not executed");
145+
146+
int status;
147+
waitpid(pid, &status, 0);
148+
if (WEXITSTATUS(status) != 20)
149+
{
150+
printf("Expected exit code 20 from subprocess, got %d\n", WEXITSTATUS(status));
151+
return 1;
152+
}
153+
154+
return 0;
155+
}
156+
}
157+
158+
// Test that vfork works even after other contexts are active
159+
int fork_after_switching()
160+
{
161+
// Create two contexts. One is to verify switching works now and the other to verify it works later on.
162+
wasix_context_id_t ctx_a, ctx_b;
163+
int ret = wasix_context_create(&ctx_a, context_fn_switch_to_main);
164+
assert(ret == 0 && "Failed to create context");
165+
ret = wasix_context_create(&ctx_b, context_fn_switch_to_main);
166+
assert(ret == 0 && "Failed to create context");
167+
168+
// Verify that switching works before vfork
169+
was_in_context_fn_switch_to_main = 0;
170+
wasix_context_switch(ctx_a);
171+
assert(was_in_context_fn_switch_to_main == 1 && "Context function was not executed");
172+
173+
int pid = fork();
174+
175+
if (pid == 0)
176+
{
177+
// The process created by fork should have a new context switching environment
178+
// so we get a EINVAL here because the context does not exist in this new environment
179+
int ret = wasix_context_switch(ctx_b);
180+
if (ret != -1) {
181+
exit(11);
182+
}
183+
if (errno != EINVAL) {
184+
exit(12);
185+
}
186+
// Recreate the context in the child process
187+
ret = wasix_context_create(&ctx_b, context_fn_switch_to_main);
188+
assert(ret == 0 && "Failed to create context");
189+
190+
// Now we can switch to it. Switching back to main should work too.
191+
was_in_context_fn_switch_to_main = 0;
192+
wasix_context_switch(ctx_b);
193+
assert(was_in_context_fn_switch_to_main == 1 && "Context function was not executed");
194+
195+
// exec should always bring us in a new context switching environment
196+
execl("./main.wasm", "main.wasm", "subprocess_with_switching", NULL);
197+
perror("execl");
198+
exit(10);
199+
}
200+
else
201+
{
202+
// The parent should still be in the same context switching environment
203+
was_in_context_fn_switch_to_main = 0;
204+
wasix_context_switch(ctx_b);
205+
assert(was_in_context_fn_switch_to_main == 1 && "Context function was not executed");
206+
207+
int status;
208+
waitpid(pid, &status, 0);
209+
if (WEXITSTATUS(status) != 20)
210+
{
211+
printf("Expected exit code 20 from subprocess, got %d\n", WEXITSTATUS(status));
212+
return 1;
213+
}
214+
215+
return 0;
216+
}
217+
}
218+
219+
void context_fn_that_executes_fork_and_vfork()
220+
{
221+
int pid = fork();
222+
assert(pid == -1 && "fork should fail in a context");
223+
assert(errno == ENOTSUP && "fork should return ENOTSUP in a context");
224+
pid = vfork();
225+
assert(pid == -1 && "vfork should fail in a context");
226+
assert(errno == ENOTSUP && "vfork should return ENOTSUP in a context");
227+
wasix_context_switch(wasix_context_main);
228+
assert(0 && "Should not return to this context");
229+
}
230+
231+
int fork_and_vfork_only_work_in_main_context()
232+
{
233+
wasix_context_id_t ctx;
234+
int ret = wasix_context_create(&ctx, context_fn_that_executes_fork_and_vfork);
235+
assert(ret == 0 && "Failed to create context");
236+
ret = wasix_context_switch(ctx);
237+
assert(ret == 0 && "Failed to switch to context");
238+
return 0;
239+
}
240+
241+
extern char **environ;
242+
void context_fn_posix_spawn_a_forking_subprocess_from_a_context()
243+
{
244+
int pid;
245+
int status;
246+
int exit_code;
247+
248+
// Test a subprocess that does context switching
249+
char *argV[] = {"./main.wasm", "subprocess_with_switching",(char *) 0};
250+
posix_spawn(&pid, "./main.wasm", NULL, NULL, argV, environ);
251+
waitpid(pid, &status, 0);
252+
exit_code = WEXITSTATUS(status);
253+
assert(exit_code == 20 && "Expected exit code 20 from subprocess");
254+
255+
// Test a subprocess that does fork and vfork
256+
char *argV2[] = {"./main.wasm", "subprocess_with_fork_and_vfork",(char *) 0};
257+
posix_spawn(&pid, "./main.wasm", NULL, NULL, argV2, environ);
258+
waitpid(pid, &status, 0);
259+
exit_code = WEXITSTATUS(status);
260+
assert(exit_code == 20 && "Expected exit code 20 from subprocess");
261+
262+
wasix_context_switch(wasix_context_main);
263+
assert(0 && "Should not return to this context");
264+
}
265+
266+
int posix_spawning_a_forking_subprocess_from_a_context()
267+
{
268+
wasix_context_id_t ctx;
269+
int ret = wasix_context_create(&ctx, context_fn_posix_spawn_a_forking_subprocess_from_a_context);
270+
assert(ret == 0 && "Failed to create context");
271+
ret = wasix_context_switch(ctx);
272+
assert(ret == 0 && "Failed to switch to context");
273+
return 0;
274+
}
275+
276+
int subprocess()
277+
{
278+
return 20;
279+
}
280+
281+
// Test a simple context switching scenario
282+
int subprocess_with_switching() {
283+
test_basic_switching();
284+
285+
return 20;
286+
}
287+
288+
// Test a simple context switching scenario
289+
int subprocess_with_fork_and_vfork() {
290+
vfork_after_switching2();
291+
292+
fork_after_switching();
293+
294+
return 20;
295+
}
296+
297+
int main(int argc, char **argv)
298+
{
299+
if (argc < 2)
300+
{
301+
return -1;
302+
}
303+
304+
305+
if (!strcmp(argv[1], "subprocess"))
306+
{
307+
return subprocess();
308+
}
309+
else if (!strcmp(argv[1], "subprocess_with_switching"))
310+
{
311+
return subprocess_with_switching();
312+
}
313+
else if (!strcmp(argv[1], "subprocess_with_fork_and_vfork"))
314+
{
315+
return subprocess_with_fork_and_vfork();
316+
}
317+
else if (!strcmp(argv[1], "basic_switching"))
318+
{
319+
return test_basic_switching();
320+
}
321+
else if (!strcmp(argv[1], "vfork_after_switching"))
322+
{
323+
return vfork_after_switching();
324+
}
325+
else if (!strcmp(argv[1], "vfork_after_switching2"))
326+
{
327+
return vfork_after_switching2();
328+
}
329+
else if (!strcmp(argv[1], "fork_after_switching"))
330+
{
331+
return fork_after_switching();
332+
}
333+
else if (!strcmp(argv[1], "fork_and_vfork_only_work_in_main_context"))
334+
{
335+
return fork_and_vfork_only_work_in_main_context();
336+
}
337+
else if (!strcmp(argv[1], "posix_spawning_a_forking_subprocess_from_a_context"))
338+
{
339+
return posix_spawning_a_forking_subprocess_from_a_context();
340+
}
341+
else if (!strcmp(argv[1], "fork_and_vfork_only_work_in_main_context2"))
342+
{
343+
return fork_and_vfork_only_work_in_main_context();
344+
}
345+
else if (!strcmp(argv[1], "fork_and_vfork_only_work_in_main_context2"))
346+
{
347+
return fork_and_vfork_only_work_in_main_context();
348+
}
349+
else
350+
{
351+
printf("bad command %s\n", argv[1]);
352+
return 1;
353+
}
354+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
set -e
2+
3+
$WASMER -q run main.wasm --dir . -- basic_switching
4+
$WASMER -q run main.wasm --dir . -- vfork_after_switching
5+
$WASMER -q run main.wasm --dir . -- vfork_after_switching2
6+
$WASMER -q run main.wasm --dir . -- fork_after_switching
7+
$WASMER -q run main.wasm --dir . -- fork_and_vfork_only_work_in_main_context
8+
$WASMER -q run main.wasm --dir . -- posix_spawning_a_forking_subprocess_from_a_context

0 commit comments

Comments
 (0)