comparison src/audlegacy/signals.c @ 4811:7bf7f83a217e

rename src/audacious src/audlegacy so that both audlegacy and audacious can coexist.
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Wed, 26 Nov 2008 00:44:56 +0900
parents src/audacious/signals.c@1d13609b1c52
children 901cd268f0ca
comparison
equal deleted inserted replaced
4810:c10e53092037 4811:7bf7f83a217e
1 /*
2 * Audacious
3 * Copyright (c) 2005-2007 Yoshiki Yazawa
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; under version 3 of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses>.
16 *
17 * The Audacious team does not consider modular code linking to
18 * Audacious or using our public API to be a derived work.
19 */
20
21 //#define _XOPEN_SOURCE
22 #include <unistd.h> /* for signal_check_for_broken_impl() */
23
24 #include <glib.h>
25 #include <glib/gi18n.h>
26 #include <config.h>
27 #include <stdlib.h>
28 #include <pthread.h> /* for pthread_sigmask() */
29 #include <signal.h>
30
31 #ifdef HAVE_EXECINFO_H
32 # include <execinfo.h>
33 #endif
34
35 #include "main.h"
36 #include "signals.h"
37 #include "build_stamp.h"
38 #ifdef USE_EGGSM
39 #include "eggsmclient.h"
40 #endif
41
42 typedef void (*SignalHandler) (gint);
43
44 gint linuxthread_signal_number = 0;
45
46 static void
47 signal_process_segv(void)
48 {
49 g_printerr(_("\nAudacious has caught signal 11 (SIGSEGV).\n\n"
50 "We apologize for the inconvenience, but Audacious has crashed.\n"
51 "This is a bug in the program, and should never happen under normal circumstances.\n"
52 "Your current configuration has been saved and should not be damaged.\n\n"
53 "You can help improve the quality of Audacious by filing a bug at http://bugzilla.atheme.org/\n"
54 "Please include the entire text of this message and a description of what you were doing when\n"
55 "this crash occured in order to quickly expedite the handling of your bug report:\n\n"));
56
57 g_printerr("Program version: Audacious %s (buildid: %s)\n\n", VERSION, svn_stamp);
58
59 #ifdef HAVE_EXECINFO_H
60 {
61 void *stack[20];
62 size_t size;
63 char **strings;
64 size_t i;
65
66 size = backtrace(stack, 20);
67 strings = backtrace_symbols(stack, size);
68
69 g_printerr("Stacktrace (%zd frames):\n", size);
70
71 for (i = 0; i < size; i++)
72 g_printerr(" %ld. %s\n", (long)i + 1, strings[i]);
73
74 g_free(strings);
75 }
76 #else
77 g_printerr(_("Stacktrace was unavailable. You might want to reproduce this "
78 "problem while running Audacious under GDB to get a proper backtrace.\n"));
79 #endif
80
81 g_printerr(_("\nBugs can be reported at http://bugzilla.atheme.org/ against "
82 "the Audacious or Audacious Plugins product.\n"));
83
84 g_critical("Received SIGSEGV -- Audacious has crashed.");
85
86 aud_config_save();
87 abort();
88 }
89
90 #if (!defined(HAVE_SIGNALFD) || !defined(HAVE_SYS_SIGNALFD_H))
91
92 static void *
93 signal_process_signals (void *data)
94 {
95 sigset_t waitset;
96 int sig;
97
98 sigemptyset(&waitset);
99 sigaddset(&waitset, SIGPIPE);
100 sigaddset(&waitset, SIGSEGV);
101 sigaddset(&waitset, SIGINT);
102 sigaddset(&waitset, SIGTERM);
103
104 while(1) {
105 sigwait(&waitset, &sig);
106
107 switch(sig){
108 case SIGPIPE:
109 /*
110 * do something.
111 */
112 break;
113
114 case SIGSEGV:
115 signal_process_segv();
116 break;
117
118 case SIGINT:
119 g_print("Audacious has received SIGINT and is shutting down.\n");
120 aud_quit();
121 break;
122
123 case SIGTERM:
124 g_print("Audacious has received SIGTERM and is shutting down.\n");
125 aud_quit();
126 break;
127 }
128 }
129
130 return NULL; //dummy
131 }
132
133 /********************************************************************************/
134 /* for linuxthread */
135 /********************************************************************************/
136
137 static void *
138 signal_process_signals_linuxthread (void *data)
139 {
140 while(1) {
141 g_usleep(1000000);
142
143 switch(linuxthread_signal_number){
144 case SIGPIPE:
145 /*
146 * do something.
147 */
148 linuxthread_signal_number = 0;
149 break;
150
151 case SIGSEGV:
152 signal_process_segv();
153 break;
154
155 case SIGINT:
156 g_print("Audacious has received SIGINT and is shutting down.\n");
157 aud_quit();
158 break;
159
160 case SIGTERM:
161 g_print("Audacious has received SIGTERM and is shutting down.\n");
162 aud_quit();
163 break;
164 }
165 }
166
167 return NULL; //dummy
168 }
169
170 static void
171 linuxthread_handler (gint signal_number)
172 {
173 /* note: cannot manipulate mutex from signal handler */
174 linuxthread_signal_number = signal_number;
175 }
176
177 #else
178
179 #include <sys/signalfd.h>
180
181 static gpointer
182 signal_process_signals(gpointer data)
183 {
184 struct signalfd_siginfo d;
185 sigset_t waitset;
186 int sigfd;
187
188 sigemptyset(&waitset);
189 sigaddset(&waitset, SIGPIPE);
190 sigaddset(&waitset, SIGSEGV);
191 sigaddset(&waitset, SIGINT);
192 sigaddset(&waitset, SIGTERM);
193
194 sigfd = signalfd(-1, &waitset, 0);
195
196 while (read(sigfd, &d, sizeof(struct signalfd_siginfo)) > 0)
197 {
198 switch(d.ssi_signo)
199 {
200 case SIGPIPE:
201 /*
202 * do something.
203 */
204 break;
205
206 case SIGSEGV:
207 signal_process_segv();
208 break;
209
210 case SIGINT:
211 g_print("Audacious has received SIGINT and is shutting down.\n");
212 aud_quit();
213 break;
214
215 case SIGTERM:
216 g_print("Audacious has received SIGTERM and is shutting down.\n");
217 aud_quit();
218 break;
219 }
220 }
221
222 close(sigfd);
223
224 return NULL;
225 }
226
227 #endif
228
229 static SignalHandler
230 signal_install_handler_full (gint signal_number,
231 SignalHandler handler,
232 gint *signals_to_block,
233 gsize n_signals)
234 {
235 struct sigaction action, old_action;
236 gsize i;
237
238 action.sa_handler = handler;
239 action.sa_flags = SA_RESTART;
240
241 sigemptyset (&action.sa_mask);
242
243 for (i = 0; i < n_signals; i++)
244 sigaddset (&action.sa_mask, signals_to_block[i]);
245
246 if (sigaction (signal_number, &action, &old_action) == -1)
247 {
248 g_message ("Failed to install handler for signal %d", signal_number);
249 return NULL;
250 }
251
252 return old_action.sa_handler;
253 }
254
255 /*
256 * A version of signal() that works more reliably across different
257 * platforms. It:
258 * a. restarts interrupted system calls
259 * b. does not reset the handler
260 * c. blocks the same signal within the handler
261 *
262 * (adapted from Unix Network Programming Vol. 1)
263 */
264 static SignalHandler
265 signal_install_handler (gint signal_number,
266 SignalHandler handler)
267 {
268 return signal_install_handler_full (signal_number, handler, NULL, 0);
269 }
270
271
272 /* sets up blocking signals for pthreads.
273 * linuxthreads sucks and needs this to make sigwait(2) work
274 * correctly. --nenolod
275 *
276 * correction -- this trick does not work on linuxthreads.
277 * going to keep it in it's own function though --nenolod
278 */
279 static void
280 signal_initialize_blockers(void)
281 {
282 sigset_t blockset;
283
284 sigemptyset(&blockset);
285 sigaddset(&blockset, SIGPIPE);
286 sigaddset(&blockset, SIGSEGV);
287 sigaddset(&blockset, SIGINT);
288 sigaddset(&blockset, SIGTERM);
289
290 if(pthread_sigmask(SIG_BLOCK, &blockset, NULL))
291 g_print("pthread_sigmask() failed.\n");
292 }
293
294 static gboolean
295 signal_check_for_broken_impl(void)
296 {
297 #ifdef _CS_GNU_LIBPTHREAD_VERSION
298 {
299 gchar str[1024];
300 confstr(_CS_GNU_LIBPTHREAD_VERSION, str, sizeof(str));
301
302 if (g_ascii_strncasecmp("linuxthreads", str, 12) == 0)
303 return TRUE;
304 }
305 #endif
306
307 return FALSE;
308 }
309
310 #ifdef USE_EGGSM
311 static void
312 signal_session_quit_cb(EggSMClient *client, gpointer user_data)
313 {
314 g_print("Session quit requested. Saving state and shutting down.\n");
315 aud_quit();
316 }
317
318 static void
319 signal_session_save_cb(EggSMClient *client, const char *state_dir, gpointer user_data)
320 {
321 g_print("Session save requested. Saving state.\n");
322 aud_config_save();
323 }
324 #endif
325
326 void
327 signal_handlers_init(void)
328 {
329 #ifdef USE_EGGSM
330 EggSMClient *client;
331
332 client = egg_sm_client_get ();
333 if (client != NULL)
334 {
335 egg_sm_client_set_mode (EGG_SM_CLIENT_MODE_NORMAL);
336 g_signal_connect (client, "quit",
337 G_CALLBACK (signal_session_quit_cb), NULL);
338 g_signal_connect (client, "save-state",
339 G_CALLBACK (signal_session_save_cb), NULL);
340
341 }
342 #endif
343
344 #if (!defined(HAVE_SIGNALFD) || !defined(HAVE_SYS_SIGNALFD_H))
345
346 if (signal_check_for_broken_impl() != TRUE)
347 {
348 signal_initialize_blockers();
349 g_thread_create(signal_process_signals, NULL, FALSE, NULL);
350 }
351 else
352 {
353 g_printerr(_("Your signaling implementation is broken.\n"
354 "Expect unusable crash reports.\n"));
355
356 /* install special handler which catches signals and forwards to the signal handling thread */
357 signal_install_handler(SIGPIPE, linuxthread_handler);
358 signal_install_handler(SIGSEGV, linuxthread_handler);
359 signal_install_handler(SIGINT, linuxthread_handler);
360 signal_install_handler(SIGTERM, linuxthread_handler);
361
362 /* create handler thread */
363 g_thread_create(signal_process_signals_linuxthread, NULL, FALSE, NULL);
364
365 }
366
367 #else
368
369 signal_initialize_blockers();
370 g_thread_create(signal_process_signals, NULL, FALSE, NULL);
371
372 #endif
373 }