• 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 <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