~ubuntu-branches/ubuntu/intrepid/ecl/intrepid

« back to all changes in this revision

Viewing changes to src/c/unixint.d

  • Committer: Bazaar Package Importer
  • Author(s): Peter Van Eynde
  • Date: 2006-05-17 02:46:26 UTC
  • Revision ID: james.westby@ubuntu.com-20060517024626-lljr08ftv9g9vefl
Tags: upstream-0.9h-20060510
ImportĀ upstreamĀ versionĀ 0.9h-20060510

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    unixint.c -- Unix interrupt interface.
 
3
*/
 
4
/*
 
5
    Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
 
6
    Copyright (c) 1990, Giuseppe Attardi.
 
7
    Copyright (c) 2001, Juan Jose Garcia Ripoll.
 
8
 
 
9
    ECL is free software; you can redistribute it and/or
 
10
    modify it under the terms of the GNU Library General Public
 
11
    License as published by the Free Software Foundation; either
 
12
    version 2 of the License, or (at your option) any later version.
 
13
 
 
14
    See file '../Copyright' for full details.
 
15
*/
 
16
 
 
17
#include <ecl/ecl.h>
 
18
#if defined(HAVE_FENV_H)
 
19
# define _GNU_SOURCE
 
20
# include <fenv.h>
 
21
# ifndef FE_UNDERFLOW
 
22
#  define FE_UNDERFLOW 0
 
23
# endif
 
24
# ifndef FE_OVERFLOW
 
25
#  define FE_OVERFLOW 0
 
26
# endif
 
27
# ifndef FE_INVALID
 
28
#  define FE_INVALID 0
 
29
# endif
 
30
# ifndef FE_DIVBYZERO
 
31
#  define FE_DIVBYZERO 0
 
32
# endif
 
33
# ifndef FE_INEXACT
 
34
#  define FE_INEXACT 0
 
35
# endif
 
36
#endif
 
37
#include <signal.h>
 
38
#if defined(mingw32) || defined(_MSC_VER)
 
39
# include <windows.h>
 
40
void handle_fpe_signal(int,int);
 
41
#endif
 
42
#if !defined(_MSC_VER)
 
43
# include <unistd.h>
 
44
#endif
 
45
#include <ecl/internal.h>
 
46
 
 
47
/******************************* ------- ******************************/
 
48
 
 
49
bool ecl_interrupt_enable;
 
50
 
 
51
#ifdef HAVE_SIGPROCMASK
 
52
static void
 
53
mysignal(int code, void *handler)
 
54
{
 
55
        struct sigaction new_action, old_action;
 
56
 
 
57
        new_action.sa_sigaction = handler;
 
58
        sigemptyset(&new_action.sa_mask);
 
59
        new_action.sa_flags = SA_SIGINFO;
 
60
        sigaction(code, &new_action, &old_action);
 
61
}
 
62
#else
 
63
#define mysignal(x,y) signal(x,y)
 
64
#endif
 
65
 
 
66
static void
 
67
#ifdef SA_SIGINFO
 
68
handle_signal(int sig, siginfo_t *info, void *aux)
 
69
#else
 
70
handle_signal(int sig)
 
71
#endif
 
72
{
 
73
        switch (sig) {
 
74
#if defined(ECL_THREADS) && !defined(_MSC_VER) && !defined(mingw32)
 
75
        case SIGUSR1:
 
76
                funcall(1, cl_env.own_process->process.interrupt);
 
77
                break;
 
78
#endif
 
79
        case SIGINT:
 
80
                funcall(2, @'si::terminal-interrupt', Ct);
 
81
                break;
 
82
        case SIGFPE: {
 
83
                cl_object condition = @'arithmetic-error';
 
84
#if defined(HAVE_FENV_H)
 
85
                int bits = fetestexcept(FE_ALL_EXCEPT);
 
86
                if (bits & FE_DIVBYZERO)
 
87
                        condition = @'division-by-zero';
 
88
                if (bits & FE_OVERFLOW)
 
89
                        condition = @'floating-point-overflow';
 
90
                if (bits & FE_UNDERFLOW)
 
91
                        condition = @'floating-point-underflow';
 
92
                if (bits & FE_INEXACT)
 
93
                        condition = @'floating-point-inexact';
 
94
                if (bits & FE_INVALID)
 
95
                        condition = @'floating-point-invalid-operation';
 
96
#endif
 
97
#ifdef SA_SIGINFO
 
98
                if (info) {
 
99
                        if (info->si_code == FPE_INTDIV || info->si_code == FPE_FLTDIV)
 
100
                                condition = @'division-by-zero';
 
101
                        if (info->si_code == FPE_FLTOVF)
 
102
                                condition = @'floating-point-overflow';
 
103
                        if (info->si_code == FPE_FLTUND)
 
104
                                condition = @'floating-point-underflow';
 
105
                }
 
106
#endif
 
107
                si_trap_fpe(@'last', Ct);
 
108
                cl_error(1, condition);
 
109
                break;
 
110
        }
 
111
        case SIGSEGV:
 
112
                FEerror("Segmentation violation.", 0);
 
113
                break;
 
114
        default:
 
115
                FEerror("Serious signal ~D caught.", 1, MAKE_FIXNUM(sig));
 
116
        }
 
117
}
 
118
 
 
119
/*
 
120
 * TODO: Use POSIX signals, and in particular use sigaltstack to
 
121
 * handle stack overflows gracefully.
 
122
 */
 
123
static void
 
124
#ifdef SA_SIGINFO
 
125
signal_catcher(int sig, siginfo_t *siginfo, void *data)
 
126
#else
 
127
signal_catcher(int sig)
 
128
#endif
 
129
{
 
130
        if (!ecl_interrupt_enable ||
 
131
            symbol_value(@'si::*interrupt-enable*') == Cnil) {
 
132
                mysignal(sig, signal_catcher);
 
133
                cl_env.interrupt_pending = sig;
 
134
                return;
 
135
        }
 
136
        mysignal(sig, signal_catcher);
 
137
#ifdef HAVE_SIGPROCMASK
 
138
        CL_UNWIND_PROTECT_BEGIN {
 
139
                handle_signal(sig, siginfo, data);
 
140
        } CL_UNWIND_PROTECT_EXIT {
 
141
                sigset_t block_mask;
 
142
                sigemptyset(&block_mask);
 
143
                sigaddset(&block_mask, sig);
 
144
#ifdef ECL_THREADS
 
145
                pthread_sigmask(SIG_UNBLOCK, &block_mask, NULL);
 
146
#else
 
147
                sigprocmask(SIG_UNBLOCK, &block_mask, NULL);
 
148
#endif
 
149
        } CL_UNWIND_PROTECT_END;
 
150
#else
 
151
#if defined (_MSC_VER)
 
152
        if (sig == SIGFPE) {
 
153
                handle_fpe_signal(sig, _fpecode);
 
154
        }
 
155
#endif
 
156
        handle_signal(sig);
 
157
#endif
 
158
}
 
159
 
 
160
cl_object
 
161
si_check_pending_interrupts(void)
 
162
{
 
163
        int what = cl_env.interrupt_pending;
 
164
        cl_env.interrupt_pending = 0;
 
165
#ifdef HAVE_SIGPROCMASK
 
166
        handle_signal(what, 0, 0);
 
167
#else
 
168
        handle_signal(what);
 
169
#endif
 
170
        @(return)
 
171
}
 
172
 
 
173
cl_object
 
174
si_catch_bad_signals()
 
175
{
 
176
        mysignal(SIGILL, signal_catcher);
 
177
#ifndef GBC_BOEHM
 
178
        mysignal(SIGBUS, signal_catcher);
 
179
#endif
 
180
        mysignal(SIGSEGV, signal_catcher);
 
181
#ifdef SIGIOT
 
182
        mysignal(SIGIOT, signal_catcher);
 
183
#endif
 
184
#ifdef SIGEMT
 
185
        mysignal(SIGEMT, signal_catcher);
 
186
#endif
 
187
#ifdef SIGSYS
 
188
        mysignal(SIGSYS, signal_catcher);
 
189
#endif
 
190
        @(return Ct)
 
191
}
 
192
 
 
193
cl_object
 
194
si_uncatch_bad_signals()
 
195
{
 
196
        mysignal(SIGILL, SIG_DFL);
 
197
#ifndef GBC_BOEHM
 
198
        mysignal(SIGBUS, SIG_DFL);
 
199
#endif
 
200
        mysignal(SIGSEGV, SIG_DFL);
 
201
#ifdef SIGIOT
 
202
        mysignal(SIGIOT, SIG_DFL);
 
203
#endif
 
204
#ifdef SIGEMT
 
205
        mysignal(SIGEMT, SIG_DFL);
 
206
#endif
 
207
#ifdef SIGSYS
 
208
        mysignal(SIGSYS, SIG_DFL);
 
209
#endif
 
210
        @(return Ct)
 
211
}
 
212
 
 
213
#ifdef _MSC_VER
 
214
LONG WINAPI W32_exception_filter(struct _EXCEPTION_POINTERS* ep)
 
215
{
 
216
        LONG excpt_result;
 
217
 
 
218
        excpt_result = EXCEPTION_CONTINUE_EXECUTION;
 
219
        switch (ep->ExceptionRecord->ExceptionCode)
 
220
        {
 
221
                /* Catch all arithmetic exceptions */
 
222
                case EXCEPTION_INT_DIVIDE_BY_ZERO:
 
223
                case EXCEPTION_INT_OVERFLOW:
 
224
                case EXCEPTION_FLT_DIVIDE_BY_ZERO:
 
225
                case EXCEPTION_FLT_OVERFLOW:
 
226
                case EXCEPTION_FLT_UNDERFLOW:
 
227
                case EXCEPTION_FLT_INEXACT_RESULT:
 
228
                case EXCEPTION_FLT_DENORMAL_OPERAND:
 
229
                case EXCEPTION_FLT_INVALID_OPERATION:
 
230
                case EXCEPTION_FLT_STACK_CHECK:
 
231
                        handle_signal(SIGFPE);
 
232
                        break;
 
233
                /* Catch segmentation fault */
 
234
                case EXCEPTION_ACCESS_VIOLATION:
 
235
                        handle_signal(SIGSEGV);
 
236
                        break;
 
237
                /* Catch illegal instruction */
 
238
                case EXCEPTION_ILLEGAL_INSTRUCTION:
 
239
                        handle_signal(SIGILL);
 
240
                        break;
 
241
                /* Do not catch anything else */
 
242
                default:
 
243
                        excpt_result = EXCEPTION_CONTINUE_SEARCH;
 
244
                        break;
 
245
        }
 
246
 
 
247
        return excpt_result;
 
248
}
 
249
 
 
250
void handle_fpe_signal(int sig, int num)
 
251
{
 
252
        cl_object condition = @'arithmetic-error';
 
253
 
 
254
        switch (num) {
 
255
        case _FPE_OVERFLOW:
 
256
                condition = @'floating-point-overflow';
 
257
                break;
 
258
        case _FPE_UNDERFLOW:
 
259
                condition = @'floating-point-underflow';
 
260
                break;
 
261
        case _FPE_ZERODIVIDE:
 
262
                condition = @'division-by-zero';
 
263
                break;
 
264
        }
 
265
 
 
266
        si_trap_fpe(@'last', Ct);
 
267
        cl_error(1, condition);
 
268
}
 
269
 
 
270
BOOL WINAPI W32_console_ctrl_handler(DWORD type)
 
271
{
 
272
        switch (type)
 
273
        {
 
274
                /* Catch CTRL-C */
 
275
                case CTRL_C_EVENT:
 
276
                        handle_signal(SIGINT);
 
277
                        return TRUE;
 
278
        }
 
279
        return FALSE;
 
280
}
 
281
#endif
 
282
 
 
283
cl_object
 
284
si_trap_fpe(cl_object condition, cl_object flag)
 
285
{
 
286
#if (defined(HAVE_FENV_H) && defined(HAVE_FEENABLEEXCEPT)) || defined(_MSC_VER) || defined(mingw32)
 
287
        static int last_bits = 0;
 
288
        int bits = 0;
 
289
        if (condition == @'division-by-zero')
 
290
                bits = FE_DIVBYZERO;
 
291
        else if (condition == @'floating-point-overflow')
 
292
                bits = FE_OVERFLOW;
 
293
        else if (condition == @'floating-point-underflow')
 
294
                bits = FE_UNDERFLOW;
 
295
        else if (condition == Ct)
 
296
                bits = FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW;
 
297
        else if (condition == @'last')
 
298
                bits = last_bits;
 
299
#if defined(_MSC_VER) || defined(mingw32)
 
300
        _fpreset();
 
301
#endif
 
302
        if (bits) {
 
303
                if (flag == Cnil) {
 
304
                        fedisableexcept(bits);
 
305
                        last_bits &= ~bits;
 
306
                } else {
 
307
                        feenableexcept(bits);
 
308
                        last_bits |= bits;
 
309
                }
 
310
        }
 
311
#endif
 
312
        @(return flag)
 
313
}       
 
314
 
 
315
void
 
316
init_unixint(void)
 
317
{
 
318
        mysignal(SIGFPE, signal_catcher);
 
319
        si_trap_fpe(Ct, Ct);
 
320
        mysignal(SIGINT, signal_catcher);
 
321
#if defined(ECL_THREADS) && !defined(_MSC_VER) && !defined(mingw32)
 
322
        mysignal(SIGUSR1, signal_catcher);
 
323
#endif
 
324
#ifdef _MSC_VER
 
325
        SetUnhandledExceptionFilter(W32_exception_filter);
 
326
        SetConsoleCtrlHandler(W32_console_ctrl_handler, TRUE);
 
327
#endif
 
328
        ECL_SET(@'si::*interrupt-enable*', Ct);
 
329
        ecl_interrupt_enable = 1;
 
330
}