#undef G_DISABLE_ASSERT #undef G_LOG_DOMAIN #include <errno.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/resource.h> #include <sys/time.h> #include <sys/poll.h> #define TRUE 1 #define FALSE 0 static int n_children = 3; static int n_active_children; static int n_iters = 10000; static int write_fds[1024]; static struct pollfd poll_fds[1024]; void my_pipe (int *fds) { if (pipe(fds) < 0) { fprintf (stderr, "Cannot create pipe %s\n", strerror (errno)); exit (1); } } int read_all (int fd, char *buf, int len) { size_t bytes_read = 0; ssize_t count; while (bytes_read < len) { count = read (fd, buf + bytes_read, len - bytes_read); if (count < 0) { if (errno != EAGAIN) return FALSE; } else if (count == 0) return FALSE; bytes_read += count; } return TRUE; } int write_all (int fd, char *buf, int len) { size_t bytes_written = 0; ssize_t count; while (bytes_written < len) { count = write (fd, buf + bytes_written, len - bytes_written); if (count < 0) { if (errno != EAGAIN) return FALSE; } bytes_written += count; } return TRUE; } void run_child (int in_fd, int out_fd) { int i; int val = 1; for (i = 0; i < n_iters; i++) { write_all (out_fd, (char *)&val, sizeof (val)); read_all (in_fd, (char *)&val, sizeof (val)); } val = 0; write_all (out_fd, (char *)&val, sizeof (val)); exit (0); } int input_callback (int source, int dest) { int val; if (!read_all (source, (char *)&val, sizeof(val))) { fprintf (stderr,"Unexpected EOF\n"); exit (1); } if (val) { write_all (dest, (char *)&val, sizeof(val)); return TRUE; } else { close (source); close (dest); n_active_children--; return FALSE; } } void create_child (int pos) { int pid; int in_fds[2]; int out_fds[2]; my_pipe (in_fds); my_pipe (out_fds); pid = fork (); if (pid > 0) /* Parent */ { close (in_fds[0]); close (out_fds[1]); write_fds[pos] = in_fds[1]; poll_fds[pos].fd = out_fds[0]; poll_fds[pos].events = POLLIN; } else if (pid == 0) /* Child */ { close (in_fds[1]); close (out_fds[0]); setsid (); run_child (in_fds[0], out_fds[1]); } else /* Error */ { fprintf (stderr,"Cannot fork: %s\n", strerror (errno)); exit (1); } } static double difftimeval (struct timeval *old, struct timeval *new) { return (new->tv_sec - old->tv_sec) * 1000. + (new->tv_usec - old->tv_usec) / 1000; } int main (int argc, char **argv) { int i, j; struct rusage old_usage; struct rusage new_usage; if (argc > 1) n_children = atoi(argv[1]); if (argc > 2) n_iters = atoi(argv[2]); printf ("Children: %d Iters: %d\n", n_children, n_iters); n_active_children = n_children; for (i = 0; i < n_children; i++) create_child (i); getrusage (RUSAGE_SELF, &old_usage); while (n_active_children > 0) { int old_n_active_children = n_active_children; poll (poll_fds, n_active_children, -1); for (i=0; i<n_active_children; i++) { if (poll_fds[i].events & (POLLIN | POLLHUP)) { if (!input_callback (poll_fds[i].fd, write_fds[i])) write_fds[i] = -1; } } if (old_n_active_children > n_active_children) { j = 0; for (i=0; i<old_n_active_children; i++) { if (write_fds[i] != -1) { if (j < i) { poll_fds[j] = poll_fds[i]; write_fds[j] = write_fds[i]; } j++; } } } } getrusage (RUSAGE_SELF, &new_usage); printf ("Elapsed user: %g\n", difftimeval (&old_usage.ru_utime, &new_usage.ru_utime)); printf ("Elapsed system: %g\n", difftimeval (&old_usage.ru_stime, &new_usage.ru_stime)); printf ("Elapsed total: %g\n", difftimeval (&old_usage.ru_utime, &new_usage.ru_utime) + difftimeval (&old_usage.ru_stime, &new_usage.ru_stime)); printf ("total / iteration: %g\n", (difftimeval (&old_usage.ru_utime, &new_usage.ru_utime) + difftimeval (&old_usage.ru_stime, &new_usage.ru_stime)) / (n_iters * n_children)); return 0; }