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> 8*f659bf00SMichał 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 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 19*f659bf00SMichał Górny int parent_done[2]; 20*f659bf00SMichał Górny char parent_done_str[16]; 21*f659bf00SMichał Górny 22*f659bf00SMichał Górny void wait_for_parent() { 23*f659bf00SMichał Górny char buf[2]; 24*f659bf00SMichał Górny // wait for the parent to finish its part 25*f659bf00SMichał Górny int ret = read(parent_done[0], buf, sizeof(buf)); 26*f659bf00SMichał Górny assert(ret == 2); 27*f659bf00SMichał Górny ret = close(parent_done[0]); 28*f659bf00SMichał Górny assert(ret == 0); 29*f659bf00SMichał Górny } 30*f659bf00SMichał Górny 31*f659bf00SMichał Górny int child_func(void *argv0_ptr) { 32*f659bf00SMichał Górny const char *argv0 = static_cast<char*>(argv0_ptr); 33*f659bf00SMichał Górny 34*f659bf00SMichał Górny // NB: when using vfork(), the parent may be suspended while running 35*f659bf00SMichał Górny // this function, so do not rely on any synchronization until we exec 36*f659bf00SMichał Górny #if defined(TEST_FORK) 37*f659bf00SMichał Górny if (TEST_FORK != vfork) 38*f659bf00SMichał Górny #endif 39*f659bf00SMichał Górny wait_for_parent(); 40*f659bf00SMichał Górny 41*f659bf00SMichał Górny int ret = close(parent_done[1]); 42*f659bf00SMichał Górny assert(ret == 0); 43*f659bf00SMichał Górny 4463d75641SMichał Górny // we need to avoid memory modifications for vfork(), yet we want 4563d75641SMichał Górny // to be able to test watchpoints, so do the next best thing 4663d75641SMichał Górny // and restore the original value 4763d75641SMichał Górny g_val = 2; 4863d75641SMichał Górny g_val = 0; 49*f659bf00SMichał Górny execl(argv0, argv0, parent_done_str, NULL); 50*f659bf00SMichał Górny assert(0 && "this should not be reached"); 51*f659bf00SMichał Górny return 1; 52*f659bf00SMichał Górny } 53*f659bf00SMichał Górny 54*f659bf00SMichał Górny int main(int argc, char* argv[]) { 55*f659bf00SMichał Górny alignas(uintmax_t) char stack[4096]; 56*f659bf00SMichał Górny int ret; 57*f659bf00SMichał Górny 58*f659bf00SMichał Górny if (argv[1]) { 59*f659bf00SMichał Górny parent_done[0] = atoi(argv[1]); 60*f659bf00SMichał Górny assert(parent_done[0] != 0); 61*f659bf00SMichał Górny 62*f659bf00SMichał Górny #if defined(TEST_FORK) 63*f659bf00SMichał Górny // for vfork(), we need to synchronize after exec 64*f659bf00SMichał Górny if (TEST_FORK == vfork) 65*f659bf00SMichał Górny wait_for_parent(); 66*f659bf00SMichał Górny #endif 67*f659bf00SMichał Górny 68*f659bf00SMichał Górny fprintf(stderr, "function run in exec'd child\n"); 6963d75641SMichał Górny return 0; 7063d75641SMichał Górny } 7163d75641SMichał Górny 72*f659bf00SMichał Górny ret = pipe(parent_done); 73*f659bf00SMichał Górny assert(ret == 0); 74*f659bf00SMichał Górny 75*f659bf00SMichał Górny ret = snprintf(parent_done_str, sizeof(parent_done_str), 76*f659bf00SMichał Górny "%d", parent_done[0]); 77*f659bf00SMichał Górny assert(ret != -1); 7863d75641SMichał Górny 7963d75641SMichał Górny #if defined(TEST_CLONE) 80*f659bf00SMichał Górny pid_t pid = clone(child_func, &stack[sizeof(stack)], 0, argv[0]); 8163d75641SMichał Górny #elif defined(TEST_FORK) 8263d75641SMichał Górny pid_t pid = TEST_FORK(); 83*f659bf00SMichał Górny // NB: this must be equivalent to the clone() call above 8463d75641SMichał Górny if (pid == 0) 85*f659bf00SMichał Górny _exit(child_func(argv[0])); 8663d75641SMichał Górny #endif 8763d75641SMichał Górny assert(pid != -1); 8863d75641SMichał Górny 89*f659bf00SMichał Górny ret = close(parent_done[0]); 90*f659bf00SMichał Górny assert(ret == 0); 91*f659bf00SMichał Górny 9263d75641SMichał Górny parent_func(); 93*f659bf00SMichał Górny 94*f659bf00SMichał Górny // resume the child 95*f659bf00SMichał Górny ret = write(parent_done[1], "go", 2); 96*f659bf00SMichał Górny assert(ret == 2); 97*f659bf00SMichał Górny ret = close(parent_done[1]); 98*f659bf00SMichał Górny assert(ret == 0); 99*f659bf00SMichał Górny 10063d75641SMichał Górny int status, wait_flags = 0; 10163d75641SMichał Górny #if defined(TEST_CLONE) 10263d75641SMichał Górny wait_flags = __WALL; 10363d75641SMichał Górny #endif 10463d75641SMichał Górny pid_t waited = waitpid(pid, &status, wait_flags); 10563d75641SMichał Górny assert(waited == pid); 10663d75641SMichał Górny assert(WIFEXITED(status)); 107*f659bf00SMichał Górny assert(WEXITSTATUS(status) == 0); 10863d75641SMichał Górny 10963d75641SMichał Górny return 0; 11063d75641SMichał Górny } 111