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 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, write to the 16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 * Boston, MA 02111-1307, USA. 18 */ 19 20 /* 21 * Modified by the GLib Team and others 1997-2000. See the AUTHORS 22 * file for a list of people on the GLib Team. See the ChangeLog 23 * files for a list of changes. These files are distributed with 24 * GLib at ftp://ftp.gtk.org/pub/gtk/. 25 */ 26 27 #include "config.h" 28 29 #include <sys/types.h> 30 #ifdef HAVE_UNISTD_H 31 #include <unistd.h> 32 #endif 33 #include <stdlib.h> 34 35 #include <glib.h> 36 37 #ifdef G_OS_WIN32 38 #include <windows.h> 39 #endif 40 41 #ifdef G_OS_WIN32 42 #define GPID_FORMAT "%p" 43 #else 44 #define GPID_FORMAT "%d" 45 #endif 46 47 GMainLoop *main_loop; 48 gint alive; 49 50 #ifdef G_OS_WIN32 51 char *argv0; 52 #endif 53 54 GPid 55 get_a_child (gint ttl) 56 { 57 GPid pid; 58 59 #ifdef G_OS_WIN32 60 STARTUPINFO si; 61 PROCESS_INFORMATION pi; 62 gchar *cmdline; 63 64 memset (&si, 0, sizeof (si)); 65 si.cb = sizeof (&si); 66 memset (&pi, 0, sizeof (pi)); 67 68 cmdline = g_strdup_printf( "child-test -c%d", ttl); 69 70 if (!CreateProcess (argv0, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) 71 g_error ("CreateProcess failed: %s\n", g_win32_error_message (GetLastError ())); 72 73 g_free(cmdline); 74 75 CloseHandle (pi.hThread); 76 pid = pi.hProcess; 77 78 return pid; 79 #else 80 pid = fork (); 81 if (pid < 0) 82 exit (1); 83 84 if (pid > 0) 85 return pid; 86 87 sleep (ttl); 88 _exit (0); 89 #endif /* G_OS_WIN32 */ 90 } 91 92 gboolean 93 child_watch_callback (GPid pid, gint status, gpointer data) 94 { 95 #ifdef VERBOSE 96 gint ttl = GPOINTER_TO_INT (data); 97 98 g_print ("child " GPID_FORMAT " (ttl %d) exited, status %d\n", pid, ttl, status); 99 #endif 100 101 g_spawn_close_pid (pid); 102 103 if (--alive == 0) 104 g_main_loop_quit (main_loop); 105 106 return TRUE; 107 } 108 109 static gboolean 110 quit_loop (gpointer data) 111 { 112 GMainLoop *main_loop = data; 113 114 g_main_loop_quit (main_loop); 115 116 return TRUE; 117 } 118 119 #ifdef TEST_THREAD 120 static gpointer 121 test_thread (gpointer data) 122 { 123 GMainLoop *new_main_loop; 124 GSource *source; 125 GPid pid; 126 gint ttl = GPOINTER_TO_INT (data); 127 128 new_main_loop = g_main_loop_new (NULL, FALSE); 129 130 pid = get_a_child (ttl); 131 source = g_child_watch_source_new (pid); 132 g_source_set_callback (source, (GSourceFunc) child_watch_callback, data, NULL); 133 g_source_attach (source, g_main_loop_get_context (new_main_loop)); 134 g_source_unref (source); 135 136 #ifdef VERBOSE 137 g_print ("whee! created pid: " GPID_FORMAT " (ttl %d)\n", pid, ttl); 138 #endif 139 140 g_main_loop_run (new_main_loop); 141 142 return NULL; 143 } 144 #endif 145 146 int 147 main (int argc, char *argv[]) 148 { 149 #ifndef TEST_THREAD 150 GPid pid; 151 #endif 152 #ifdef G_OS_WIN32 153 argv0 = argv[0]; 154 if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'c') 155 { 156 int ttl = atoi (argv[1] + 2); 157 Sleep (ttl * 1000); 158 /* Exit on purpose with STILL_ACTIVE (which isn't a very common 159 * exit status) to verify that g_child_watch_check() in gmain.c 160 * doesn't believe a child still to be active if it happens to 161 * exit with that status. 162 */ 163 exit (STILL_ACTIVE); 164 } 165 #endif 166 /* Only run the test, if threads are enabled and a default thread 167 * implementation is available. 168 */ 169 #if defined(G_THREADS_ENABLED) && ! defined(G_THREADS_IMPL_NONE) 170 #ifdef TEST_THREAD 171 g_thread_init (NULL); 172 #endif 173 main_loop = g_main_loop_new (NULL, FALSE); 174 175 #ifdef G_OS_WIN32 176 system ("ipconfig /all"); 177 #else 178 system ("/bin/true"); 179 #endif 180 181 alive = 2; 182 g_timeout_add (30000, quit_loop, main_loop); 183 184 #ifdef TEST_THREAD 185 g_thread_create (test_thread, GINT_TO_POINTER (10), FALSE, NULL); 186 g_thread_create (test_thread, GINT_TO_POINTER (20), FALSE, NULL); 187 #else 188 pid = get_a_child (10); 189 g_child_watch_add (pid, (GChildWatchFunc) child_watch_callback, 190 GINT_TO_POINTER (10)); 191 pid = get_a_child (20); 192 g_child_watch_add (pid, (GChildWatchFunc) child_watch_callback, 193 GINT_TO_POINTER (20)); 194 #endif 195 196 g_main_loop_run (main_loop); 197 198 if (alive > 0) 199 { 200 g_warning ("%d children still alive\n", alive); 201 return 1; 202 } 203 204 #endif 205 return 0; 206 } 207