4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
31 * Portions of this source code were derived from Berkeley
32 * 4.3 BSD under license from the regents of the University of
36 #pragma ident "%Z%%M% %I% %E% SMI"
38 /* Swap handler for SIGFPE codes. */
44 #include <floatingpoint.h>
45 #include <sys/types.h>
46 #include <sys/ucontext.h>
47 #include <sys/siginfo.h>
53 #define FPE_INTDIV 1 /* integer divide by zero */
56 #define FPE_INTOVF 2 /* integer overflow */
59 #define FPE_FLTDIV 3 /* [floating divide by zero] */
62 #define FPE_FLTOVF 4 /* [floating overflow] */
65 #define FPE_FLTUND 5 /* [floating underflow] */
68 #define FPE_FLTRES 6 /* [floating inexact result] */
71 #define FPE_FLTINV 7 /* [floating invalid operation] */
74 #if defined(__i386) || defined(__amd64)
77 #define FPE_FLTSUB 8 /* subscript out of range */
80 #define FPE_FLTDEN 9 /* x86-specific: denormal operand */
83 #define N_SIGFPE_CODE 10
87 #define N_SIGFPE_CODE 8
91 /* Array of SIGFPE codes. */
93 static const sigfpe_code_type sigfpe_codes
[N_SIGFPE_CODE
] = {
101 #if defined(__i386) || defined(__amd64)
108 /* Array of handlers. */
110 static mutex_t sigfpe_lock
= DEFAULTMUTEX
;
112 sigfpe_handler_type ieee_handlers
[N_IEEE_EXCEPTION
];
113 static sigfpe_handler_type sigfpe_handlers
[N_SIGFPE_CODE
];
115 static int _sigfpe_master_enabled
;
116 /* Originally zero, set to 1 by _enable_sigfpe_master. */
119 #define BADSIG (void (*)(void))-1
123 _sigfpe_master(int sig
, siginfo_t
*siginfo
, void *arg
)
125 ucontext_t
*ucontext
= arg
;
128 enum fp_exception_type exception
;
130 lmutex_lock(&sigfpe_lock
);
131 code
= siginfo
->si_code
;
132 for (i
= 0; (i
< N_SIGFPE_CODE
) && (code
!= sigfpe_codes
[i
]); i
++)
134 /* Find index of handler. */
135 if (i
>= N_SIGFPE_CODE
)
136 i
= N_SIGFPE_CODE
- 1;
137 switch ((intptr_t)sigfpe_handlers
[i
]) {
138 case ((intptr_t)(SIGFPE_DEFAULT
)):
141 exception
= fp_invalid
;
144 exception
= fp_inexact
;
147 exception
= fp_division
;
150 exception
= fp_underflow
;
153 exception
= fp_overflow
;
155 default: /* The common default treatment is to abort. */
158 case ((intptr_t)(SIGFPE_ABORT
)):
161 case ((intptr_t)(SIGFPE_IGNORE
)):
162 lmutex_unlock(&sigfpe_lock
);
164 default: /* User-defined not SIGFPE_DEFAULT or SIGFPE_ABORT. */
165 (sigfpe_handlers
[i
])(sig
, siginfo
, ucontext
);
166 lmutex_unlock(&sigfpe_lock
);
170 switch ((intptr_t)ieee_handlers
[(int)exception
]) {
171 case ((intptr_t)(SIGFPE_DEFAULT
)): /* Error condition but ignore it. */
172 case ((intptr_t)(SIGFPE_IGNORE
)): /* Error condition but ignore it. */
173 lmutex_unlock(&sigfpe_lock
);
175 case ((intptr_t)(SIGFPE_ABORT
)):
178 (ieee_handlers
[(int)exception
])(sig
, siginfo
, ucontext
);
179 lmutex_unlock(&sigfpe_lock
);
185 _enable_sigfpe_master(void)
187 /* Enable the sigfpe master handler always. */
188 struct sigaction newsigact
, oldsigact
;
190 newsigact
.sa_sigaction
= _sigfpe_master
;
191 (void) sigemptyset(&newsigact
.sa_mask
);
192 newsigact
.sa_flags
= SA_SIGINFO
; /* enhanced handler */
193 _sigfpe_master_enabled
= 1;
194 return (sigaction(SIGFPE
, &newsigact
, &oldsigact
));
198 _test_sigfpe_master(void)
201 * Enable the sigfpe master handler if it's never been enabled
205 if (_sigfpe_master_enabled
== 0)
206 return (_enable_sigfpe_master());
208 return (_sigfpe_master_enabled
);
212 sigfpe(sigfpe_code_type code
, sigfpe_handler_type hdl
)
214 sigfpe_handler_type oldhdl
;
217 lmutex_lock(&sigfpe_lock
);
218 (void) _test_sigfpe_master();
219 for (i
= 0; (i
< N_SIGFPE_CODE
) && (code
!= sigfpe_codes
[i
]); i
++)
221 /* Find index of handler. */
222 if (i
>= N_SIGFPE_CODE
) {
224 lmutex_unlock(&sigfpe_lock
);
225 /* Not 0 or SIGFPE code */
226 return ((sigfpe_handler_type
)BADSIG
);
228 oldhdl
= sigfpe_handlers
[i
];
229 sigfpe_handlers
[i
] = hdl
;
230 lmutex_unlock(&sigfpe_lock
);