1 | /* GLIB - Library of useful routines for C programming |
2 | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | /* |
19 | * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
20 | * file for a list of people on the GLib Team. See the ChangeLog |
21 | * files for a list of changes. These files are distributed with |
22 | * GLib at ftp://ftp.gtk.org/pub/gtk/. |
23 | */ |
24 | |
25 | #include <sys/types.h> |
26 | #include <stdlib.h> |
27 | |
28 | #include <glib.h> |
29 | |
30 | #ifdef G_OS_UNIX |
31 | #include <unistd.h> |
32 | #endif |
33 | |
34 | #ifdef G_OS_WIN32 |
35 | #include <windows.h> |
36 | #endif |
37 | |
38 | #ifdef G_OS_WIN32 |
39 | #define GPID_FORMAT "%p" |
40 | #else |
41 | #define GPID_FORMAT "%d" |
42 | #endif |
43 | |
44 | GMainLoop *main_loop; |
45 | gint alive; |
46 | |
47 | #ifdef G_OS_WIN32 |
48 | char *argv0; |
49 | #endif |
50 | |
51 | static GPid |
52 | get_a_child (gint ttl) |
53 | { |
54 | GPid pid; |
55 | |
56 | #ifdef G_OS_WIN32 |
57 | STARTUPINFO si; |
58 | PROCESS_INFORMATION pi; |
59 | gchar *cmdline; |
60 | |
61 | memset (&si, 0, sizeof (si)); |
62 | si.cb = sizeof (&si); |
63 | memset (&pi, 0, sizeof (pi)); |
64 | |
65 | cmdline = g_strdup_printf( "child-test -c%d" , ttl); |
66 | |
67 | if (!CreateProcess (argv0, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) |
68 | g_error ("CreateProcess failed: %s" , g_win32_error_message (GetLastError ())); |
69 | |
70 | g_free(cmdline); |
71 | |
72 | CloseHandle (pi.hThread); |
73 | pid = pi.hProcess; |
74 | |
75 | return pid; |
76 | #else |
77 | pid = fork (); |
78 | if (pid < 0) |
79 | exit (status: 1); |
80 | |
81 | if (pid > 0) |
82 | return pid; |
83 | |
84 | sleep (seconds: ttl); |
85 | _exit (status: 0); |
86 | #endif /* G_OS_WIN32 */ |
87 | } |
88 | |
89 | static gboolean |
90 | child_watch_callback (GPid pid, gint status, gpointer data) |
91 | { |
92 | #ifdef VERBOSE |
93 | gint ttl = GPOINTER_TO_INT (data); |
94 | |
95 | g_print ("child " GPID_FORMAT " (ttl %d) exited, status %d\n" , pid, ttl, status); |
96 | #endif |
97 | |
98 | g_spawn_close_pid (pid); |
99 | |
100 | if (--alive == 0) |
101 | g_main_loop_quit (loop: main_loop); |
102 | |
103 | return TRUE; |
104 | } |
105 | |
106 | static gboolean |
107 | quit_loop (gpointer data) |
108 | { |
109 | GMainLoop *main_loop = data; |
110 | |
111 | g_main_loop_quit (loop: main_loop); |
112 | |
113 | return TRUE; |
114 | } |
115 | |
116 | #ifdef TEST_THREAD |
117 | static gpointer |
118 | test_thread (gpointer data) |
119 | { |
120 | GMainLoop *new_main_loop; |
121 | GSource *source; |
122 | GPid pid; |
123 | gint ttl = GPOINTER_TO_INT (data); |
124 | |
125 | new_main_loop = g_main_loop_new (NULL, FALSE); |
126 | |
127 | pid = get_a_child (ttl); |
128 | source = g_child_watch_source_new (pid); |
129 | g_source_set_callback (source, (GSourceFunc) child_watch_callback, data, NULL); |
130 | g_source_attach (source, g_main_loop_get_context (new_main_loop)); |
131 | g_source_unref (source); |
132 | |
133 | #ifdef VERBOSE |
134 | g_print ("whee! created pid: " GPID_FORMAT " (ttl %d)\n" , pid, ttl); |
135 | #endif |
136 | |
137 | g_main_loop_run (new_main_loop); |
138 | |
139 | return NULL; |
140 | } |
141 | #endif |
142 | |
143 | int |
144 | main (int argc, char *argv[]) |
145 | { |
146 | #ifndef TEST_THREAD |
147 | GPid pid; |
148 | #endif |
149 | #ifdef G_OS_WIN32 |
150 | argv0 = argv[0]; |
151 | if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'c') |
152 | { |
153 | int ttl = atoi (argv[1] + 2); |
154 | Sleep (ttl * 1000); |
155 | /* Exit on purpose with STILL_ACTIVE (which isn't a very common |
156 | * exit status) to verify that g_child_watch_check() in gmain.c |
157 | * doesn't believe a child still to be active if it happens to |
158 | * exit with that status. |
159 | */ |
160 | exit (STILL_ACTIVE); |
161 | } |
162 | #endif |
163 | |
164 | main_loop = g_main_loop_new (NULL, FALSE); |
165 | |
166 | #ifdef G_OS_WIN32 |
167 | system ("ipconfig /all" ); |
168 | #else |
169 | system (command: "true" ); |
170 | #endif |
171 | |
172 | alive = 2; |
173 | g_timeout_add_seconds (interval: 30, function: quit_loop, data: main_loop); |
174 | |
175 | #ifdef TEST_THREAD |
176 | g_thread_create (test_thread, GINT_TO_POINTER (10), FALSE, NULL); |
177 | g_thread_create (test_thread, GINT_TO_POINTER (20), FALSE, NULL); |
178 | #else |
179 | pid = get_a_child (ttl: 10); |
180 | g_child_watch_add (pid, function: (GChildWatchFunc) child_watch_callback, |
181 | GINT_TO_POINTER (10)); |
182 | pid = get_a_child (ttl: 20); |
183 | g_child_watch_add (pid, function: (GChildWatchFunc) child_watch_callback, |
184 | GINT_TO_POINTER (20)); |
185 | #endif |
186 | |
187 | g_main_loop_run (loop: main_loop); |
188 | |
189 | g_main_loop_unref (loop: main_loop); |
190 | |
191 | if (alive > 0) |
192 | { |
193 | g_warning ("%d children still alive" , alive); |
194 | return 1; |
195 | } |
196 | |
197 | return 0; |
198 | } |
199 | |