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