#include #include #include #include #include #include #include #include #include #include #include #define log(...) fprintf(stderr, __VA_ARGS__) #define WATCHER "watcher" static struct proc { uint64_t deadline; char filename[32 - sizeof(uint64_t)]; } procs[NPROC]; static pid_t spawn_watcher(char *filename) { char *argv[3] = { WATCHER, filename, NULL }; pid_t pid; pid = fork(); if (pid == 0) { if (execv(WATCHER, argv)) { log("Error spawning '%s': %s\n", WATCHER, strerror(errno)); exit(EXIT_FAILURE); } } if (pid < 0) log("Error forking: %s\n", strerror(errno)); return pid; } static int touch(char *filename, int flags) { int fd = open(filename, flags, 0644); if (fd < 0 || close(fd)) { log("Error touching '%s': %s\n", filename, strerror(errno)); return -1; } return 0; } static uint64_t now(void) { struct timeval tv; (void)gettimeofday(&tv, NULL); return ((uint64_t)tv.tv_sec * 1000000) + (uint64_t)tv.tv_usec; } static uint64_t random_delay(void) { return (uint64_t)DELAY_MIN + (random() / (RAND_MAX/(DELAY_MAX - DELAY_MIN))); } int main() { unsigned int i; struct proc *next; if (signal(SIGCHLD, SIG_IGN)) { log("Error setting SIGCHLD handler: %s\n", strerror(errno)); return EXIT_FAILURE; } for (i = 0; i < NPROC; i++) { (void)sprintf(procs[i].filename, "%03u.tmp", i); if (touch(procs[i].filename, O_WRONLY | O_CREAT)) { log("Error creating file '%s': %s\n", procs[i].filename, strerror(errno)); return EXIT_FAILURE; } } next = &procs[0]; for (i = 0; i < NPROC; i++) { if (spawn_watcher(procs[i].filename) < 0) goto error; procs[i].deadline = now() + random_delay(); if (procs[i].deadline < next->deadline) next = &procs[i]; } while (1) { uint64_t n = now(); if (next->deadline > n) { usleep(next->deadline - n); continue; } if (touch(next->filename, O_WRONLY)) goto error; if (spawn_watcher(next->filename) < 0) goto error; next->deadline = now() + random_delay(); for (i = 0; i < NPROC; i++) { if (procs[i].deadline < next->deadline) next = &procs[i]; } } error: for (i = 0; i < NPROC; i++) (void)touch(procs[i].filename, O_WRONLY); return EXIT_FAILURE; }