Tizen 2.1 base
[platform/upstream/glib2.0.git] / glib / tests / spawn-multithreaded.c
1 /* 
2  * Copyright (C) 2011 Red Hat, Inc.
3  *
4  * This work is provided "as is"; redistribution and modification
5  * in whole or in part, in any medium, physical or electronic is
6  * permitted without restriction.
7  *
8  * This work is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * In no event shall the authors or contributors be liable for any
13  * direct, indirect, incidental, special, exemplary, or consequential
14  * damages (including, but not limited to, procurement of substitute
15  * goods or services; loss of use, data, or profits; or business
16  * interruption) however caused and on any theory of liability, whether
17  * in contract, strict liability, or tort (including negligence or
18  * otherwise) arising in any way out of the use of this software, even
19  * if advised of the possibility of such damage.
20  *
21  * Author: Colin Walters <walters@verbum.org> 
22  */
23
24 #include "config.h"
25
26 #include <glib.h>
27 #include <string.h>
28
29 #define N_THREADS (100)
30
31 static char *echo_prog_path;
32
33 static void
34 multithreaded_test_run (GThreadFunc function)
35 {
36   int i;
37   GPtrArray *threads = g_ptr_array_new ();
38
39   for (i = 0; i < N_THREADS; i++)
40     {
41       GThread *thread;
42
43       thread = g_thread_new ("test", function, GINT_TO_POINTER (i));
44       g_ptr_array_add (threads, thread);
45     }
46
47   for (i = 0; i < N_THREADS; i++)
48     {
49       gpointer ret;
50       ret = g_thread_join (g_ptr_array_index (threads, i));
51       g_assert_cmpint (GPOINTER_TO_INT (ret), ==, i);
52     }
53   g_ptr_array_free (threads, TRUE);
54 }
55
56 static gpointer
57 test_spawn_sync_multithreaded_instance (gpointer data)
58 {
59   int tnum = GPOINTER_TO_INT (data);
60   GError *error = NULL;
61   GPtrArray *argv;
62   char *arg;
63   char *stdout_str;
64   int estatus;
65
66   arg = g_strdup_printf ("thread %d", tnum);
67
68   argv = g_ptr_array_new ();
69   g_ptr_array_add (argv, echo_prog_path);
70   g_ptr_array_add (argv, arg);
71   g_ptr_array_add (argv, NULL);
72
73   g_spawn_sync (NULL, (char**)argv->pdata, NULL, 0, NULL, NULL, &stdout_str, NULL, &estatus, &error);
74   g_assert_no_error (error);
75   g_assert_cmpstr (arg, ==, stdout_str);
76   g_free (arg);
77   g_free (stdout_str);
78   g_ptr_array_free (argv, TRUE);
79
80   return GINT_TO_POINTER (tnum);
81 }
82
83 static void
84 test_spawn_sync_multithreaded (void)
85 {
86   multithreaded_test_run (test_spawn_sync_multithreaded_instance);
87 }
88
89 typedef struct {
90   GMainLoop *loop;
91   gboolean child_exited;
92   gboolean stdout_done;
93   GString *stdout_buf;
94 } SpawnAsyncMultithreadedData;
95
96 static gboolean
97 on_child_exited (GPid     pid,
98                  gint     status,
99                  gpointer datap)
100 {
101   SpawnAsyncMultithreadedData *data = datap;
102
103   data->child_exited = TRUE;
104   if (data->child_exited && data->stdout_done)
105     g_main_loop_quit (data->loop);
106   
107   return G_SOURCE_REMOVE;
108 }
109
110 static gboolean
111 on_child_stdout (GIOChannel   *channel,
112                  GIOCondition  condition,
113                  gpointer      datap)
114 {
115   char buf[1024];
116   GError *error = NULL;
117   gsize bytes_read;
118   GIOStatus status;
119   SpawnAsyncMultithreadedData *data = datap;
120
121  read:
122   status = g_io_channel_read_chars (channel, buf, sizeof (buf), &bytes_read, &error);
123   if (status == G_IO_STATUS_NORMAL)
124     {
125       g_string_append_len (data->stdout_buf, buf, (gssize) bytes_read);
126       if (bytes_read == sizeof (buf))
127         goto read;
128     }
129   else if (status == G_IO_STATUS_EOF)
130     {
131       g_string_append_len (data->stdout_buf, buf, (gssize) bytes_read);
132       data->stdout_done = TRUE;
133     }
134   else if (status == G_IO_STATUS_ERROR)
135     {
136       g_error ("Error reading from child stdin: %s", error->message);
137     }
138
139   if (data->child_exited && data->stdout_done)
140     g_main_loop_quit (data->loop);
141
142   return !data->stdout_done;
143 }
144
145 static gpointer
146 test_spawn_async_multithreaded_instance (gpointer thread_data)
147 {
148   int tnum = GPOINTER_TO_INT (thread_data);
149   GError *error = NULL;
150   GPtrArray *argv;
151   char *arg;
152   GPid pid;
153   GMainContext *context;
154   GMainLoop *loop;
155   GIOChannel *channel;
156   GSource *source;
157   int child_stdout_fd;
158   SpawnAsyncMultithreadedData data;
159
160   context = g_main_context_new ();
161   loop = g_main_loop_new (context, TRUE);
162
163   arg = g_strdup_printf ("thread %d", tnum);
164
165   argv = g_ptr_array_new ();
166   g_ptr_array_add (argv, echo_prog_path);
167   g_ptr_array_add (argv, arg);
168   g_ptr_array_add (argv, NULL);
169
170   g_spawn_async_with_pipes (NULL, (char**)argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, NULL,
171                             &child_stdout_fd, NULL, &error);
172   g_assert_no_error (error);
173   g_ptr_array_free (argv, TRUE);
174
175   data.loop = loop;
176   data.stdout_done = FALSE;
177   data.child_exited = FALSE;
178   data.stdout_buf = g_string_new (0);
179
180   source = g_child_watch_source_new (pid);
181   g_source_set_callback (source, (GSourceFunc)on_child_exited, &data, NULL);
182   g_source_attach (source, context);
183   g_source_unref (source);
184
185   channel = g_io_channel_unix_new (child_stdout_fd);
186   source = g_io_create_watch (channel, G_IO_IN | G_IO_HUP);
187   g_source_set_callback (source, (GSourceFunc)on_child_stdout, &data, NULL);
188   g_source_attach (source, context);
189   g_source_unref (source);
190
191   g_main_loop_run (loop);
192
193   g_assert (data.child_exited);
194   g_assert (data.stdout_done);
195   g_assert_cmpstr (data.stdout_buf->str, ==, arg);
196   g_string_free (data.stdout_buf, TRUE);
197
198   g_io_channel_unref (channel);
199   g_main_context_unref (context);
200   g_main_loop_unref (loop);
201
202   g_free (arg);
203
204   return GINT_TO_POINTER (tnum);
205 }
206
207 static void
208 test_spawn_async_multithreaded (void)
209 {
210   multithreaded_test_run (test_spawn_async_multithreaded_instance);
211 }
212
213 int
214 main (int   argc,
215       char *argv[])
216 {
217   char *dirname;
218
219   g_test_init (&argc, &argv, NULL);
220
221   dirname = g_path_get_dirname (argv[0]);
222   echo_prog_path = g_build_filename (dirname, "test-spawn-echo", NULL);
223   if (!g_file_test (echo_prog_path, G_FILE_TEST_EXISTS))
224     {
225       g_free (echo_prog_path);
226       echo_prog_path = g_build_filename (dirname, "lt-test-spawn-echo", NULL);
227     }
228   g_free (dirname);
229
230   g_assert (g_file_test (echo_prog_path, G_FILE_TEST_EXISTS));
231
232   g_test_add_func ("/gthread/spawn-sync", test_spawn_sync_multithreaded);
233   g_test_add_func ("/gthread/spawn-async", test_spawn_async_multithreaded);
234
235   return g_test_run();
236 }