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