dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libm / common / m9x / __fex_hdlr.c
blob054dd9601357507b9da68b49edd4ae63982cf915
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
26 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
30 #undef lint
31 #include <signal.h>
32 #include <siginfo.h>
33 #include <ucontext.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <thread.h>
38 #include <math.h>
39 #include <fenv.h>
40 #include "fex_handler.h"
41 #include "fenv_inlines.h"
43 #if defined(__sparc) && !defined(__sparcv9)
44 #include <sys/procfs.h>
45 #endif
47 /* 2.x signal.h doesn't declare sigemptyset or sigismember
48 if they're #defined (see sys/signal.h) */
49 extern int sigemptyset(sigset_t *);
50 extern int sigismember(const sigset_t *, int);
52 /* external globals */
53 void (*__mt_fex_sync)() = NULL; /* for synchronization with libmtsk */
54 #pragma weak __mt_fex_sync
56 void (*__libm_mt_fex_sync)() = NULL; /* new, improved version of above */
57 #pragma weak __libm_mt_fex_sync
59 /* private variables */
60 static fex_handler_t main_handlers;
61 static int handlers_initialized = 0;
62 static thread_key_t handlers_key;
63 static mutex_t handlers_key_lock = DEFAULTMUTEX;
65 static struct sigaction oact = { 0, SIG_DFL };
66 static mutex_t hdlr_lock = DEFAULTMUTEX;
67 static int hdlr_installed = 0;
69 /* private const data */
70 static const int te_bit[FEX_NUM_EXC] = {
71 1 << fp_trap_inexact,
72 1 << fp_trap_division,
73 1 << fp_trap_underflow,
74 1 << fp_trap_overflow,
75 1 << fp_trap_invalid,
76 1 << fp_trap_invalid,
77 1 << fp_trap_invalid,
78 1 << fp_trap_invalid,
79 1 << fp_trap_invalid,
80 1 << fp_trap_invalid,
81 1 << fp_trap_invalid,
82 1 << fp_trap_invalid
86 * Return the traps to be enabled given the current handling modes
87 * and flags
89 static int
90 __fex_te_needed(struct fex_handler_data *thr_handlers, unsigned long fsr)
92 int i, ex, te;
94 /* set traps for handling modes */
95 te = 0;
96 for (i = 0; i < FEX_NUM_EXC; i++)
97 if (thr_handlers[i].__mode != FEX_NONSTOP)
98 te |= te_bit[i];
100 /* add traps for retrospective diagnostics */
101 if (fex_get_log()) {
102 ex = (int)__fenv_get_ex(fsr);
103 if (!(ex & FE_INEXACT))
104 te |= (1 << fp_trap_inexact);
105 if (!(ex & FE_UNDERFLOW))
106 te |= (1 << fp_trap_underflow);
107 if (!(ex & FE_OVERFLOW))
108 te |= (1 << fp_trap_overflow);
109 if (!(ex & FE_DIVBYZERO))
110 te |= (1 << fp_trap_division);
111 if (!(ex & FE_INVALID))
112 te |= (1 << fp_trap_invalid);
115 return te;
119 * The following function synchronizes with libmtsk (SPARC only, for now)
121 static void
122 __fex_sync_with_libmtsk(int begin, int master)
124 static fenv_t master_env;
125 static int env_initialized = 0;
126 static mutex_t env_lock = DEFAULTMUTEX;
128 if (begin) {
129 mutex_lock(&env_lock);
130 if (master) {
131 (void) fegetenv(&master_env);
132 env_initialized = 1;
134 else if (env_initialized)
135 (void) fesetenv(&master_env);
136 mutex_unlock(&env_lock);
138 else if (master && fex_get_log())
139 __fex_update_te();
143 * The following function may be used for synchronization with any
144 * internal project that manages multiple threads
146 enum __libm_mt_fex_sync_actions {
147 __libm_mt_fex_start_master = 0,
148 __libm_mt_fex_start_slave,
149 __libm_mt_fex_finish_master,
150 __libm_mt_fex_finish_slave
153 struct __libm_mt_fex_sync_data {
154 fenv_t master_env;
155 int initialized;
156 mutex_t lock;
159 static void
160 __fex_sync_with_threads(enum __libm_mt_fex_sync_actions action,
161 struct __libm_mt_fex_sync_data *thr_env)
163 switch (action) {
164 case __libm_mt_fex_start_master:
165 mutex_lock(&thr_env->lock);
166 (void) fegetenv(&thr_env->master_env);
167 thr_env->initialized = 1;
168 mutex_unlock(&thr_env->lock);
169 break;
171 case __libm_mt_fex_start_slave:
172 mutex_lock(&thr_env->lock);
173 if (thr_env->initialized)
174 (void) fesetenv(&thr_env->master_env);
175 mutex_unlock(&thr_env->lock);
176 break;
178 case __libm_mt_fex_finish_master:
179 #if defined(__x86)
180 __fex_update_te();
181 #else
182 if (fex_get_log())
183 __fex_update_te();
184 #endif
185 break;
187 case __libm_mt_fex_finish_slave:
188 #if defined(__x86)
189 /* clear traps, making all accrued flags visible in status word */
191 unsigned long fsr;
192 __fenv_getfsr(&fsr);
193 __fenv_set_te(fsr, 0);
194 __fenv_setfsr(&fsr);
196 #endif
197 break;
201 #if defined(__sparc)
204 * Code for setting or clearing interval mode on US-III and above.
205 * This is embedded as data so we don't have to mark the library
206 * as a v8plusb/v9b object. (I could have just used one entry and
207 * modified the second word to set the bits I want, but that would
208 * have required another mutex.)
210 static const unsigned int siam[][2] = {
211 { 0x81c3e008, 0x81b01020 }, /* retl, siam 0 */
212 { 0x81c3e008, 0x81b01024 }, /* retl, siam 4 */
213 { 0x81c3e008, 0x81b01025 }, /* retl, siam 5 */
214 { 0x81c3e008, 0x81b01026 }, /* retl, siam 6 */
215 { 0x81c3e008, 0x81b01027 } /* retl, siam 7 */
219 * If a handling mode is in effect, apply it; otherwise invoke the
220 * saved handler
222 static void
223 __fex_hdlr(int sig, siginfo_t *sip, ucontext_t *uap)
225 struct fex_handler_data *thr_handlers;
226 struct sigaction act;
227 void (*handler)(), (*siamp)();
228 int mode, i;
229 enum fex_exception e;
230 fex_info_t info;
231 unsigned long fsr, tmpfsr, addr;
232 unsigned int gsr;
234 /* determine which exception occurred */
235 switch (sip->si_code) {
236 case FPE_FLTDIV:
237 e = fex_division;
238 break;
239 case FPE_FLTOVF:
240 e = fex_overflow;
241 break;
242 case FPE_FLTUND:
243 e = fex_underflow;
244 break;
245 case FPE_FLTRES:
246 e = fex_inexact;
247 break;
248 case FPE_FLTINV:
249 if ((int)(e = __fex_get_invalid_type(sip, uap)) < 0)
250 goto not_ieee;
251 break;
252 default:
253 /* not an IEEE exception */
254 goto not_ieee;
257 /* get the handling mode */
258 mode = FEX_NOHANDLER;
259 handler = oact.sa_handler; /* for log; just looking, no need to lock */
260 thr_handlers = __fex_get_thr_handlers();
261 if (thr_handlers && thr_handlers[(int)e].__mode != FEX_NOHANDLER) {
262 mode = thr_handlers[(int)e].__mode;
263 handler = thr_handlers[(int)e].__handler;
266 /* make an entry in the log of retro. diag. if need be */
267 i = ((int)uap->uc_mcontext.fpregs.fpu_fsr >> 5) & 0x1f;
268 __fex_mklog(uap, (char *)sip->si_addr, i, e, mode, (void *)handler);
270 /* handle the exception based on the mode */
271 if (mode == FEX_NOHANDLER)
272 goto not_ieee;
273 else if (mode == FEX_ABORT)
274 abort();
275 else if (mode == FEX_SIGNAL) {
276 handler(sig, sip, uap);
277 return;
280 /* custom or nonstop mode; disable traps and clear flags */
281 __fenv_getfsr(&fsr);
282 __fenv_set_te(fsr, 0);
283 __fenv_set_ex(fsr, 0);
285 /* if interval mode was set, clear it, then substitute the
286 interval rounding direction and clear ns mode in the fsr */
287 #ifdef __sparcv9
288 gsr = uap->uc_mcontext.asrs[3];
289 #else
290 gsr = 0;
291 if (uap->uc_mcontext.xrs.xrs_id == XRS_ID)
292 gsr = (*(unsigned long long*)((prxregset_t*)uap->uc_mcontext.
293 xrs.xrs_ptr)->pr_un.pr_v8p.pr_filler);
294 #endif
295 gsr = (gsr >> 25) & 7;
296 if (gsr & 4) {
297 siamp = (void (*)()) siam[0];
298 siamp();
299 tmpfsr = fsr;
300 fsr = (fsr & ~0xc0400000ul) | ((gsr & 3) << 30);
302 __fenv_setfsr(&fsr);
304 /* decode the operation */
305 __fex_get_op(sip, uap, &info);
307 /* if a custom mode handler is installed, invoke it */
308 if (mode == FEX_CUSTOM) {
309 /* if we got here from feraiseexcept, pass dummy info */
310 addr = (unsigned long)sip->si_addr;
311 if (addr >= (unsigned long)feraiseexcept &&
312 addr < (unsigned long)fetestexcept) {
313 info.op = fex_other;
314 info.op1.type = info.op2.type = info.res.type =
315 fex_nodata;
318 /* restore interval mode if it was set, and put the original
319 rounding direction and ns mode back in the fsr */
320 if (gsr & 4) {
321 __fenv_setfsr(&tmpfsr);
322 siamp = (void (*)()) siam[1 + (gsr & 3)];
323 siamp();
326 handler(1 << (int)e, &info);
328 /* restore modes in case the user's handler changed them */
329 if (gsr & 4) {
330 siamp = (void (*)()) siam[0];
331 siamp();
333 __fenv_setfsr(&fsr);
336 /* stuff the result */
337 __fex_st_result(sip, uap, &info);
339 /* "or" in any exception flags and update traps */
340 fsr = uap->uc_mcontext.fpregs.fpu_fsr;
341 fsr |= ((info.flags & 0x1f) << 5);
342 i = __fex_te_needed(thr_handlers, fsr);
343 __fenv_set_te(fsr, i);
344 uap->uc_mcontext.fpregs.fpu_fsr = fsr;
345 return;
347 not_ieee:
348 /* revert to the saved handler (if any) */
349 mutex_lock(&hdlr_lock);
350 act = oact;
351 mutex_unlock(&hdlr_lock);
352 switch ((unsigned long)act.sa_handler) {
353 case (unsigned long)SIG_DFL:
354 /* simulate trap with no handler installed */
355 sigaction(SIGFPE, &act, NULL);
356 kill(getpid(), SIGFPE);
357 break;
358 case (unsigned long)SIG_IGN:
359 break;
360 default:
361 act.sa_handler(sig, sip, uap);
365 #elif defined(__x86)
367 #if defined(__amd64)
368 #define test_sse_hw 1
369 #else
370 extern int _sse_hw;
371 #define test_sse_hw _sse_hw
372 #endif
374 #if !defined(REG_PC)
375 #define REG_PC EIP
376 #endif
379 * If a handling mode is in effect, apply it; otherwise invoke the
380 * saved handler
382 static void
383 __fex_hdlr(int sig, siginfo_t *sip, ucontext_t *uap)
385 struct fex_handler_data *thr_handlers;
386 struct sigaction act;
387 void (*handler)() = NULL, (*simd_handler[4])();
388 int mode, simd_mode[4], i, len, accrued, *ap;
389 unsigned int cwsw, oldcwsw, mxcsr, oldmxcsr;
390 enum fex_exception e, simd_e[4];
391 fex_info_t info, simd_info[4];
392 unsigned long addr;
393 siginfo_t osip = *sip;
394 sseinst_t inst;
396 /* check for an exception caused by an SSE instruction */
397 if (!(uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status & 0x80)) {
398 len = __fex_parse_sse(uap, &inst);
399 if (len == 0)
400 goto not_ieee;
402 /* disable all traps and clear flags */
403 __fenv_getcwsw(&oldcwsw);
404 cwsw = (oldcwsw & ~0x3f) | 0x003f0000;
405 __fenv_setcwsw(&cwsw);
406 __fenv_getmxcsr(&oldmxcsr);
407 mxcsr = (oldmxcsr & ~0x3f) | 0x1f80;
408 __fenv_setmxcsr(&mxcsr);
410 if ((int)inst.op & SIMD) {
411 __fex_get_simd_op(uap, &inst, simd_e, simd_info);
413 thr_handlers = __fex_get_thr_handlers();
414 addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC];
415 accrued = uap->uc_mcontext.fpregs.fp_reg_set.
416 fpchip_state.mxcsr;
418 e = (enum fex_exception)-1;
419 mode = FEX_NONSTOP;
420 for (i = 0; i < 4; i++) {
421 if ((int)simd_e[i] < 0)
422 continue;
424 e = simd_e[i];
425 simd_mode[i] = FEX_NOHANDLER;
426 simd_handler[i] = oact.sa_handler;
427 if (thr_handlers &&
428 thr_handlers[(int)e].__mode !=
429 FEX_NOHANDLER) {
430 simd_mode[i] =
431 thr_handlers[(int)e].__mode;
432 simd_handler[i] =
433 thr_handlers[(int)e].__handler;
435 accrued &= ~te_bit[(int)e];
436 switch (simd_mode[i]) {
437 case FEX_ABORT:
438 mode = FEX_ABORT;
439 break;
440 case FEX_SIGNAL:
441 if (mode != FEX_ABORT)
442 mode = FEX_SIGNAL;
443 handler = simd_handler[i];
444 break;
445 case FEX_NOHANDLER:
446 if (mode != FEX_ABORT && mode !=
447 FEX_SIGNAL)
448 mode = FEX_NOHANDLER;
449 break;
452 if (e == (enum fex_exception)-1) {
453 __fenv_setcwsw(&oldcwsw);
454 __fenv_setmxcsr(&oldmxcsr);
455 goto not_ieee;
457 accrued |= uap->uc_mcontext.fpregs.fp_reg_set.
458 fpchip_state.status;
459 ap = __fex_accrued();
460 accrued |= *ap;
461 accrued &= 0x3d;
463 for (i = 0; i < 4; i++) {
464 if ((int)simd_e[i] < 0)
465 continue;
467 __fex_mklog(uap, (char *)addr, accrued,
468 simd_e[i], simd_mode[i],
469 (void *)simd_handler[i]);
472 if (mode == FEX_NOHANDLER) {
473 __fenv_setcwsw(&oldcwsw);
474 __fenv_setmxcsr(&oldmxcsr);
475 goto not_ieee;
476 } else if (mode == FEX_ABORT) {
477 abort();
478 } else if (mode == FEX_SIGNAL) {
479 __fenv_setcwsw(&oldcwsw);
480 __fenv_setmxcsr(&oldmxcsr);
481 handler(sig, &osip, uap);
482 return;
485 *ap = 0;
486 for (i = 0; i < 4; i++) {
487 if ((int)simd_e[i] < 0)
488 continue;
490 if (simd_mode[i] == FEX_CUSTOM) {
491 handler(1 << (int)simd_e[i],
492 &simd_info[i]);
493 __fenv_setcwsw(&cwsw);
494 __fenv_setmxcsr(&mxcsr);
498 __fex_st_simd_result(uap, &inst, simd_e, simd_info);
499 for (i = 0; i < 4; i++) {
500 if ((int)simd_e[i] < 0)
501 continue;
503 accrued |= simd_info[i].flags;
506 if ((int)inst.op & INTREG) {
507 /* set MMX mode */
508 #if defined(__amd64)
509 uap->uc_mcontext.fpregs.fp_reg_set.
510 fpchip_state.sw &= ~0x3800;
511 uap->uc_mcontext.fpregs.fp_reg_set.
512 fpchip_state.fctw = 0;
513 #else
514 uap->uc_mcontext.fpregs.fp_reg_set.
515 fpchip_state.state[1] &= ~0x3800;
516 uap->uc_mcontext.fpregs.fp_reg_set.
517 fpchip_state.state[2] = 0;
518 #endif
520 } else {
521 e = __fex_get_sse_op(uap, &inst, &info);
522 if ((int)e < 0) {
523 __fenv_setcwsw(&oldcwsw);
524 __fenv_setmxcsr(&oldmxcsr);
525 goto not_ieee;
528 mode = FEX_NOHANDLER;
529 handler = oact.sa_handler;
530 thr_handlers = __fex_get_thr_handlers();
531 if (thr_handlers && thr_handlers[(int)e].__mode !=
532 FEX_NOHANDLER) {
533 mode = thr_handlers[(int)e].__mode;
534 handler = thr_handlers[(int)e].__handler;
537 addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC];
538 accrued = uap->uc_mcontext.fpregs.fp_reg_set.
539 fpchip_state.mxcsr & ~te_bit[(int)e];
540 accrued |= uap->uc_mcontext.fpregs.fp_reg_set.
541 fpchip_state.status;
542 ap = __fex_accrued();
543 accrued |= *ap;
544 accrued &= 0x3d;
545 __fex_mklog(uap, (char *)addr, accrued, e, mode,
546 (void *)handler);
548 if (mode == FEX_NOHANDLER) {
549 __fenv_setcwsw(&oldcwsw);
550 __fenv_setmxcsr(&oldmxcsr);
551 goto not_ieee;
552 } else if (mode == FEX_ABORT) {
553 abort();
554 } else if (mode == FEX_SIGNAL) {
555 __fenv_setcwsw(&oldcwsw);
556 __fenv_setmxcsr(&oldmxcsr);
557 handler(sig, &osip, uap);
558 return;
559 } else if (mode == FEX_CUSTOM) {
560 *ap = 0;
561 if (addr >= (unsigned long)feraiseexcept &&
562 addr < (unsigned long)fetestexcept) {
563 info.op = fex_other;
564 info.op1.type = info.op2.type =
565 info.res.type = fex_nodata;
567 handler(1 << (int)e, &info);
568 __fenv_setcwsw(&cwsw);
569 __fenv_setmxcsr(&mxcsr);
572 __fex_st_sse_result(uap, &inst, e, &info);
573 accrued |= info.flags;
575 #if defined(__amd64)
577 * In 64-bit mode, the 32-bit convert-to-integer
578 * instructions zero the upper 32 bits of the
579 * destination. (We do this here and not in
580 * __fex_st_sse_result because __fex_st_sse_result
581 * can be called from __fex_st_simd_result, too.)
583 if (inst.op == cvtss2si || inst.op == cvttss2si ||
584 inst.op == cvtsd2si || inst.op == cvttsd2si)
585 inst.op1->i[1] = 0;
586 #endif
589 /* advance the pc past the SSE instruction */
590 uap->uc_mcontext.gregs[REG_PC] += len;
591 goto update_state;
594 /* determine which exception occurred */
595 __fex_get_x86_exc(sip, uap);
596 switch (sip->si_code) {
597 case FPE_FLTDIV:
598 e = fex_division;
599 break;
600 case FPE_FLTOVF:
601 e = fex_overflow;
602 break;
603 case FPE_FLTUND:
604 e = fex_underflow;
605 break;
606 case FPE_FLTRES:
607 e = fex_inexact;
608 break;
609 case FPE_FLTINV:
610 if ((int)(e = __fex_get_invalid_type(sip, uap)) < 0)
611 goto not_ieee;
612 break;
613 default:
614 /* not an IEEE exception */
615 goto not_ieee;
618 /* get the handling mode */
619 mode = FEX_NOHANDLER;
620 handler = oact.sa_handler; /* for log; just looking, no need to lock */
621 thr_handlers = __fex_get_thr_handlers();
622 if (thr_handlers && thr_handlers[(int)e].__mode != FEX_NOHANDLER) {
623 mode = thr_handlers[(int)e].__mode;
624 handler = thr_handlers[(int)e].__handler;
627 /* make an entry in the log of retro. diag. if need be */
628 #if defined(__amd64)
629 addr = (unsigned long)uap->uc_mcontext.fpregs.fp_reg_set.
630 fpchip_state.rip;
631 #else
632 addr = (unsigned long)uap->uc_mcontext.fpregs.fp_reg_set.
633 fpchip_state.state[3];
634 #endif
635 accrued = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status &
636 ~te_bit[(int)e];
637 if (test_sse_hw)
638 accrued |= uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.
639 mxcsr;
640 ap = __fex_accrued();
641 accrued |= *ap;
642 accrued &= 0x3d;
643 __fex_mklog(uap, (char *)addr, accrued, e, mode, (void *)handler);
645 /* handle the exception based on the mode */
646 if (mode == FEX_NOHANDLER)
647 goto not_ieee;
648 else if (mode == FEX_ABORT)
649 abort();
650 else if (mode == FEX_SIGNAL) {
651 handler(sig, &osip, uap);
652 return;
655 /* disable all traps and clear flags */
656 __fenv_getcwsw(&cwsw);
657 cwsw = (cwsw & ~0x3f) | 0x003f0000;
658 __fenv_setcwsw(&cwsw);
659 if (test_sse_hw) {
660 __fenv_getmxcsr(&mxcsr);
661 mxcsr = (mxcsr & ~0x3f) | 0x1f80;
662 __fenv_setmxcsr(&mxcsr);
664 *ap = 0;
666 /* decode the operation */
667 __fex_get_op(sip, uap, &info);
669 /* if a custom mode handler is installed, invoke it */
670 if (mode == FEX_CUSTOM) {
671 /* if we got here from feraiseexcept, pass dummy info */
672 if (addr >= (unsigned long)feraiseexcept &&
673 addr < (unsigned long)fetestexcept) {
674 info.op = fex_other;
675 info.op1.type = info.op2.type = info.res.type =
676 fex_nodata;
679 handler(1 << (int)e, &info);
681 /* restore modes in case the user's handler changed them */
682 __fenv_setcwsw(&cwsw);
683 if (test_sse_hw)
684 __fenv_setmxcsr(&mxcsr);
687 /* stuff the result */
688 __fex_st_result(sip, uap, &info);
689 accrued |= info.flags;
691 update_state:
692 accrued &= 0x3d;
693 i = __fex_te_needed(thr_handlers, accrued);
694 *ap = accrued & i;
695 #if defined(__amd64)
696 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw &= ~0x3d;
697 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= (accrued & ~i);
698 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw |= 0x3d;
699 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw &= ~i;
700 #else
701 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] &= ~0x3d;
702 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] |=
703 (accrued & ~i);
704 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] |= 0x3d;
705 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] &= ~i;
706 #endif
707 if (test_sse_hw) {
708 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &= ~0x3d;
709 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr |=
710 0x1e80 | (accrued & ~i);
711 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &=
712 ~(i << 7);
714 return;
716 not_ieee:
717 /* revert to the saved handler (if any) */
718 mutex_lock(&hdlr_lock);
719 act = oact;
720 mutex_unlock(&hdlr_lock);
721 switch ((unsigned long)act.sa_handler) {
722 case (unsigned long)SIG_DFL:
723 /* simulate trap with no handler installed */
724 sigaction(SIGFPE, &act, NULL);
725 kill(getpid(), SIGFPE);
726 break;
727 case (unsigned long)SIG_IGN:
728 break;
729 default:
730 act.sa_handler(sig, &osip, uap);
734 #else
735 #error Unknown architecture
736 #endif
739 * Return a pointer to the thread-specific handler data, and
740 * initialize it if necessary
742 struct fex_handler_data *
743 __fex_get_thr_handlers()
745 struct fex_handler_data *ptr;
746 unsigned long fsr;
747 int i, te;
749 if (thr_main()) {
750 if (!handlers_initialized) {
751 /* initialize to FEX_NOHANDLER if trap is enabled,
752 FEX_NONSTOP if trap is disabled */
753 __fenv_getfsr(&fsr);
754 te = (int)__fenv_get_te(fsr);
755 for (i = 0; i < FEX_NUM_EXC; i++)
756 main_handlers[i].__mode =
757 ((te & te_bit[i])? FEX_NOHANDLER : FEX_NONSTOP);
758 handlers_initialized = 1;
760 return main_handlers;
762 else {
763 ptr = NULL;
764 mutex_lock(&handlers_key_lock);
765 if (thr_getspecific(handlers_key, (void **)&ptr) != 0 &&
766 thr_keycreate(&handlers_key, free) != 0) {
767 mutex_unlock(&handlers_key_lock);
768 return NULL;
770 mutex_unlock(&handlers_key_lock);
771 if (!ptr) {
772 if ((ptr = (struct fex_handler_data *)
773 malloc(sizeof(fex_handler_t))) == NULL) {
774 return NULL;
776 if (thr_setspecific(handlers_key, (void *)ptr) != 0) {
777 (void)free(ptr);
778 return NULL;
780 /* initialize to FEX_NOHANDLER if trap is enabled,
781 FEX_NONSTOP if trap is disabled */
782 __fenv_getfsr(&fsr);
783 te = (int)__fenv_get_te(fsr);
784 for (i = 0; i < FEX_NUM_EXC; i++)
785 ptr[i].__mode = ((te & te_bit[i])? FEX_NOHANDLER : FEX_NONSTOP);
787 return ptr;
792 * Update the trap enable bits according to the selected modes
794 void
795 __fex_update_te()
797 struct fex_handler_data *thr_handlers;
798 struct sigaction act, tmpact;
799 sigset_t blocked;
800 unsigned long fsr;
801 int te;
803 /* determine which traps are needed */
804 thr_handlers = __fex_get_thr_handlers();
805 __fenv_getfsr(&fsr);
806 te = __fex_te_needed(thr_handlers, fsr);
808 /* install __fex_hdlr as necessary */
809 if (!hdlr_installed && te) {
810 act.sa_handler = __fex_hdlr;
811 sigemptyset(&act.sa_mask);
812 act.sa_flags = SA_SIGINFO;
813 sigaction(SIGFPE, &act, &tmpact);
814 if (tmpact.sa_handler != __fex_hdlr)
816 mutex_lock(&hdlr_lock);
817 oact = tmpact;
818 mutex_unlock(&hdlr_lock);
820 hdlr_installed = 1;
823 /* set the new trap enable bits (only if SIGFPE is not blocked) */
824 if (sigprocmask(0, NULL, &blocked) == 0 &&
825 !sigismember(&blocked, SIGFPE)) {
826 __fenv_set_te(fsr, te);
827 __fenv_setfsr(&fsr);
830 /* synchronize with libmtsk */
831 __mt_fex_sync = __fex_sync_with_libmtsk;
833 /* synchronize with other projects */
834 __libm_mt_fex_sync = __fex_sync_with_threads;