• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-unix.h"
27 #include <string.h>
28 
29 static void
test_pipe(void)30 test_pipe (void)
31 {
32   GError *error = NULL;
33   int pipefd[2];
34   char buf[1024];
35   gssize bytes_read;
36   gboolean res;
37 
38   res = g_unix_open_pipe (pipefd, FD_CLOEXEC, &error);
39   g_assert (res);
40   g_assert_no_error (error);
41 
42   write (pipefd[1], "hello", sizeof ("hello"));
43   memset (buf, 0, sizeof (buf));
44   bytes_read = read (pipefd[0], buf, sizeof(buf) - 1);
45   g_assert_cmpint (bytes_read, >, 0);
46   buf[bytes_read] = '\0';
47 
48   close (pipefd[0]);
49   close (pipefd[1]);
50 
51   g_assert (g_str_has_prefix (buf, "hello"));
52 }
53 
54 static void
test_error(void)55 test_error (void)
56 {
57   GError *error = NULL;
58   gboolean res;
59 
60   res = g_unix_set_fd_nonblocking (123456, TRUE, &error);
61   g_assert_cmpint (errno, ==, EBADF);
62   g_assert (!res);
63   g_assert_error (error, G_UNIX_ERROR, 0);
64   g_clear_error (&error);
65 }
66 
67 static void
test_nonblocking(void)68 test_nonblocking (void)
69 {
70   GError *error = NULL;
71   int pipefd[2];
72   gboolean res;
73   int flags;
74 
75   res = g_unix_open_pipe (pipefd, FD_CLOEXEC, &error);
76   g_assert (res);
77   g_assert_no_error (error);
78 
79   res = g_unix_set_fd_nonblocking (pipefd[0], TRUE, &error);
80   g_assert (res);
81   g_assert_no_error (error);
82 
83   flags = fcntl (pipefd[0], F_GETFL);
84   g_assert_cmpint (flags, !=, -1);
85   g_assert (flags & O_NONBLOCK);
86 
87   res = g_unix_set_fd_nonblocking (pipefd[0], FALSE, &error);
88   g_assert (res);
89   g_assert_no_error (error);
90 
91   flags = fcntl (pipefd[0], F_GETFL);
92   g_assert_cmpint (flags, !=, -1);
93   g_assert (!(flags & O_NONBLOCK));
94 
95   close (pipefd[0]);
96   close (pipefd[1]);
97 }
98 
99 static gboolean sig_received = FALSE;
100 static gboolean sig_timeout = FALSE;
101 static int sig_counter = 0;
102 
103 static gboolean
on_sig_received(gpointer user_data)104 on_sig_received (gpointer user_data)
105 {
106   GMainLoop *loop = user_data;
107   g_main_loop_quit (loop);
108   sig_received = TRUE;
109   sig_counter ++;
110   return G_SOURCE_REMOVE;
111 }
112 
113 static gboolean
on_sig_timeout(gpointer data)114 on_sig_timeout (gpointer data)
115 {
116   GMainLoop *loop = data;
117   g_main_loop_quit (loop);
118   sig_timeout = TRUE;
119   return G_SOURCE_REMOVE;
120 }
121 
122 static gboolean
exit_mainloop(gpointer data)123 exit_mainloop (gpointer data)
124 {
125   GMainLoop *loop = data;
126   g_main_loop_quit (loop);
127   return G_SOURCE_REMOVE;
128 }
129 
130 static gboolean
on_sig_received_2(gpointer data)131 on_sig_received_2 (gpointer data)
132 {
133   GMainLoop *loop = data;
134 
135   sig_counter ++;
136   if (sig_counter == 2)
137     g_main_loop_quit (loop);
138   return G_SOURCE_REMOVE;
139 }
140 
141 static void
test_signal(int signum)142 test_signal (int signum)
143 {
144   GMainLoop *mainloop;
145   int id;
146 
147   mainloop = g_main_loop_new (NULL, FALSE);
148 
149   sig_received = FALSE;
150   sig_counter = 0;
151   g_unix_signal_add (signum, on_sig_received, mainloop);
152   kill (getpid (), signum);
153   g_assert (!sig_received);
154   id = g_timeout_add (5000, on_sig_timeout, mainloop);
155   g_main_loop_run (mainloop);
156   g_assert (sig_received);
157   sig_received = FALSE;
158   g_source_remove (id);
159 
160   /* Ensure we don't get double delivery */
161   g_timeout_add (500, exit_mainloop, mainloop);
162   g_main_loop_run (mainloop);
163   g_assert (!sig_received);
164 
165   /* Ensure that two sources for the same signal get it */
166   sig_counter = 0;
167   g_unix_signal_add (signum, on_sig_received_2, mainloop);
168   g_unix_signal_add (signum, on_sig_received_2, mainloop);
169   id = g_timeout_add (5000, on_sig_timeout, mainloop);
170 
171   kill (getpid (), signum);
172   g_main_loop_run (mainloop);
173   g_assert_cmpint (sig_counter, ==, 2);
174   g_source_remove (id);
175 
176   g_main_loop_unref (mainloop);
177 }
178 
179 static void
test_sighup(void)180 test_sighup (void)
181 {
182   test_signal (SIGHUP);
183 }
184 
185 static void
test_sigterm(void)186 test_sigterm (void)
187 {
188   test_signal (SIGTERM);
189 }
190 
191 static void
test_sighup_add_remove(void)192 test_sighup_add_remove (void)
193 {
194   guint id;
195   struct sigaction action;
196 
197   sig_received = FALSE;
198   id = g_unix_signal_add (SIGHUP, on_sig_received, NULL);
199   g_source_remove (id);
200 
201   sigaction (SIGHUP, NULL, &action);
202   g_assert (action.sa_handler == SIG_DFL);
203 }
204 
205 static gboolean
nested_idle(gpointer data)206 nested_idle (gpointer data)
207 {
208   GMainLoop *nested;
209   GMainContext *context;
210   GSource *source;
211 
212   context = g_main_context_new ();
213   nested = g_main_loop_new (context, FALSE);
214 
215   source = g_unix_signal_source_new (SIGHUP);
216   g_source_set_callback (source, on_sig_received, nested, NULL);
217   g_source_attach (source, context);
218   g_source_unref (source);
219 
220   kill (getpid (), SIGHUP);
221   g_main_loop_run (nested);
222   g_assert_cmpint (sig_counter, ==, 1);
223 
224   g_main_loop_unref (nested);
225   g_main_context_unref (context);
226 
227   return G_SOURCE_REMOVE;
228 }
229 
230 static void
test_sighup_nested(void)231 test_sighup_nested (void)
232 {
233   GMainLoop *mainloop;
234 
235   mainloop = g_main_loop_new (NULL, FALSE);
236 
237   sig_counter = 0;
238   sig_received = FALSE;
239   g_unix_signal_add (SIGHUP, on_sig_received, mainloop);
240   g_idle_add (nested_idle, mainloop);
241 
242   g_main_loop_run (mainloop);
243   g_assert_cmpint (sig_counter, ==, 2);
244 
245   g_main_loop_unref (mainloop);
246 }
247 
248 static gboolean
on_sigwinch_received(gpointer data)249 on_sigwinch_received (gpointer data)
250 {
251   GMainLoop *loop = (GMainLoop *) data;
252 
253   sig_counter ++;
254 
255   if (sig_counter == 1)
256     kill (getpid (), SIGWINCH);
257   else if (sig_counter == 2)
258     g_main_loop_quit (loop);
259   else if (sig_counter > 2)
260     g_assert_not_reached ();
261 
262   /* Increase the time window in which an issue could happen. */
263   g_usleep (G_USEC_PER_SEC);
264 
265   return G_SOURCE_CONTINUE;
266 }
267 
268 static void
test_callback_after_signal(void)269 test_callback_after_signal (void)
270 {
271   /* Checks that user signal callback is invoked *after* receiving a signal.
272    * In other words a new signal is never merged with the one being currently
273    * dispatched or whose dispatch had already finished. */
274 
275   GMainLoop *mainloop;
276   GMainContext *context;
277   GSource *source;
278 
279   sig_counter = 0;
280 
281   context = g_main_context_new ();
282   mainloop = g_main_loop_new (context, FALSE);
283 
284   source = g_unix_signal_source_new (SIGWINCH);
285   g_source_set_callback (source, on_sigwinch_received, mainloop, NULL);
286   g_source_attach (source, context);
287   g_source_unref (source);
288 
289   g_assert_cmpint (sig_counter, ==, 0);
290   kill (getpid (), SIGWINCH);
291   g_main_loop_run (mainloop);
292   g_assert_cmpint (sig_counter, ==, 2);
293 
294   g_main_loop_unref (mainloop);
295   g_main_context_unref (context);
296 }
297 
298 int
main(int argc,char * argv[])299 main (int   argc,
300       char *argv[])
301 {
302   g_test_init (&argc, &argv, NULL);
303 
304   g_test_add_func ("/glib-unix/pipe", test_pipe);
305   g_test_add_func ("/glib-unix/error", test_error);
306   g_test_add_func ("/glib-unix/nonblocking", test_nonblocking);
307   g_test_add_func ("/glib-unix/sighup", test_sighup);
308   g_test_add_func ("/glib-unix/sigterm", test_sigterm);
309   g_test_add_func ("/glib-unix/sighup_again", test_sighup);
310   g_test_add_func ("/glib-unix/sighup_add_remove", test_sighup_add_remove);
311   g_test_add_func ("/glib-unix/sighup_nested", test_sighup_nested);
312   g_test_add_func ("/glib-unix/callback_after_signal", test_callback_after_signal);
313 
314   return g_test_run();
315 }
316