| 139 } |
138 } |
| 140 |
139 |
| 141 #ifdef HAVE_SIGNAL_H |
140 #ifdef HAVE_SIGNAL_H |
| 142 static void sighandler(int sig); |
141 static void sighandler(int sig); |
| 143 |
142 |
| 144 /** |
143 /* |
| 145 * Reap all our dead children. Sometimes libpurple forks off a separate |
144 * This child process reaping stuff is currently only used for processes that |
| 146 * process to do some stuff. When that process exits we are |
145 * were forked to play sounds. It's not needed for forked DNS child, which |
| 147 * informed about it so that we can call waitpid() and let it |
146 * have their own waitpid() call. It might be wise to move this code into |
| 148 * stop being a zombie. |
147 * gtksound.c. |
| 149 * |
|
| 150 * We used to do this immediately when our signal handler was |
|
| 151 * called, but because of GStreamer we now wait one second before |
|
| 152 * reaping anything. Why? For some reason GStreamer fork()s |
|
| 153 * during their initialization process. I don't understand why... |
|
| 154 * but they do it, and there's nothing we can do about it. |
|
| 155 * |
|
| 156 * Anyway, so then GStreamer waits for its child to die and then |
|
| 157 * it continues with the initialization process. This means that |
|
| 158 * we have a race condition where GStreamer is waitpid()ing for its |
|
| 159 * child to die and we're catching the SIGCHLD signal. If GStreamer |
|
| 160 * is awarded the zombied process then everything is ok. But if libpurple |
|
| 161 * reaps the zombie process then the GStreamer initialization sequence |
|
| 162 * fails. |
|
| 163 * |
|
| 164 * So the ugly solution is to wait a second to give GStreamer time to |
|
| 165 * reap that bad boy. |
|
| 166 * |
|
| 167 * GStreamer 0.10.10 and newer have a gst_register_fork_set_enabled() |
|
| 168 * function that can be called by applications to disable forking |
|
| 169 * during initialization. But it's not in 0.10.0, so we shouldn't |
|
| 170 * use it. |
|
| 171 * |
|
| 172 * All of this child process reaping stuff is currently only used for |
|
| 173 * processes that were forked to play sounds. It's not needed for |
|
| 174 * forked DNS child, which have their own waitpid() call. It might |
|
| 175 * be wise to move this code into gtksound.c. |
|
| 176 */ |
148 */ |
| 177 static void |
149 static void |
| 178 clean_pid(void) |
150 clean_pid(void) |
| 179 { |
151 { |
| 180 int status; |
152 int status; |
| 187 if ((pid == (pid_t) - 1) && (errno != ECHILD)) { |
159 if ((pid == (pid_t) - 1) && (errno != ECHILD)) { |
| 188 char errmsg[BUFSIZ]; |
160 char errmsg[BUFSIZ]; |
| 189 snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); |
161 snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); |
| 190 perror(errmsg); |
162 perror(errmsg); |
| 191 } |
163 } |
| 192 |
|
| 193 /* Restore signal catching */ |
|
| 194 signal(SIGALRM, sighandler); |
|
| 195 } |
164 } |
| 196 |
165 |
| 197 char *segfault_message; |
166 char *segfault_message; |
| 198 |
167 |
| 199 /* |
168 /* |
| 219 case SIGSEGV: |
188 case SIGSEGV: |
| 220 fprintf(stderr, "%s", segfault_message); |
189 fprintf(stderr, "%s", segfault_message); |
| 221 abort(); |
190 abort(); |
| 222 break; |
191 break; |
| 223 case SIGCHLD: |
192 case SIGCHLD: |
| 224 /* Restore signal catching */ |
|
| 225 signal(SIGCHLD, sighandler); |
|
| 226 alarm(1); |
|
| 227 break; |
|
| 228 case SIGALRM: |
|
| 229 clean_pid(); |
193 clean_pid(); |
| |
194 signal(SIGCHLD, sighandler); /* restore signal catching on this one! */ |
| 230 break; |
195 break; |
| 231 default: |
196 default: |
| 232 purple_debug_warning("sighandler", "Caught signal %d\n", sig); |
197 purple_debug_warning("sighandler", "Caught signal %d\n", sig); |
| 233 purple_connections_disconnect_all(); |
198 purple_connections_disconnect_all(); |
| 234 |
199 |