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