poll.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #ifdef _WIN32
  2. #include <windows.h>
  3. static void millisleep(long ms)
  4. {
  5. Sleep((DWORD) ms);
  6. }
  7. static int getpid()
  8. {
  9. return (int) GetCurrentProcessId();
  10. }
  11. #else
  12. #define _POSIX_C_SOURCE 200809L
  13. #include <time.h>
  14. #include <unistd.h>
  15. static inline void millisleep(long ms)
  16. {
  17. nanosleep(&(struct timespec){ .tv_sec = (ms) / 1000,
  18. .tv_nsec = ((ms) % 1000L) * 1000000 },
  19. NULL);
  20. }
  21. #endif
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <reproc/reproc.h>
  25. enum { NUM_CHILDREN = 20 };
  26. static int parent(const char *program)
  27. {
  28. reproc_event_source children[NUM_CHILDREN] = { { 0 } };
  29. int r = -1;
  30. for (int i = 0; i < NUM_CHILDREN; i++) {
  31. reproc_t *process = reproc_new();
  32. const char *args[] = { program, "child", NULL };
  33. r = reproc_start(process, args, (reproc_options){ .nonblocking = true });
  34. if (r < 0) {
  35. goto finish;
  36. }
  37. children[i].process = process;
  38. children[i].interests = REPROC_EVENT_OUT;
  39. }
  40. for (;;) {
  41. r = reproc_poll(children, NUM_CHILDREN, REPROC_INFINITE);
  42. if (r < 0) {
  43. r = r == REPROC_EPIPE ? 0 : r;
  44. goto finish;
  45. }
  46. for (int i = 0; i < NUM_CHILDREN; i++) {
  47. if (children[i].process == NULL || !children[i].events) {
  48. continue;
  49. }
  50. uint8_t output[4096];
  51. r = reproc_read(children[i].process, REPROC_STREAM_OUT, output,
  52. sizeof(output));
  53. if (r == REPROC_EPIPE) {
  54. // `reproc_destroy` returns `NULL`. Event sources with their process set
  55. // to `NULL` are ignored by `reproc_poll`.
  56. children[i].process = reproc_destroy(children[i].process);
  57. continue;
  58. }
  59. if (r < 0) {
  60. goto finish;
  61. }
  62. output[r] = '\0';
  63. printf("%s\n", output);
  64. }
  65. }
  66. finish:
  67. for (int i = 0; i < NUM_CHILDREN; i++) {
  68. reproc_destroy(children[i].process);
  69. }
  70. if (r < 0) {
  71. fprintf(stderr, "%s\n", reproc_strerror(r));
  72. }
  73. return abs(r);
  74. }
  75. static int child(void)
  76. {
  77. srand(((unsigned int) getpid()));
  78. int ms = rand() % NUM_CHILDREN * 4; // NOLINT
  79. millisleep(ms);
  80. printf("Process %i slept %i milliseconds.", getpid(), ms);
  81. return EXIT_SUCCESS;
  82. }
  83. // Starts a number of child processes that each sleep a random amount of
  84. // milliseconds before printing a message and exiting. The parent process polls
  85. // each of the child processes and prints their messages to stdout.
  86. int main(int argc, const char **argv)
  87. {
  88. return argc > 1 && strcmp(argv[1], "child") == 0 ? child() : parent(argv[0]);
  89. }