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