comparison gtk/gtkmain.c @ 14480:1de5d45426e2

[gaim-migrate @ 17199] This should fix the bug where GStreamer would sometimes fail to initialize correctly. See the insanely long comment I added to the code if you want an explanation. I'm open to suggestions for a better way to fix this. committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Sat, 09 Sep 2006 10:39:06 +0000
parents bb060cdc23d1
children 497f4e9a0375
comparison
equal deleted inserted replaced
14479:aca9a7b62a23 14480:1de5d45426e2
87 static SnLauncheeContext *sn_context = NULL; 87 static SnLauncheeContext *sn_context = NULL;
88 static SnDisplay *sn_display = NULL; 88 static SnDisplay *sn_display = NULL;
89 #endif 89 #endif
90 90
91 #ifdef HAVE_SIGNAL_H 91 #ifdef HAVE_SIGNAL_H
92 static guint clean_pid_timeout = 0;
93
92 /* 94 /*
93 * Lists of signals we wish to catch and those we wish to ignore. 95 * Lists of signals we wish to catch and those we wish to ignore.
94 * Each list terminated with -1 96 * Each list terminated with -1
95 */ 97 */
96 static int catch_sig_list[] = { 98 static int catch_sig_list[] = {
141 143
142 return ret; 144 return ret;
143 } 145 }
144 146
145 #ifdef HAVE_SIGNAL_H 147 #ifdef HAVE_SIGNAL_H
146 static void 148 static void sighandler(int sig);
147 clean_pid(void) 149
150 /**
151 * Reap all our dead children. Sometimes Gaim forks off a separate
152 * process to do some stuff. When that process exits we are
153 * informed about it so that we can call waitpid() and let it
154 * stop being a zombie.
155 *
156 * We used to do this immediately when our signal handler was
157 * called, but because of GStreamer we now wait one second before
158 * reaping anything. Why? For some reason GStreamer fork()s
159 * during their initialization process. I don't understand why...
160 * but they do it, and there's nothing we can do about it.
161 *
162 * Anyway, so then GStreamer waits for its child to die and then
163 * it continues with the initialization process. This means that
164 * we have a race condition where GStreamer is waitpid()ing for its
165 * child to die and we're catching the SIGCHLD signal. If GStreamer
166 * is awarded the zombied process then everything is ok. But if Gaim
167 * reaps the zombie process then the GStreamer initialization sequence
168 * fails.
169 *
170 * So the ugly solution is to wait a second to give GStreamer time to
171 * reap that bad boy.
172 *
173 * GStreamer 0.10.10 and newer have a gst_register_fork_set_enabled()
174 * function that can be called by applications to disable forking
175 * during initialization. But it's not in 0.10.0, so we shouldn't
176 * use it.
177 */
178 static gboolean
179 clean_pid(gpointer data)
148 { 180 {
149 int status; 181 int status;
150 pid_t pid; 182 pid_t pid;
183
184 clean_pid_timeout = 0;
151 185
152 do { 186 do {
153 pid = waitpid(-1, &status, WNOHANG); 187 pid = waitpid(-1, &status, WNOHANG);
154 } while (pid != 0 && pid != (pid_t)-1); 188 } while (pid != 0 && pid != (pid_t)-1);
155 189
156 if ((pid == (pid_t) - 1) && (errno != ECHILD)) { 190 if ((pid == (pid_t) - 1) && (errno != ECHILD)) {
157 char errmsg[BUFSIZ]; 191 char errmsg[BUFSIZ];
158 snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); 192 snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid);
159 perror(errmsg); 193 perror(errmsg);
160 } 194 }
195
196 /* Restore signal catching */
197 signal(SIGCHLD, sighandler);
198
199 /* This timer should not be called again by glib */
200 return FALSE;
161 } 201 }
162 202
163 char *segfault_message; 203 char *segfault_message;
164 204
165 static void 205 static void
173 case SIGSEGV: 213 case SIGSEGV:
174 fprintf(stderr, "%s", segfault_message); 214 fprintf(stderr, "%s", segfault_message);
175 abort(); 215 abort();
176 break; 216 break;
177 case SIGCHLD: 217 case SIGCHLD:
178 clean_pid(); 218 if (clean_pid_timeout > 0)
179 signal(SIGCHLD, sighandler); /* restore signal catching on this one! */ 219 gaim_timeout_remove(clean_pid_timeout);
220 clean_pid_timeout = gaim_timeout_add(1000, clean_pid, NULL);
180 break; 221 break;
181 default: 222 default:
182 gaim_debug_warning("sighandler", "Caught signal %d\n", sig); 223 gaim_debug_warning("sighandler", "Caught signal %d\n", sig);
183 gaim_connections_disconnect_all(); 224 gaim_connections_disconnect_all();
184 225
759 #endif 800 #endif
760 801
761 gtk_main(); 802 gtk_main();
762 803
763 #ifdef HAVE_SIGNAL_H 804 #ifdef HAVE_SIGNAL_H
805 if (clean_pid_timeout > 0)
806 gaim_timeout_remove(clean_pid_timeout);
764 g_free(segfault_message); 807 g_free(segfault_message);
765 #endif 808 #endif
766 809
767 #ifdef _WIN32 810 #ifdef _WIN32
768 gtkwgaim_cleanup(); 811 gtkwgaim_cleanup();