Merge remote-tracking branch 'gvdb/master'
[platform/upstream/glib.git] / glib / tests / spawn-singlethread.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 static char *echo_prog_path;
30
31 typedef struct {
32   GMainLoop *loop;
33   gboolean child_exited;
34   gboolean stdout_done;
35   GString *stdout_buf;
36 } SpawnAsyncMultithreadedData;
37
38 static gboolean
39 on_child_exited (GPid     pid,
40                  gint     status,
41                  gpointer datap)
42 {
43   SpawnAsyncMultithreadedData *data = datap;
44
45   data->child_exited = TRUE;
46   if (data->child_exited && data->stdout_done)
47     g_main_loop_quit (data->loop);
48   
49   return FALSE;
50 }
51
52 static gboolean
53 on_child_stdout (GIOChannel   *channel,
54                  GIOCondition  condition,
55                  gpointer      datap)
56 {
57   char buf[1024];
58   GError *error = NULL;
59   gsize bytes_read;
60   SpawnAsyncMultithreadedData *data = datap;
61
62   if (condition & G_IO_IN)
63     {
64       GIOStatus status;
65       status = g_io_channel_read_chars (channel, buf, sizeof (buf), &bytes_read, &error);
66       g_assert_no_error (error);
67       g_string_append_len (data->stdout_buf, buf, (gssize) bytes_read);
68       if (status == G_IO_STATUS_EOF)
69         data->stdout_done = TRUE;
70     }
71   if (condition & G_IO_HUP)
72     data->stdout_done = TRUE;
73   if (condition & G_IO_ERR)
74     g_error ("Error reading from child stdin");
75
76   if (data->child_exited && data->stdout_done)
77     g_main_loop_quit (data->loop);
78
79   return !data->stdout_done;
80 }
81
82 static void
83 test_spawn_async (void)
84 {
85   int tnum = 1;
86   GError *error = NULL;
87   GPtrArray *argv;
88   char *arg;
89   GPid pid;
90   GMainContext *context;
91   GMainLoop *loop;
92   GIOChannel *channel;
93   GSource *source;
94   int child_stdout_fd;
95   SpawnAsyncMultithreadedData data;
96
97   context = g_main_context_new ();
98   loop = g_main_loop_new (context, TRUE);
99
100   arg = g_strdup_printf ("thread %d", tnum);
101
102   argv = g_ptr_array_new ();
103   g_ptr_array_add (argv, echo_prog_path);
104   g_ptr_array_add (argv, arg);
105   g_ptr_array_add (argv, NULL);
106
107   g_spawn_async_with_pipes (NULL, (char**)argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, NULL,
108                             &child_stdout_fd, NULL, &error);
109   g_assert_no_error (error);
110   g_ptr_array_free (argv, TRUE);
111
112   data.loop = loop;
113   data.stdout_done = FALSE;
114   data.child_exited = FALSE;
115   data.stdout_buf = g_string_new (0);
116
117   source = g_child_watch_source_new (pid);
118   g_source_set_callback (source, (GSourceFunc)on_child_exited, &data, NULL);
119   g_source_attach (source, context);
120   g_source_unref (source);
121
122   channel = g_io_channel_unix_new (child_stdout_fd);
123   source = g_io_create_watch (channel, G_IO_IN | G_IO_HUP | G_IO_ERR);
124   g_source_set_callback (source, (GSourceFunc)on_child_stdout, &data, NULL);
125   g_source_attach (source, context);
126   g_source_unref (source);
127
128   g_main_loop_run (loop);
129
130   g_assert (data.child_exited);
131   g_assert (data.stdout_done);
132   g_assert_cmpstr (data.stdout_buf->str, ==, arg);
133   g_string_free (data.stdout_buf, TRUE);
134
135   g_io_channel_unref (channel);
136   g_main_context_unref (context);
137   g_main_loop_unref (loop);
138
139   g_free (arg);
140 }
141
142 static void
143 test_spawn_sync (void)
144 {
145   int tnum = 1;
146   GError *error = NULL;
147   GPtrArray *argv;
148   char *arg;
149   char *stdout_str;
150   int estatus;
151
152   arg = g_strdup_printf ("thread %d", tnum);
153
154   argv = g_ptr_array_new ();
155   g_ptr_array_add (argv, echo_prog_path);
156   g_ptr_array_add (argv, arg);
157   g_ptr_array_add (argv, NULL);
158
159   g_spawn_sync (NULL, (char**)argv->pdata, NULL, 0, NULL, NULL, &stdout_str, NULL, &estatus, &error);
160   g_assert_no_error (error);
161   g_assert_cmpstr (arg, ==, stdout_str);
162   g_free (arg);
163   g_free (stdout_str);
164   g_ptr_array_free (argv, TRUE);
165 }
166
167 int
168 main (int   argc,
169       char *argv[])
170 {
171   char *dirname;
172
173   g_test_init (&argc, &argv, NULL);
174
175   dirname = g_path_get_dirname (argv[0]);
176   echo_prog_path = g_build_filename (dirname, "test-spawn-echo", NULL);
177   if (!g_file_test (echo_prog_path, G_FILE_TEST_EXISTS))
178     {
179       g_free (echo_prog_path);
180       echo_prog_path = g_build_filename (dirname, "lt-test-spawn-echo", NULL);
181     }
182   g_free (dirname);
183
184   g_assert (g_file_test (echo_prog_path, G_FILE_TEST_EXISTS));
185
186   g_test_add_func ("/gthread/spawn-single-sync", test_spawn_sync);
187   g_test_add_func ("/gthread/spawn-single-async", test_spawn_async);
188
189   return g_test_run();
190 }