| 
									
										
										
										
											2002-07-04 15:19:30 +00:00
										 |  |  | #undef G_DISABLE_ASSERT
 | 
					
						
							|  |  |  | #undef G_LOG_DOMAIN
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-03 22:13:16 +00:00
										 |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <sys/time.h>
 | 
					
						
							|  |  |  | #include <sys/resource.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <glib.h>
 | 
					
						
							|  |  |  | #include <glib-object.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int n_children = 3; | 
					
						
							|  |  |  | static int n_active_children; | 
					
						
							|  |  |  | static int n_iters = 10000; | 
					
						
							|  |  |  | static GMainLoop *loop; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | io_pipe (GIOChannel **channels) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int fds[2]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (pipe(fds) < 0) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-07-31 11:30:55 +01:00
										 |  |  |       int errsv = errno; | 
					
						
							|  |  |  |       fprintf (stderr, "Cannot create pipe %s\n", g_strerror (errsv)); | 
					
						
							| 
									
										
										
										
											2001-09-03 22:13:16 +00:00
										 |  |  |       exit (1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   channels[0] = g_io_channel_unix_new (fds[0]); | 
					
						
							|  |  |  |   channels[1] = g_io_channel_unix_new (fds[1]); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							|  |  |  | read_all (GIOChannel *channel, char *buf, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   gsize bytes_read = 0; | 
					
						
							|  |  |  |   gsize count; | 
					
						
							|  |  |  |   GIOError err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (bytes_read < len) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       err = g_io_channel_read (channel, buf + bytes_read, len - bytes_read, &count); | 
					
						
							|  |  |  |       if (err) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  if (err != G_IO_ERROR_AGAIN) | 
					
						
							|  |  |  | 	    return FALSE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       else if (count == 0) | 
					
						
							|  |  |  | 	return FALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       bytes_read += count; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return TRUE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							|  |  |  | write_all (GIOChannel *channel, char *buf, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   gsize bytes_written = 0; | 
					
						
							|  |  |  |   gsize count; | 
					
						
							|  |  |  |   GIOError err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (bytes_written < len) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       err = g_io_channel_write (channel, buf + bytes_written, len - bytes_written, &count); | 
					
						
							|  |  |  |       if (err && err != G_IO_ERROR_AGAIN) | 
					
						
							|  |  |  | 	return FALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       bytes_written += count; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return TRUE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | run_child (GIOChannel *in_channel, GIOChannel *out_channel) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int i; | 
					
						
							|  |  |  |   int val = 1; | 
					
						
							|  |  |  |   GTimer *timer = g_timer_new(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (i = 0; i < n_iters; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       write_all (out_channel, (char *)&val, sizeof (val)); | 
					
						
							|  |  |  |       read_all (in_channel, (char *)&val, sizeof (val)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   val = 0; | 
					
						
							|  |  |  |   write_all (out_channel, (char *)&val, sizeof (val)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   val = g_timer_elapsed (timer, NULL) * 1000; | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   write_all (out_channel, (char *)&val, sizeof (val)); | 
					
						
							|  |  |  |   g_timer_destroy (timer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   exit (0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static gboolean | 
					
						
							|  |  |  | input_callback (GIOChannel   *source, | 
					
						
							|  |  |  | 		GIOCondition  condition, | 
					
						
							|  |  |  | 		gpointer      data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int val; | 
					
						
							|  |  |  |   GIOChannel *dest = (GIOChannel *)data; | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   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 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       g_io_channel_close (source); | 
					
						
							|  |  |  |       g_io_channel_close (dest); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       n_active_children--; | 
					
						
							|  |  |  |       if (n_active_children == 0) | 
					
						
							|  |  |  | 	g_main_loop_quit (loop); | 
					
						
							|  |  |  |        | 
					
						
							|  |  |  |       return FALSE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2004-11-01 18:47:12 +00:00
										 |  |  | create_child (void) | 
					
						
							| 
									
										
										
										
											2001-09-03 22:13:16 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-07-31 11:30:55 +01:00
										 |  |  |   int pid, errsv; | 
					
						
							| 
									
										
										
										
											2001-09-03 22:13:16 +00:00
										 |  |  |   GIOChannel *in_channels[2]; | 
					
						
							|  |  |  |   GIOChannel *out_channels[2]; | 
					
						
							|  |  |  |   GSource *source; | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   io_pipe (in_channels); | 
					
						
							|  |  |  |   io_pipe (out_channels); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   pid = fork (); | 
					
						
							| 
									
										
										
										
											2017-07-31 11:30:55 +01:00
										 |  |  |   errsv = errno; | 
					
						
							| 
									
										
										
										
											2001-09-03 22:13:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (pid > 0)			/* Parent */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       g_io_channel_close (in_channels[0]); | 
					
						
							|  |  |  |       g_io_channel_close (out_channels[1]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       source = g_io_create_watch (out_channels[0], G_IO_IN | G_IO_HUP); | 
					
						
							|  |  |  |       g_source_set_closure (source, | 
					
						
							| 
									
										
										
										
											2013-11-10 15:57:12 +01:00
										 |  |  |                             g_cclosure_new (G_CALLBACK (input_callback), in_channels[1], | 
					
						
							|  |  |  |                                             (GClosureNotify)g_io_channel_unref)); | 
					
						
							| 
									
										
										
										
											2001-09-03 22:13:16 +00:00
										 |  |  |       g_source_attach (source, NULL); | 
					
						
							| 
									
										
										
										
											2013-11-10 15:57:12 +01:00
										 |  |  |       g_source_unref (source); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       g_io_channel_unref (in_channels[0]); | 
					
						
							|  |  |  |       g_io_channel_unref (out_channels[0]); | 
					
						
							|  |  |  |       g_io_channel_unref (out_channels[1]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-03 22:13:16 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |   else if (pid == 0)		/* Child */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       g_io_channel_close (in_channels[1]); | 
					
						
							|  |  |  |       g_io_channel_close (out_channels[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       setsid (); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       run_child (in_channels[0], out_channels[1]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   else				/* Error */ | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2017-07-31 11:30:55 +01:00
										 |  |  |       fprintf (stderr, "Cannot fork: %s\n", g_strerror (errsv)); | 
					
						
							| 
									
										
										
										
											2001-09-03 22:13:16 +00:00
										 |  |  |       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; | 
					
						
							|  |  |  |   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 (); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   getrusage (RUSAGE_SELF, &old_usage); | 
					
						
							|  |  |  |   loop = g_main_loop_new (NULL, FALSE); | 
					
						
							|  |  |  |   g_main_loop_run (loop); | 
					
						
							|  |  |  |   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)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-10 15:57:12 +01:00
										 |  |  |   g_main_loop_unref (loop); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-03 22:13:16 +00:00
										 |  |  |   return 0; | 
					
						
							|  |  |  | } |