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