nexmon – Rev 1

Subversion Repositories:
Rev:
#undef G_DISABLE_ASSERT
#undef G_LOG_DOMAIN

#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <poll.h>

#define TRUE 1
#define FALSE 0

static int n_children = 3;
static int n_active_children;
static int n_iters = 10000;

static int write_fds[1024];
static struct pollfd poll_fds[1024];

void
my_pipe (int *fds)
{
  if (pipe(fds) < 0)
    {
      fprintf (stderr, "Cannot create pipe %s\n", strerror (errno));
      exit (1);
    }
}

int
read_all (int fd, char *buf, int len)
{
  size_t bytes_read = 0;
  ssize_t count;

  while (bytes_read < len)
    {
      count = read (fd, buf + bytes_read, len - bytes_read);
      if (count < 0)
        {
          if (errno != EAGAIN)
            return FALSE;
        }
      else if (count == 0)
        return FALSE;

      bytes_read += count;
    }

  return TRUE;
}

int
write_all (int fd, char *buf, int len)
{
  size_t bytes_written = 0;
  ssize_t count;

  while (bytes_written < len)
    {
      count = write (fd, buf + bytes_written, len - bytes_written);
      if (count < 0)
        {
          if (errno != EAGAIN)
            return FALSE;
        }

      bytes_written += count;
    }

  return TRUE;
}

void
run_child (int in_fd, int out_fd)
{
  int i;
  int val = 1;

  for (i = 0; i < n_iters; i++)
    {
      write_all (out_fd, (char *)&val, sizeof (val));
      read_all (in_fd, (char *)&val, sizeof (val));
    }

  val = 0;
  write_all (out_fd, (char *)&val, sizeof (val));

  exit (0);
}

int
input_callback (int source, int dest)
{
  int val;
  
  if (!read_all (source, (char *)&val, sizeof(val)))
    {
      fprintf (stderr,"Unexpected EOF\n");
      exit (1);
    }

  if (val)
    {
      write_all (dest, (char *)&val, sizeof(val));
      return TRUE;
    }
  else
    {
      close (source);
      close (dest);
      
      n_active_children--;
      return FALSE;
    }
}

void
create_child (int pos)
{
  int pid;
  int in_fds[2];
  int out_fds[2];
  
  my_pipe (in_fds);
  my_pipe (out_fds);

  pid = fork ();

  if (pid > 0)                  /* Parent */
    {
      close (in_fds[0]);
      close (out_fds[1]);

      write_fds[pos] = in_fds[1];
      poll_fds[pos].fd = out_fds[0];
      poll_fds[pos].events = POLLIN;
    }
  else if (pid == 0)            /* Child */
    {
      close (in_fds[1]);
      close (out_fds[0]);

      setsid ();

      run_child (in_fds[0], out_fds[1]);
    }
  else                          /* Error */
    {
      fprintf (stderr,"Cannot fork: %s\n", strerror (errno));
      exit (1);
    }
}

static double 
difftimeval (struct timeval *old, struct timeval *new)
{
  return
    (new->tv_sec - old->tv_sec) * 1000. + (new->tv_usec - old->tv_usec) / 1000;
}

int 
main (int argc, char **argv)
{
  int i, j;
  struct rusage old_usage;
  struct rusage new_usage;
  
  if (argc > 1)
    n_children = atoi(argv[1]);

  if (argc > 2)
    n_iters = atoi(argv[2]);

  printf ("Children: %d     Iters: %d\n", n_children, n_iters);

  n_active_children = n_children;
  for (i = 0; i < n_children; i++)
    create_child (i);

  getrusage (RUSAGE_SELF, &old_usage);

  while (n_active_children > 0)
    {
      int old_n_active_children = n_active_children;

      poll (poll_fds, n_active_children, -1);

      for (i=0; i<n_active_children; i++)
        {
          if (poll_fds[i].events & (POLLIN | POLLHUP))
            {
              if (!input_callback (poll_fds[i].fd, write_fds[i]))
                write_fds[i] = -1;
            }
        }

      if (old_n_active_children > n_active_children)
        {
          j = 0;
          for (i=0; i<old_n_active_children; i++)
            {
              if (write_fds[i] != -1)
                {
                  if (j < i)
                    {
                      poll_fds[j] = poll_fds[i];
                      write_fds[j] = write_fds[i];
                    }
                  j++;
                }
            }
        }
    }

  getrusage (RUSAGE_SELF, &new_usage);

  printf ("Elapsed user: %g\n",
           difftimeval (&old_usage.ru_utime, &new_usage.ru_utime));
  printf ("Elapsed system: %g\n",
           difftimeval (&old_usage.ru_stime, &new_usage.ru_stime));
  printf ("Elapsed total: %g\n",
          difftimeval (&old_usage.ru_utime, &new_usage.ru_utime) +         
           difftimeval (&old_usage.ru_stime, &new_usage.ru_stime));
  printf ("total / iteration: %g\n",
           (difftimeval (&old_usage.ru_utime, &new_usage.ru_utime) +       
            difftimeval (&old_usage.ru_stime, &new_usage.ru_stime)) /
           (n_iters * n_children));

  return 0;
}