1 #undef G_DISABLE_ASSERT 2 #undef G_LOG_DOMAIN 3 4 #include <errno.h> 5 #include <stdlib.h> 6 #include <unistd.h> 7 #include <stdio.h> 8 #include <sys/time.h> 9 #include <sys/resource.h> 10 11 #include <glib.h> 12 #include <glib-object.h> 13 14 static int n_children = 3; 15 static int n_active_children; 16 static int n_iters = 10000; 17 static GMainLoop *loop; 18 19 static void 20 io_pipe (GIOChannel **channels) 21 { 22 int fds[2]; 23 24 if (pipe(fds) < 0) 25 { 26 fprintf (stderr, "Cannot create pipe %s\n", g_strerror (errno)); 27 exit (1); 28 } 29 30 channels[0] = g_io_channel_unix_new (fds[0]); 31 channels[1] = g_io_channel_unix_new (fds[1]); 32 } 33 34 static gboolean 35 read_all (GIOChannel *channel, char *buf, int len) 36 { 37 gsize bytes_read = 0; 38 gsize count; 39 GIOError err; 40 41 while (bytes_read < len) 42 { 43 err = g_io_channel_read (channel, buf + bytes_read, len - bytes_read, &count); 44 if (err) 45 { 46 if (err != G_IO_ERROR_AGAIN) 47 return FALSE; 48 } 49 else if (count == 0) 50 return FALSE; 51 52 bytes_read += count; 53 } 54 55 return TRUE; 56 } 57 58 static gboolean 59 write_all (GIOChannel *channel, char *buf, int len) 60 { 61 gsize bytes_written = 0; 62 gsize count; 63 GIOError err; 64 65 while (bytes_written < len) 66 { 67 err = g_io_channel_write (channel, buf + bytes_written, len - bytes_written, &count); 68 if (err && err != G_IO_ERROR_AGAIN) 69 return FALSE; 70 71 bytes_written += count; 72 } 73 74 return TRUE; 75 } 76 77 static void 78 run_child (GIOChannel *in_channel, GIOChannel *out_channel) 79 { 80 int i; 81 int val = 1; 82 GTimer *timer = g_timer_new(); 83 84 for (i = 0; i < n_iters; i++) 85 { 86 write_all (out_channel, (char *)&val, sizeof (val)); 87 read_all (in_channel, (char *)&val, sizeof (val)); 88 } 89 90 val = 0; 91 write_all (out_channel, (char *)&val, sizeof (val)); 92 93 val = g_timer_elapsed (timer, NULL) * 1000; 94 95 write_all (out_channel, (char *)&val, sizeof (val)); 96 g_timer_destroy (timer); 97 98 exit (0); 99 } 100 101 static gboolean 102 input_callback (GIOChannel *source, 103 GIOCondition condition, 104 gpointer data) 105 { 106 int val; 107 GIOChannel *dest = (GIOChannel *)data; 108 109 if (!read_all (source, (char *)&val, sizeof(val))) 110 { 111 fprintf (stderr, "Unexpected EOF\n"); 112 exit (1); 113 } 114 115 if (val) 116 { 117 write_all (dest, (char *)&val, sizeof(val)); 118 119 return TRUE; 120 } 121 else 122 { 123 g_io_channel_close (source); 124 g_io_channel_close (dest); 125 126 g_io_channel_unref (source); 127 g_io_channel_unref (dest); 128 129 n_active_children--; 130 if (n_active_children == 0) 131 g_main_loop_quit (loop); 132 133 return FALSE; 134 } 135 } 136 137 static void 138 create_child (void) 139 { 140 int pid; 141 GIOChannel *in_channels[2]; 142 GIOChannel *out_channels[2]; 143 GSource *source; 144 145 io_pipe (in_channels); 146 io_pipe (out_channels); 147 148 pid = fork (); 149 150 if (pid > 0) /* Parent */ 151 { 152 g_io_channel_close (in_channels[0]); 153 g_io_channel_close (out_channels[1]); 154 155 source = g_io_create_watch (out_channels[0], G_IO_IN | G_IO_HUP); 156 g_source_set_closure (source, 157 g_cclosure_new (G_CALLBACK (input_callback), in_channels[1], NULL)); 158 g_source_attach (source, NULL); 159 } 160 else if (pid == 0) /* Child */ 161 { 162 g_io_channel_close (in_channels[1]); 163 g_io_channel_close (out_channels[0]); 164 165 setsid (); 166 167 run_child (in_channels[0], out_channels[1]); 168 } 169 else /* Error */ 170 { 171 fprintf (stderr, "Cannot fork: %s\n", g_strerror (errno)); 172 exit (1); 173 } 174 } 175 176 static double 177 difftimeval (struct timeval *old, struct timeval *new) 178 { 179 return 180 (new->tv_sec - old->tv_sec) * 1000. + (new->tv_usec - old->tv_usec) / 1000; 181 } 182 183 int 184 main (int argc, char **argv) 185 { 186 int i; 187 struct rusage old_usage; 188 struct rusage new_usage; 189 190 g_type_init (); 191 192 if (argc > 1) 193 n_children = atoi(argv[1]); 194 195 if (argc > 2) 196 n_iters = atoi(argv[2]); 197 198 printf ("Children: %d Iters: %d\n", n_children, n_iters); 199 200 n_active_children = n_children; 201 for (i = 0; i < n_children; i++) 202 create_child (); 203 204 getrusage (RUSAGE_SELF, &old_usage); 205 loop = g_main_loop_new (NULL, FALSE); 206 g_main_loop_run (loop); 207 getrusage (RUSAGE_SELF, &new_usage); 208 209 printf ("Elapsed user: %g\n", 210 difftimeval (&old_usage.ru_utime, &new_usage.ru_utime)); 211 printf ("Elapsed system: %g\n", 212 difftimeval (&old_usage.ru_stime, &new_usage.ru_stime)); 213 printf ("Elapsed total: %g\n", 214 difftimeval (&old_usage.ru_utime, &new_usage.ru_utime) + 215 difftimeval (&old_usage.ru_stime, &new_usage.ru_stime)); 216 printf ("total / iteration: %g\n", 217 (difftimeval (&old_usage.ru_utime, &new_usage.ru_utime) + 218 difftimeval (&old_usage.ru_stime, &new_usage.ru_stime)) / 219 (n_iters * n_children)); 220 221 return 0; 222 } 223