1 #include <sys/types.h>
2 #include <sys/wait.h>
3 #include <assert.h>
4 #if defined(TEST_CLONE)
5 #include <sched.h>
6 #endif
7 #include <stdint.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <unistd.h>
11 
12 int g_val = 0;
13 
14 void parent_func() {
15   g_val = 1;
16   printf("function run in parent\n");
17 }
18 
19 int parent_done[2];
20 char parent_done_str[16];
21 
22 void wait_for_parent() {
23   char buf[2];
24   // wait for the parent to finish its part
25   int ret = read(parent_done[0], buf, sizeof(buf));
26   assert(ret == 2);
27   ret = close(parent_done[0]);
28   assert(ret == 0);
29 }
30 
31 int child_func(void *argv0_ptr) {
32   const char *argv0 = static_cast<char*>(argv0_ptr);
33 
34   // NB: when using vfork(), the parent may be suspended while running
35   // this function, so do not rely on any synchronization until we exec
36 #if defined(TEST_FORK)
37   if (TEST_FORK != vfork)
38 #endif
39     wait_for_parent();
40 
41   int ret = close(parent_done[1]);
42   assert(ret == 0);
43 
44   // we need to avoid memory modifications for vfork(), yet we want
45   // to be able to test watchpoints, so do the next best thing
46   // and restore the original value
47   g_val = 2;
48   g_val = 0;
49   execl(argv0, argv0, parent_done_str, NULL);
50   assert(0 && "this should not be reached");
51   return 1;
52 }
53 
54 int main(int argc, char* argv[]) {
55   alignas(uintmax_t) char stack[4096];
56   int ret;
57 
58   if (argv[1]) {
59     parent_done[0] = atoi(argv[1]);
60     assert(parent_done[0] != 0);
61 
62 #if defined(TEST_FORK)
63     // for vfork(), we need to synchronize after exec
64     if (TEST_FORK == vfork)
65       wait_for_parent();
66 #endif
67 
68     fprintf(stderr, "function run in exec'd child\n");
69     return 0;
70   }
71 
72   ret = pipe(parent_done);
73   assert(ret == 0);
74 
75   ret = snprintf(parent_done_str, sizeof(parent_done_str),
76                  "%d", parent_done[0]);
77   assert(ret != -1);
78 
79 #if defined(TEST_CLONE)
80   pid_t pid = clone(child_func, &stack[sizeof(stack)], 0, argv[0]);
81 #elif defined(TEST_FORK)
82   pid_t pid = TEST_FORK();
83   // NB: this must be equivalent to the clone() call above
84   if (pid == 0)
85     _exit(child_func(argv[0]));
86 #endif
87   assert(pid != -1);
88 
89   ret = close(parent_done[0]);
90   assert(ret == 0);
91 
92   parent_func();
93 
94   // resume the child
95   ret = write(parent_done[1], "go", 2);
96   assert(ret == 2);
97   ret = close(parent_done[1]);
98   assert(ret == 0);
99 
100   int status, wait_flags = 0;
101 #if defined(TEST_CLONE)
102   wait_flags = __WALL;
103 #endif
104   pid_t waited = waitpid(pid, &status, wait_flags);
105   assert(waited == pid);
106   assert(WIFEXITED(status));
107   assert(WEXITSTATUS(status) == 0);
108 
109   return 0;
110 }
111