1 #undef G_DISABLE_ASSERT 2 #undef G_LOG_DOMAIN 3 4 #include <errno.h> 5 #include <stdlib.h> 6 #include <stdio.h> 7 #include <string.h> 8 #include <unistd.h> 9 #include <sys/resource.h> 10 #include <sys/time.h> 11 #include <sys/poll.h> 12 13 #define TRUE 1 14 #define FALSE 0 15 16 static int n_children = 3; 17 static int n_active_children; 18 static int n_iters = 10000; 19 20 static int write_fds[1024]; 21 static struct pollfd poll_fds[1024]; 22 23 void 24 my_pipe (int *fds) 25 { 26 if (pipe(fds) < 0) 27 { 28 fprintf (stderr, "Cannot create pipe %s\n", strerror (errno)); 29 exit (1); 30 } 31 } 32 33 int 34 read_all (int fd, char *buf, int len) 35 { 36 size_t bytes_read = 0; 37 ssize_t count; 38 39 while (bytes_read < len) 40 { 41 count = read (fd, buf + bytes_read, len - bytes_read); 42 if (count < 0) 43 { 44 if (errno != EAGAIN) 45 return FALSE; 46 } 47 else if (count == 0) 48 return FALSE; 49 50 bytes_read += count; 51 } 52 53 return TRUE; 54 } 55 56 int 57 write_all (int fd, char *buf, int len) 58 { 59 size_t bytes_written = 0; 60 ssize_t count; 61 62 while (bytes_written < len) 63 { 64 count = write (fd, buf + bytes_written, len - bytes_written); 65 if (count < 0) 66 { 67 if (errno != EAGAIN) 68 return FALSE; 69 } 70 71 bytes_written += count; 72 } 73 74 return TRUE; 75 } 76 77 void 78 run_child (int in_fd, int out_fd) 79 { 80 int i; 81 int val = 1; 82 83 for (i = 0; i < n_iters; i++) 84 { 85 write_all (out_fd, (char *)&val, sizeof (val)); 86 read_all (in_fd, (char *)&val, sizeof (val)); 87 } 88 89 val = 0; 90 write_all (out_fd, (char *)&val, sizeof (val)); 91 92 exit (0); 93 } 94 95 int 96 input_callback (int source, int dest) 97 { 98 int val; 99 100 if (!read_all (source, (char *)&val, sizeof(val))) 101 { 102 fprintf (stderr,"Unexpected EOF\n"); 103 exit (1); 104 } 105 106 if (val) 107 { 108 write_all (dest, (char *)&val, sizeof(val)); 109 return TRUE; 110 } 111 else 112 { 113 close (source); 114 close (dest); 115 116 n_active_children--; 117 return FALSE; 118 } 119 } 120 121 void 122 create_child (int pos) 123 { 124 int pid; 125 int in_fds[2]; 126 int out_fds[2]; 127 128 my_pipe (in_fds); 129 my_pipe (out_fds); 130 131 pid = fork (); 132 133 if (pid > 0) /* Parent */ 134 { 135 close (in_fds[0]); 136 close (out_fds[1]); 137 138 write_fds[pos] = in_fds[1]; 139 poll_fds[pos].fd = out_fds[0]; 140 poll_fds[pos].events = POLLIN; 141 } 142 else if (pid == 0) /* Child */ 143 { 144 close (in_fds[1]); 145 close (out_fds[0]); 146 147 setsid (); 148 149 run_child (in_fds[0], out_fds[1]); 150 } 151 else /* Error */ 152 { 153 fprintf (stderr,"Cannot fork: %s\n", strerror (errno)); 154 exit (1); 155 } 156 } 157 158 static double 159 difftimeval (struct timeval *old, struct timeval *new) 160 { 161 return 162 (new->tv_sec - old->tv_sec) * 1000. + (new->tv_usec - old->tv_usec) / 1000; 163 } 164 165 int 166 main (int argc, char **argv) 167 { 168 int i, j; 169 struct rusage old_usage; 170 struct rusage new_usage; 171 172 if (argc > 1) 173 n_children = atoi(argv[1]); 174 175 if (argc > 2) 176 n_iters = atoi(argv[2]); 177 178 printf ("Children: %d Iters: %d\n", n_children, n_iters); 179 180 n_active_children = n_children; 181 for (i = 0; i < n_children; i++) 182 create_child (i); 183 184 getrusage (RUSAGE_SELF, &old_usage); 185 186 while (n_active_children > 0) 187 { 188 int old_n_active_children = n_active_children; 189 190 poll (poll_fds, n_active_children, -1); 191 192 for (i=0; i<n_active_children; i++) 193 { 194 if (poll_fds[i].events & (POLLIN | POLLHUP)) 195 { 196 if (!input_callback (poll_fds[i].fd, write_fds[i])) 197 write_fds[i] = -1; 198 } 199 } 200 201 if (old_n_active_children > n_active_children) 202 { 203 j = 0; 204 for (i=0; i<old_n_active_children; i++) 205 { 206 if (write_fds[i] != -1) 207 { 208 if (j < i) 209 { 210 poll_fds[j] = poll_fds[i]; 211 write_fds[j] = write_fds[i]; 212 } 213 j++; 214 } 215 } 216 } 217 } 218 219 getrusage (RUSAGE_SELF, &new_usage); 220 221 printf ("Elapsed user: %g\n", 222 difftimeval (&old_usage.ru_utime, &new_usage.ru_utime)); 223 printf ("Elapsed system: %g\n", 224 difftimeval (&old_usage.ru_stime, &new_usage.ru_stime)); 225 printf ("Elapsed total: %g\n", 226 difftimeval (&old_usage.ru_utime, &new_usage.ru_utime) + 227 difftimeval (&old_usage.ru_stime, &new_usage.ru_stime)); 228 printf ("total / iteration: %g\n", 229 (difftimeval (&old_usage.ru_utime, &new_usage.ru_utime) + 230 difftimeval (&old_usage.ru_stime, &new_usage.ru_stime)) / 231 (n_iters * n_children)); 232 233 return 0; 234 } 235 236