Home | History | Annotate | Download | only in tests
      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