163d75641SMichał Górny #include <sys/types.h>
263d75641SMichał Górny #include <sys/wait.h>
363d75641SMichał Górny #include <assert.h>
463d75641SMichał Górny #if defined(TEST_CLONE)
563d75641SMichał Górny #include <sched.h>
663d75641SMichał Górny #endif
763d75641SMichał Górny #include <stdint.h>
8*f659bf00SMichał Górny #include <stdlib.h>
963d75641SMichał Górny #include <stdio.h>
1063d75641SMichał Górny #include <unistd.h>
1163d75641SMichał Górny 
1263d75641SMichał Górny int g_val = 0;
1363d75641SMichał Górny 
1463d75641SMichał Górny void parent_func() {
1563d75641SMichał Górny   g_val = 1;
1663d75641SMichał Górny   printf("function run in parent\n");
1763d75641SMichał Górny }
1863d75641SMichał Górny 
19*f659bf00SMichał Górny int parent_done[2];
20*f659bf00SMichał Górny char parent_done_str[16];
21*f659bf00SMichał Górny 
22*f659bf00SMichał Górny void wait_for_parent() {
23*f659bf00SMichał Górny   char buf[2];
24*f659bf00SMichał Górny   // wait for the parent to finish its part
25*f659bf00SMichał Górny   int ret = read(parent_done[0], buf, sizeof(buf));
26*f659bf00SMichał Górny   assert(ret == 2);
27*f659bf00SMichał Górny   ret = close(parent_done[0]);
28*f659bf00SMichał Górny   assert(ret == 0);
29*f659bf00SMichał Górny }
30*f659bf00SMichał Górny 
31*f659bf00SMichał Górny int child_func(void *argv0_ptr) {
32*f659bf00SMichał Górny   const char *argv0 = static_cast<char*>(argv0_ptr);
33*f659bf00SMichał Górny 
34*f659bf00SMichał Górny   // NB: when using vfork(), the parent may be suspended while running
35*f659bf00SMichał Górny   // this function, so do not rely on any synchronization until we exec
36*f659bf00SMichał Górny #if defined(TEST_FORK)
37*f659bf00SMichał Górny   if (TEST_FORK != vfork)
38*f659bf00SMichał Górny #endif
39*f659bf00SMichał Górny     wait_for_parent();
40*f659bf00SMichał Górny 
41*f659bf00SMichał Górny   int ret = close(parent_done[1]);
42*f659bf00SMichał Górny   assert(ret == 0);
43*f659bf00SMichał Górny 
4463d75641SMichał Górny   // we need to avoid memory modifications for vfork(), yet we want
4563d75641SMichał Górny   // to be able to test watchpoints, so do the next best thing
4663d75641SMichał Górny   // and restore the original value
4763d75641SMichał Górny   g_val = 2;
4863d75641SMichał Górny   g_val = 0;
49*f659bf00SMichał Górny   execl(argv0, argv0, parent_done_str, NULL);
50*f659bf00SMichał Górny   assert(0 && "this should not be reached");
51*f659bf00SMichał Górny   return 1;
52*f659bf00SMichał Górny }
53*f659bf00SMichał Górny 
54*f659bf00SMichał Górny int main(int argc, char* argv[]) {
55*f659bf00SMichał Górny   alignas(uintmax_t) char stack[4096];
56*f659bf00SMichał Górny   int ret;
57*f659bf00SMichał Górny 
58*f659bf00SMichał Górny   if (argv[1]) {
59*f659bf00SMichał Górny     parent_done[0] = atoi(argv[1]);
60*f659bf00SMichał Górny     assert(parent_done[0] != 0);
61*f659bf00SMichał Górny 
62*f659bf00SMichał Górny #if defined(TEST_FORK)
63*f659bf00SMichał Górny     // for vfork(), we need to synchronize after exec
64*f659bf00SMichał Górny     if (TEST_FORK == vfork)
65*f659bf00SMichał Górny       wait_for_parent();
66*f659bf00SMichał Górny #endif
67*f659bf00SMichał Górny 
68*f659bf00SMichał Górny     fprintf(stderr, "function run in exec'd child\n");
6963d75641SMichał Górny     return 0;
7063d75641SMichał Górny   }
7163d75641SMichał Górny 
72*f659bf00SMichał Górny   ret = pipe(parent_done);
73*f659bf00SMichał Górny   assert(ret == 0);
74*f659bf00SMichał Górny 
75*f659bf00SMichał Górny   ret = snprintf(parent_done_str, sizeof(parent_done_str),
76*f659bf00SMichał Górny                  "%d", parent_done[0]);
77*f659bf00SMichał Górny   assert(ret != -1);
7863d75641SMichał Górny 
7963d75641SMichał Górny #if defined(TEST_CLONE)
80*f659bf00SMichał Górny   pid_t pid = clone(child_func, &stack[sizeof(stack)], 0, argv[0]);
8163d75641SMichał Górny #elif defined(TEST_FORK)
8263d75641SMichał Górny   pid_t pid = TEST_FORK();
83*f659bf00SMichał Górny   // NB: this must be equivalent to the clone() call above
8463d75641SMichał Górny   if (pid == 0)
85*f659bf00SMichał Górny     _exit(child_func(argv[0]));
8663d75641SMichał Górny #endif
8763d75641SMichał Górny   assert(pid != -1);
8863d75641SMichał Górny 
89*f659bf00SMichał Górny   ret = close(parent_done[0]);
90*f659bf00SMichał Górny   assert(ret == 0);
91*f659bf00SMichał Górny 
9263d75641SMichał Górny   parent_func();
93*f659bf00SMichał Górny 
94*f659bf00SMichał Górny   // resume the child
95*f659bf00SMichał Górny   ret = write(parent_done[1], "go", 2);
96*f659bf00SMichał Górny   assert(ret == 2);
97*f659bf00SMichał Górny   ret = close(parent_done[1]);
98*f659bf00SMichał Górny   assert(ret == 0);
99*f659bf00SMichał Górny 
10063d75641SMichał Górny   int status, wait_flags = 0;
10163d75641SMichał Górny #if defined(TEST_CLONE)
10263d75641SMichał Górny   wait_flags = __WALL;
10363d75641SMichał Górny #endif
10463d75641SMichał Górny   pid_t waited = waitpid(pid, &status, wait_flags);
10563d75641SMichał Górny   assert(waited == pid);
10663d75641SMichał Górny   assert(WIFEXITED(status));
107*f659bf00SMichał Górny   assert(WEXITSTATUS(status) == 0);
10863d75641SMichał Górny 
10963d75641SMichał Górny   return 0;
11063d75641SMichał Górny }
111