mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-10-31 08:22:16 +01:00 
			
		
		
		
	POSIX specifies that <poll.h> is the correct header to include for poll(), so let's do that instead. https://bugzilla.gnome.org/show_bug.cgi?id=141251
		
			
				
	
	
		
			236 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			236 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #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;
 | |
| }
 | |
| 
 |