pidgin/gtkmain.c

changeset 28820
58701e24ed40
parent 28800
a57c85844d28
child 28836
737062c0d40c
equal deleted inserted replaced
28819:6158b4151a59 28820:58701e24ed40
141 } 141 }
142 } 142 }
143 } 143 }
144 144
145 #ifdef HAVE_SIGNAL_H 145 #ifdef HAVE_SIGNAL_H
146 static char *segfault_message;
147
148 static int signal_sockets[2];
149
146 static void sighandler(int sig); 150 static void sighandler(int sig);
147 151
148 /* 152 /*
149 * This child process reaping stuff is currently only used for processes that 153 * This child process reaping stuff is currently only used for processes that
150 * were forked to play sounds. It's not needed for forked DNS child, which 154 * were forked to play sounds. It's not needed for forked DNS child, which
166 snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); 170 snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid);
167 perror(errmsg); 171 perror(errmsg);
168 } 172 }
169 } 173 }
170 174
171 char *segfault_message; 175 static void sighandler(int sig)
172 176 {
173 /* 177 ssize_t written;
174 * This signal handler shouldn't be touching this much stuff. 178
175 * It should just set a flag and return, and something else in 179 /*
176 * Pidgin should monitor the flag to see if something needs to 180 * We won't do any of the heavy lifting for the signal handling here
177 * be done. Because the signal handler interrupts the program, 181 * because we have no idea what was interrupted. Previously this signal
178 * it could be called in the middle of adding a new connection 182 * handler could result in some calls to malloc/free, which can cause
179 * to the list of connections, and then if we try to disconnect 183 * deadlock in libc when the signal handler was interrupting a previous
180 * all connections it could lead to a crash because the linked 184 * malloc or free. So instead we'll do an ugly hack where we write the
181 * list of connections could be in a weird state. But, well, 185 * signal number to one end of a socket pair. The other half of the
182 * this signal handler probably isn't called very often, so it's 186 * socket pair is watched by our main loop. When the main loop sees new
183 * not a big deal. 187 * data on the socket it reads in the signal and performs the appropriate
184 */ 188 * action without fear of interrupting stuff.
185 static void 189 */
186 sighandler(int sig) 190 if (sig == SIGSEGV) {
187 { 191 fprintf(stderr, "%s", segfault_message);
192 abort();
193 return;
194 }
195
196 written = write(signal_sockets[0], &sig, sizeof(int));
197 if (written < 0 || written != sizeof(int)) {
198 /* This should never happen */
199 purple_debug_error("sighandler", "Received signal %d but only "
200 "wrote %" G_GSSIZE_FORMAT " bytes out of %"
201 G_GSIZE_FORMAT ": %s\n",
202 sig, written, sizeof(int), g_strerror(errno));
203 exit(1);
204 }
205 }
206
207 static gboolean
208 mainloop_sighandler(GIOChannel *source, GIOCondition cond, gpointer data)
209 {
210 GIOStatus stat;
211 int sig;
212 gsize bytes_read;
213 GError *error = NULL;
214
215 /* read the signal number off of the io channel */
216 stat = g_io_channel_read_chars(source, (gchar *)&sig, sizeof(int),
217 &bytes_read, &error);
218 if (stat != G_IO_STATUS_NORMAL) {
219 purple_debug_error("sighandler", "Signal callback failed to read "
220 "from signal socket: %s", error->message);
221 purple_core_quit();
222 return FALSE;
223 }
224
188 switch (sig) { 225 switch (sig) {
189 case SIGHUP: 226 case SIGHUP:
190 purple_debug_warning("sighandler", "Caught signal %d\n", sig); 227 purple_debug_warning("sighandler", "Caught signal %d\n", sig);
191 break;
192 case SIGSEGV:
193 fprintf(stderr, "%s", segfault_message);
194 abort();
195 break; 228 break;
196 #if defined(USE_GSTREAMER) && !defined(GST_CAN_DISABLE_FORKING) 229 #if defined(USE_GSTREAMER) && !defined(GST_CAN_DISABLE_FORKING)
197 /* By default, gstreamer forks when you initialize it, and waitpids for the 230 /* By default, gstreamer forks when you initialize it, and waitpids for the
198 * child. But if libpurple reaps the child rather than leaving it to 231 * child. But if libpurple reaps the child rather than leaving it to
199 * gstreamer, gstreamer's initialization fails. So, we wait a second before 232 * gstreamer, gstreamer's initialization fails. So, we wait a second before
217 break; 250 break;
218 default: 251 default:
219 purple_debug_warning("sighandler", "Caught signal %d\n", sig); 252 purple_debug_warning("sighandler", "Caught signal %d\n", sig);
220 purple_core_quit(); 253 purple_core_quit();
221 } 254 }
255
256 return TRUE;
222 } 257 }
223 #endif 258 #endif
224 259
225 static int 260 static int
226 ui_main(void) 261 ui_main(void)
500 #ifdef HAVE_SIGNAL_H 535 #ifdef HAVE_SIGNAL_H
501 int sig_indx; /* for setting up signal catching */ 536 int sig_indx; /* for setting up signal catching */
502 sigset_t sigset; 537 sigset_t sigset;
503 RETSIGTYPE (*prev_sig_disp)(int); 538 RETSIGTYPE (*prev_sig_disp)(int);
504 char errmsg[BUFSIZ]; 539 char errmsg[BUFSIZ];
540 GIOChannel *signal_channel;
541 GIOStatus signal_status;
505 #ifndef DEBUG 542 #ifndef DEBUG
506 char *segfault_message_tmp; 543 char *segfault_message_tmp;
507 GError *error = NULL; 544 GError *error = NULL;
508 #endif 545 #endif
509 #endif 546 #endif
590 "haven't been cheating on you!! How many times do you want me to tell you?! And\n" 627 "haven't been cheating on you!! How many times do you want me to tell you?! And\n"
591 "for the last time, it's just a rash!\n" 628 "for the last time, it's just a rash!\n"
592 ); 629 );
593 #endif 630 #endif
594 631
632 /*
633 * Create a socket pair for receiving unix signals from a signal
634 * handler.
635 */
636 if (socketpair(AF_UNIX, SOCK_STREAM, 0, signal_sockets) < 0) {
637 perror("Failed to create sockets for GLib signal handling");
638 exit(1);
639 }
640 signal_channel = g_io_channel_unix_new(signal_sockets[1]);
641
642 /*
643 * Set the channel encoding to raw binary instead of the default of
644 * UTF-8, because we'll be sending integers across instead of strings.
645 */
646 error = NULL;
647 signal_status = g_io_channel_set_encoding(signal_channel, NULL, &error);
648 if (signal_status != G_IO_STATUS_NORMAL) {
649 fprintf(stderr, "Failed to set the signal channel to raw "
650 "binary: %s", error->message);
651 exit(1);
652 }
653 g_io_add_watch(signal_channel, G_IO_IN, mainloop_sighandler, NULL);
654
595 /* Let's not violate any PLA's!!!! */ 655 /* Let's not violate any PLA's!!!! */
596 /* jseymour: whatever the fsck that means */ 656 /* jseymour: whatever the fsck that means */
597 /* Robot101: for some reason things like gdm like to block * 657 /* Robot101: for some reason things like gdm like to block *
598 * useful signals like SIGCHLD, so we unblock all the ones we * 658 * useful signals like SIGCHLD, so we unblock all the ones we *
599 * declare a handler for. thanks JSeymour and Vann. */ 659 * declare a handler for. thanks JSeymour and Vann. */

mercurial