~ubuntu-branches/ubuntu/feisty/elinks/feisty-updates

« back to all changes in this revision

Viewing changes to src/lowlevel/signals.c

  • Committer: Bazaar Package Importer
  • Author(s): Peter Gervai
  • Date: 2004-01-21 22:13:45 UTC
  • Revision ID: james.westby@ubuntu.com-20040121221345-ju33hai1yhhqt6kn
Tags: upstream-0.9.1
ImportĀ upstreamĀ versionĀ 0.9.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Signals handling. */
 
2
/* $Id: signals.c,v 1.19 2004/01/08 13:13:50 jonas Exp $ */
 
3
 
 
4
#ifdef HAVE_CONFIG_H
 
5
#include "config.h"
 
6
#endif
 
7
 
 
8
#include <signal.h>
 
9
#include <stdlib.h>
 
10
#include <string.h>
 
11
#ifdef HAVE_SYS_SIGNAL_H
 
12
#include <sys/signal.h>
 
13
#endif
 
14
#include <sys/types.h>
 
15
#ifdef HAVE_SYS_WAIT_H
 
16
#include <sys/wait.h>
 
17
#endif
 
18
#ifdef HAVE_UNISTD_H
 
19
#include <unistd.h>
 
20
#endif
 
21
 
 
22
#include "elinks.h"
 
23
 
 
24
#include "main.h"
 
25
/* This does not deserve to survive. Gotta be moved... somewhere else.
 
26
 * 'nuff said. --pasky */
 
27
#include "dialogs/menu.h"
 
28
#include "intl/gettext/libintl.h"
 
29
#include "lowlevel/select.h"
 
30
#include "lowlevel/signals.h"
 
31
#include "modules/version.h"
 
32
#include "terminal/kbd.c"
 
33
#include "util/error.h"
 
34
 
 
35
 
 
36
static void unhandle_basic_signals(struct terminal *term);
 
37
 
 
38
static void
 
39
sig_terminate(struct terminal *t)
 
40
{
 
41
        unhandle_basic_signals(t);
 
42
        terminate = 1;
 
43
        retval = RET_SIGNAL;
 
44
}
 
45
 
 
46
static void
 
47
sig_intr(struct terminal *t)
 
48
{
 
49
        unhandle_basic_signals(t);
 
50
 
 
51
        if (!t)
 
52
                terminate = 1;
 
53
        else
 
54
                register_bottom_half((void (*)(void *))destroy_terminal, t);
 
55
}
 
56
 
 
57
void
 
58
sig_ctrl_c(struct terminal *t)
 
59
{
 
60
        if (!is_blocked()) kbd_ctrl_c();
 
61
}
 
62
 
 
63
static void
 
64
sig_ign(void *x)
 
65
{
 
66
}
 
67
 
 
68
static void
 
69
sig_tstp(struct terminal *t)
 
70
{
 
71
#ifdef SIGSTOP
 
72
        int pid = getpid();
 
73
 
 
74
        block_itrm(0);
 
75
#if defined (SIGCONT) && defined(SIGTTOU)
 
76
        if (!fork()) {
 
77
                sleep(1);
 
78
                kill(pid, SIGCONT);
 
79
                exit(0);
 
80
        }
 
81
#endif
 
82
        raise(SIGSTOP);
 
83
#endif
 
84
}
 
85
 
 
86
static void
 
87
sig_cont(struct terminal *t)
 
88
{
 
89
        if (!unblock_itrm(0)) resize_terminal();
 
90
}
 
91
 
 
92
#ifdef CONFIG_BACKTRACE
 
93
static void
 
94
sig_segv(struct terminal *t)
 
95
{
 
96
        /* Get some attention. */
 
97
        fputs("\a", stderr); fflush(stderr); sleep(1); fputs("\a\n", stderr);
 
98
 
 
99
        /* Rant. */
 
100
        fputs(  "ELinks crashed. That shouldn't happen. Please report this incident to\n"
 
101
                "developers. Preferrably please include information about what probably\n"
 
102
                "triggered this and the listout below. Note that it does NOT supercede the gdb\n"
 
103
                "output, which is way more useful for developers. If you would like to help to\n"
 
104
                "debug the problem you just uncovered, please keep the core you just got and\n"
 
105
                "send the developers output of 'bt' command entered inside of gdb (which you run\n"
 
106
                "as gdb elinks core). Thanks a lot for your cooperation!\n\n", stderr);
 
107
 
 
108
        /* version information */
 
109
        fputs(full_static_version, stderr);
 
110
        fputs("\n\n", stderr);
 
111
 
 
112
        /* Backtrace. */
 
113
        dump_backtrace(stderr, 1);
 
114
 
 
115
        /* TODO: Perhaps offer launching of gdb? Or trying to continue w/
 
116
         * program execution? --pasky */
 
117
 
 
118
        /* The fastest way OUT! */
 
119
        abort();
 
120
}
 
121
#endif
 
122
 
 
123
 
 
124
void
 
125
handle_basic_signals(struct terminal *term)
 
126
{
 
127
        install_signal_handler(SIGHUP, (void (*)(void *))sig_intr, term, 0);
 
128
        install_signal_handler(SIGINT, (void (*)(void *))sig_ctrl_c, term, 0);
 
129
        install_signal_handler(SIGTERM, (void (*)(void *))sig_terminate, term, 0);
 
130
#ifdef SIGTSTP
 
131
        install_signal_handler(SIGTSTP, (void (*)(void *))sig_tstp, term, 0);
 
132
#endif
 
133
#ifdef SIGTTIN
 
134
        install_signal_handler(SIGTTIN, (void (*)(void *))sig_tstp, term, 0);
 
135
#endif
 
136
#ifdef SIGTTOU
 
137
        install_signal_handler(SIGTTOU, (void (*)(void *))sig_ign, term, 0);
 
138
#endif
 
139
#ifdef SIGCONT
 
140
        install_signal_handler(SIGCONT, (void (*)(void *))sig_cont, term, 0);
 
141
#endif
 
142
#ifdef CONFIG_BACKTRACE
 
143
        install_signal_handler(SIGSEGV, (void (*)(void *))sig_segv, term, 1);
 
144
#endif
 
145
}
 
146
 
 
147
void
 
148
unhandle_terminal_signals(struct terminal *term)
 
149
{
 
150
        install_signal_handler(SIGHUP, NULL, NULL, 0);
 
151
        install_signal_handler(SIGINT, NULL, NULL, 0);
 
152
#ifdef SIGTSTP
 
153
        install_signal_handler(SIGTSTP, NULL, NULL, 0);
 
154
#endif
 
155
#ifdef SIGTTIN
 
156
        install_signal_handler(SIGTTIN, NULL, NULL, 0);
 
157
#endif
 
158
#ifdef SIGTTOU
 
159
        install_signal_handler(SIGTTOU, NULL, NULL, 0);
 
160
#endif
 
161
#ifdef SIGCONT
 
162
        install_signal_handler(SIGCONT, NULL, NULL, 0);
 
163
#endif
 
164
#ifdef CONFIG_BACKTRACE
 
165
        install_signal_handler(SIGSEGV, NULL, NULL, 0);
 
166
#endif
 
167
}
 
168
 
 
169
static void
 
170
unhandle_basic_signals(struct terminal *term)
 
171
{
 
172
        install_signal_handler(SIGHUP, NULL, NULL, 0);
 
173
        install_signal_handler(SIGINT, NULL, NULL, 0);
 
174
        install_signal_handler(SIGTERM, NULL, NULL, 0);
 
175
#ifdef SIGTSTP
 
176
        install_signal_handler(SIGTSTP, NULL, NULL, 0);
 
177
#endif
 
178
#ifdef SIGTTIN
 
179
        install_signal_handler(SIGTTIN, NULL, NULL, 0);
 
180
#endif
 
181
#ifdef SIGTTOU
 
182
        install_signal_handler(SIGTTOU, NULL, NULL, 0);
 
183
#endif
 
184
#ifdef SIGCONT
 
185
        install_signal_handler(SIGCONT, NULL, NULL, 0);
 
186
#endif
 
187
#ifdef CONFIG_BACKTRACE
 
188
        install_signal_handler(SIGSEGV, NULL, NULL, 0);
 
189
#endif
 
190
}
 
191
 
 
192
struct signal_info {
 
193
        void (*handler)(void *);
 
194
        void *data;
 
195
        int critical;
 
196
        int mask;
 
197
};
 
198
 
 
199
static struct signal_info signal_info[NUM_SIGNALS];
 
200
volatile int critical_section = 0;
 
201
 
 
202
static void check_for_select_race(void);
 
203
 
 
204
/* TODO: In order to gain better portability, we should use signal() instead.
 
205
 * Highest care should be given to careful watching of which signals are
 
206
 * blocked and which aren't then, though. --pasky */
 
207
 
 
208
static void
 
209
got_signal(int sig)
 
210
{
 
211
        struct signal_info *s;
 
212
 
 
213
        if (sig >= NUM_SIGNALS || sig < 0) {
 
214
                /* Signal handler - we have no good way how to tell this the
 
215
                 * user. She won't care anyway, tho'. */
 
216
                return;
 
217
        }
 
218
 
 
219
        s = &signal_info[sig];
 
220
 
 
221
        if (!s->handler) return;
 
222
 
 
223
        if (s->critical) {
 
224
                s->handler(s->data);
 
225
                return;
 
226
        }
 
227
 
 
228
        s->mask = 1;
 
229
        check_for_select_race();
 
230
}
 
231
 
 
232
void
 
233
install_signal_handler(int sig, void (*fn)(void *), void *data, int critical)
 
234
{
 
235
        struct sigaction sa = {};
 
236
 
 
237
        /* Yes, assertm() in signal handler is totally unsafe and depends just
 
238
         * on good luck. But hey, assert()ions are never triggered ;-). */
 
239
        assertm(sig >= 0 && sig < NUM_SIGNALS, "bad signal number: %d", sig);
 
240
        if_assert_failed return;
 
241
 
 
242
        if (!fn)
 
243
                sa.sa_handler = SIG_IGN;
 
244
        else
 
245
                sa.sa_handler = got_signal;
 
246
 
 
247
        sigfillset(&sa.sa_mask);
 
248
        if (!fn) sigaction(sig, &sa, NULL);
 
249
        signal_info[sig].handler = fn;
 
250
        signal_info[sig].data = data;
 
251
        signal_info[sig].critical = critical;
 
252
        if (fn) sigaction(sig, &sa, NULL);
 
253
}
 
254
 
 
255
static volatile int pending_alarm = 0;
 
256
 
 
257
static void
 
258
alarm_handler(void *x)
 
259
{
 
260
        pending_alarm = 0;
 
261
        check_for_select_race();
 
262
}
 
263
 
 
264
static void
 
265
check_for_select_race(void)
 
266
{
 
267
        if (critical_section) {
 
268
#ifdef SIGALRM
 
269
                install_signal_handler(SIGALRM, alarm_handler, NULL, 1);
 
270
#endif
 
271
                pending_alarm = 1;
 
272
#ifdef HAVE_ALARM
 
273
                alarm(1);
 
274
#endif
 
275
        }
 
276
}
 
277
 
 
278
void
 
279
uninstall_alarm(void)
 
280
{
 
281
        pending_alarm = 0;
 
282
#ifdef HAVE_ALARM
 
283
        alarm(0);
 
284
#endif
 
285
}
 
286
 
 
287
 
 
288
static void
 
289
sigchld(void *p)
 
290
{
 
291
#ifdef WNOHANG
 
292
        while ((int) waitpid(-1, NULL, WNOHANG) > 0);
 
293
#else
 
294
        wait(NULL);
 
295
#endif
 
296
}
 
297
 
 
298
void
 
299
set_sigcld(void)
 
300
{
 
301
        install_signal_handler(SIGCHLD, sigchld, NULL, 1);
 
302
}
 
303
 
 
304
void
 
305
clear_signal_mask_and_handlers(void)
 
306
{
 
307
        memset(signal_info, 0, sizeof(signal_info));
 
308
}
 
309
 
 
310
int
 
311
check_signals(void)
 
312
{
 
313
        int i, r = 0;
 
314
 
 
315
        for (i = 0; i < NUM_SIGNALS; i++) {
 
316
                struct signal_info *s = &signal_info[i];
 
317
 
 
318
                if (!s->mask) continue;
 
319
 
 
320
                s->mask = 0;
 
321
                if (s->handler)
 
322
                        s->handler(s->data);
 
323
                check_bottom_halves();
 
324
                r = 1;
 
325
        }
 
326
 
 
327
        return r;
 
328
}