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