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