brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.0 KiB · d72051e Raw
108 lines · cpp
1#include <assert.h>2#include <cstring>3#include <iostream>4#include <mutex>5#include <string.h>6#include <sys/wait.h>7#include <thread>8#include <unistd.h>9#include <vector>10 11pid_t g_pid = 0;12std::mutex g_child_pids_mutex;13std::vector<pid_t> g_child_pids;14 15const char *g_program = nullptr;16bool g_use_vfork = true;  // Use vfork by default.17bool g_call_exec = false; // Does not call exec by default.18 19int call_vfork(int index) {20  pid_t child_pid = 0;21  if (g_use_vfork) {22    child_pid = vfork();23  } else {24    child_pid = fork();25  }26 27  if (child_pid == -1) {28    // Error handling29    perror("vfork");30    return 1;31  } else if (child_pid == 0) {32    // This code is executed by the child process33    g_pid = getpid();34    printf("Child process: %d\n", g_pid);35 36    if (g_call_exec) {37      std::string child_exit_code = std::to_string(index + 10);38      execl(g_program, g_program, "--child", child_exit_code.c_str(), NULL);39    } else {40      _exit(index + 10);41    }42  } else {43    // This code is executed by the parent process44    printf("[Parent] Forked process id: %d\n", child_pid);45  }46  return 0;47}48 49void wait_all_children_to_exit() {50  std::lock_guard<std::mutex> Lock(g_child_pids_mutex);51  for (pid_t child_pid : g_child_pids) {52    int child_status = 0;53    pid_t pid = waitpid(child_pid, &child_status, 0);54    if (child_status != 0) {55      int exit_code = WEXITSTATUS(child_status);56      if (exit_code > 15 || exit_code < 10) {57        printf("Error: child process exits with unexpected code %d\n",58               exit_code);59        _exit(1); // This will let our program know that some child processes60                  // didn't exist with an expected exit status.61      }62    }63    if (pid != child_pid)64      _exit(2); // This will let our program know it didn't succeed65  }66}67 68void create_threads(int num_threads) {69  std::vector<std::thread> threads;70  for (int i = 0; i < num_threads; ++i) {71    threads.emplace_back(std::thread(call_vfork, i));72  }73  printf("Created %d threads, joining...\n",74         num_threads); // end_of_create_threads75  for (auto &thread : threads) {76    thread.join();77  }78  wait_all_children_to_exit();79}80 81// Can be called in various ways:82// 1. [program]: use vfork and not call exec83// 2. [program] --fork: use fork and not call exec84// 3. [program] --fork --exec: use fork and call exec85// 4. [program] --exec: use vfork and call exec86// 5. [program] --child [exit_code]: child process87int main(int argc, char *argv[]) {88  g_pid = getpid();89  g_program = argv[0];90 91  for (int i = 1; i < argc; ++i) {92    if (strcmp(argv[i], "--child") == 0) {93      assert(i + 1 < argc);94      int child_exit_code = std::stoi(argv[i + 1]);95      printf("Child process: %d, exiting with code %d\n", g_pid,96             child_exit_code);97      _exit(child_exit_code);98    } else if (strcmp(argv[i], "--fork") == 0)99      g_use_vfork = false;100    else if (strcmp(argv[i], "--exec") == 0)101      g_call_exec = true;102  }103 104  int num_threads = 5; // break here105  create_threads(num_threads);106  return 0;107}108