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