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