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>
8f659bf00SMichał 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 
parent_func()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 
19f659bf00SMichał Górny int parent_done[2];
20f659bf00SMichał Górny char parent_done_str[16];
21f659bf00SMichał Górny 
wait_for_parent()22f659bf00SMichał Górny void wait_for_parent() {
23f659bf00SMichał Górny   char buf[2];
24f659bf00SMichał Górny   // wait for the parent to finish its part
25f659bf00SMichał Górny   int ret = read(parent_done[0], buf, sizeof(buf));
26f659bf00SMichał Górny   assert(ret == 2);
27f659bf00SMichał Górny   ret = close(parent_done[0]);
28f659bf00SMichał Górny   assert(ret == 0);
29f659bf00SMichał Górny }
30f659bf00SMichał Górny 
31*caf508d7SMichał Górny // This is the function we set breakpoint on.
child_func(const char * argv0)32*caf508d7SMichał Górny int child_func(const char *argv0) {
3363d75641SMichał Górny   // we need to avoid memory modifications for vfork(), yet we want
3463d75641SMichał Górny   // to be able to test watchpoints, so do the next best thing
3563d75641SMichał Górny   // and restore the original value
3663d75641SMichał Górny   g_val = 2;
3763d75641SMichał Górny   g_val = 0;
38f659bf00SMichał Górny   execl(argv0, argv0, parent_done_str, NULL);
39f659bf00SMichał Górny   assert(0 && "this should not be reached");
40f659bf00SMichał Górny   return 1;
41f659bf00SMichał Górny }
42f659bf00SMichał Górny 
child_top_func(void * argv0_ptr)43*caf508d7SMichał Górny int child_top_func(void *argv0_ptr) {
44*caf508d7SMichał Górny   const char *argv0 = static_cast<char*>(argv0_ptr);
45*caf508d7SMichał Górny 
46*caf508d7SMichał Górny   int ret = close(parent_done[1]);
47*caf508d7SMichał Górny   assert(ret == 0);
48*caf508d7SMichał Górny 
49*caf508d7SMichał Górny   // NB: when using vfork(), the parent may be suspended while running
50*caf508d7SMichał Górny   // this function, so do not rely on any synchronization until we exec
51*caf508d7SMichał Górny #if defined(TEST_FORK)
52*caf508d7SMichał Górny   if (TEST_FORK != vfork)
53*caf508d7SMichał Górny #endif
54*caf508d7SMichał Górny     wait_for_parent();
55*caf508d7SMichał Górny 
56*caf508d7SMichał Górny   return child_func(argv0);
57*caf508d7SMichał Górny }
58*caf508d7SMichał Górny 
main(int argc,char * argv[])59f659bf00SMichał Górny int main(int argc, char* argv[]) {
60f659bf00SMichał Górny   alignas(uintmax_t) char stack[4096];
61f659bf00SMichał Górny   int ret;
62f659bf00SMichał Górny 
63f659bf00SMichał Górny   if (argv[1]) {
64f659bf00SMichał Górny     parent_done[0] = atoi(argv[1]);
65f659bf00SMichał Górny     assert(parent_done[0] != 0);
66f659bf00SMichał Górny 
67f659bf00SMichał Górny #if defined(TEST_FORK)
68f659bf00SMichał Górny     // for vfork(), we need to synchronize after exec
69f659bf00SMichał Górny     if (TEST_FORK == vfork)
70f659bf00SMichał Górny       wait_for_parent();
71f659bf00SMichał Górny #endif
72f659bf00SMichał Górny 
73f659bf00SMichał Górny     fprintf(stderr, "function run in exec'd child\n");
7463d75641SMichał Górny     return 0;
7563d75641SMichał Górny   }
7663d75641SMichał Górny 
77f659bf00SMichał Górny   ret = pipe(parent_done);
78f659bf00SMichał Górny   assert(ret == 0);
79f659bf00SMichał Górny 
80f659bf00SMichał Górny   ret = snprintf(parent_done_str, sizeof(parent_done_str),
81f659bf00SMichał Górny                  "%d", parent_done[0]);
82f659bf00SMichał Górny   assert(ret != -1);
8363d75641SMichał Górny 
8463d75641SMichał Górny #if defined(TEST_CLONE)
85*caf508d7SMichał Górny   pid_t pid = clone(child_top_func, &stack[sizeof(stack)], 0, argv[0]);
8663d75641SMichał Górny #elif defined(TEST_FORK)
8763d75641SMichał Górny   pid_t pid = TEST_FORK();
88f659bf00SMichał Górny   // NB: this must be equivalent to the clone() call above
8963d75641SMichał Górny   if (pid == 0)
90*caf508d7SMichał Górny     _exit(child_top_func(argv[0]));
9163d75641SMichał Górny #endif
9263d75641SMichał Górny   assert(pid != -1);
9363d75641SMichał Górny 
94f659bf00SMichał Górny   ret = close(parent_done[0]);
95f659bf00SMichał Górny   assert(ret == 0);
96f659bf00SMichał Górny 
9763d75641SMichał Górny   parent_func();
98f659bf00SMichał Górny 
99f659bf00SMichał Górny   // resume the child
100f659bf00SMichał Górny   ret = write(parent_done[1], "go", 2);
101f659bf00SMichał Górny   assert(ret == 2);
102f659bf00SMichał Górny   ret = close(parent_done[1]);
103f659bf00SMichał Górny   assert(ret == 0);
104f659bf00SMichał Górny 
10563d75641SMichał Górny   int status, wait_flags = 0;
10663d75641SMichał Górny #if defined(TEST_CLONE)
10763d75641SMichał Górny   wait_flags = __WALL;
10863d75641SMichał Górny #endif
10963d75641SMichał Górny   pid_t waited = waitpid(pid, &status, wait_flags);
11063d75641SMichał Górny   assert(waited == pid);
11163d75641SMichał Górny   assert(WIFEXITED(status));
112f659bf00SMichał Górny   assert(WEXITSTATUS(status) == 0);
11363d75641SMichał Górny 
11463d75641SMichał Górny   return 0;
11563d75641SMichał Górny }
116