• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
my_pipe(int * fds)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
read_all(int fd,char * buf,int len)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
write_all(int fd,char * buf,int len)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
run_child(int in_fd,int out_fd)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
input_callback(int source,int dest)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
create_child(int pos)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
difftimeval(struct timeval * old,struct timeval * new)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
main(int argc,char ** argv)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