Mercurial > pidgin
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(); |