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

source code of lldb/test/Shell/Subprocess/Inputs/fork.cpp