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 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 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 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 226 __fex_hdlr(int sig, siginfo_t *sip, void *arg) 227 { 228 ucontext_t *uap = arg; 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, void *arg) 390 { 391 ucontext_t *uap = arg; 392 struct fex_handler_data *thr_handlers; 393 struct sigaction act; 394 void (*handler)() = NULL, (*simd_handler[4])(); 395 int mode, simd_mode[4], i, len, accrued, *ap; 396 unsigned int cwsw, oldcwsw, mxcsr, oldmxcsr; 397 enum fex_exception e, simd_e[4]; 398 fex_info_t info, simd_info[4]; 399 unsigned long addr; 400 siginfo_t osip = *sip; 401 sseinst_t inst; 402 403 /* check for an exception caused by an SSE instruction */ 404 if (!(uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status & 0x80)) { 405 len = __fex_parse_sse(uap, &inst); 406 if (len == 0) 407 goto not_ieee; 408 409 /* disable all traps and clear flags */ 410 __fenv_getcwsw(&oldcwsw); 411 cwsw = (oldcwsw & ~0x3f) | 0x003f0000; 412 __fenv_setcwsw(&cwsw); 413 __fenv_getmxcsr(&oldmxcsr); 414 mxcsr = (oldmxcsr & ~0x3f) | 0x1f80; 415 __fenv_setmxcsr(&mxcsr); 416 417 if ((int)inst.op & SIMD) { 418 __fex_get_simd_op(uap, &inst, simd_e, simd_info); 419 420 thr_handlers = __fex_get_thr_handlers(); 421 addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC]; 422 accrued = uap->uc_mcontext.fpregs.fp_reg_set. 423 fpchip_state.mxcsr; 424 425 e = (enum fex_exception)-1; 426 mode = FEX_NONSTOP; 427 for (i = 0; i < 4; i++) { 428 if ((int)simd_e[i] < 0) 429 continue; 430 431 e = simd_e[i]; 432 simd_mode[i] = FEX_NOHANDLER; 433 simd_handler[i] = oact.sa_handler; 434 if (thr_handlers && 435 thr_handlers[(int)e].__mode != 436 FEX_NOHANDLER) { 437 simd_mode[i] = 438 thr_handlers[(int)e].__mode; 439 simd_handler[i] = 440 thr_handlers[(int)e].__handler; 441 } 442 accrued &= ~te_bit[(int)e]; 443 switch (simd_mode[i]) { 444 case FEX_ABORT: 445 mode = FEX_ABORT; 446 break; 447 case FEX_SIGNAL: 448 if (mode != FEX_ABORT) 449 mode = FEX_SIGNAL; 450 handler = simd_handler[i]; 451 break; 452 case FEX_NOHANDLER: 453 if (mode != FEX_ABORT && mode != 454 FEX_SIGNAL) 455 mode = FEX_NOHANDLER; 456 break; 457 } 458 } 459 if (e == (enum fex_exception)-1) { 460 __fenv_setcwsw(&oldcwsw); 461 __fenv_setmxcsr(&oldmxcsr); 462 goto not_ieee; 463 } 464 accrued |= uap->uc_mcontext.fpregs.fp_reg_set. 465 fpchip_state.status; 466 ap = __fex_accrued(); 467 accrued |= *ap; 468 accrued &= 0x3d; 469 470 for (i = 0; i < 4; i++) { 471 if ((int)simd_e[i] < 0) 472 continue; 473 474 __fex_mklog(uap, (char *)addr, accrued, 475 simd_e[i], simd_mode[i], 476 (void *)simd_handler[i]); 477 } 478 479 if (mode == FEX_NOHANDLER) { 480 __fenv_setcwsw(&oldcwsw); 481 __fenv_setmxcsr(&oldmxcsr); 482 goto not_ieee; 483 } else if (mode == FEX_ABORT) { 484 abort(); 485 } else if (mode == FEX_SIGNAL) { 486 __fenv_setcwsw(&oldcwsw); 487 __fenv_setmxcsr(&oldmxcsr); 488 handler(sig, &osip, uap); 489 return; 490 } 491 492 *ap = 0; 493 for (i = 0; i < 4; i++) { 494 if ((int)simd_e[i] < 0) 495 continue; 496 497 if (simd_mode[i] == FEX_CUSTOM) { 498 handler(1 << (int)simd_e[i], 499 &simd_info[i]); 500 __fenv_setcwsw(&cwsw); 501 __fenv_setmxcsr(&mxcsr); 502 } 503 } 504 505 __fex_st_simd_result(uap, &inst, simd_e, simd_info); 506 for (i = 0; i < 4; i++) { 507 if ((int)simd_e[i] < 0) 508 continue; 509 510 accrued |= simd_info[i].flags; 511 } 512 513 if ((int)inst.op & INTREG) { 514 /* set MMX mode */ 515 #if defined(__amd64) 516 uap->uc_mcontext.fpregs.fp_reg_set. 517 fpchip_state.sw &= ~0x3800; 518 uap->uc_mcontext.fpregs.fp_reg_set. 519 fpchip_state.fctw = 0; 520 #else 521 uap->uc_mcontext.fpregs.fp_reg_set. 522 fpchip_state.state[1] &= ~0x3800; 523 uap->uc_mcontext.fpregs.fp_reg_set. 524 fpchip_state.state[2] = 0; 525 #endif 526 } 527 } else { 528 e = __fex_get_sse_op(uap, &inst, &info); 529 if ((int)e < 0) { 530 __fenv_setcwsw(&oldcwsw); 531 __fenv_setmxcsr(&oldmxcsr); 532 goto not_ieee; 533 } 534 535 mode = FEX_NOHANDLER; 536 handler = oact.sa_handler; 537 thr_handlers = __fex_get_thr_handlers(); 538 if (thr_handlers && thr_handlers[(int)e].__mode != 539 FEX_NOHANDLER) { 540 mode = thr_handlers[(int)e].__mode; 541 handler = thr_handlers[(int)e].__handler; 542 } 543 544 addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC]; 545 accrued = uap->uc_mcontext.fpregs.fp_reg_set. 546 fpchip_state.mxcsr & ~te_bit[(int)e]; 547 accrued |= uap->uc_mcontext.fpregs.fp_reg_set. 548 fpchip_state.status; 549 ap = __fex_accrued(); 550 accrued |= *ap; 551 accrued &= 0x3d; 552 __fex_mklog(uap, (char *)addr, accrued, e, mode, 553 (void *)handler); 554 555 if (mode == FEX_NOHANDLER) { 556 __fenv_setcwsw(&oldcwsw); 557 __fenv_setmxcsr(&oldmxcsr); 558 goto not_ieee; 559 } else if (mode == FEX_ABORT) { 560 abort(); 561 } else if (mode == FEX_SIGNAL) { 562 __fenv_setcwsw(&oldcwsw); 563 __fenv_setmxcsr(&oldmxcsr); 564 handler(sig, &osip, uap); 565 return; 566 } else if (mode == FEX_CUSTOM) { 567 *ap = 0; 568 if (addr >= (unsigned long)feraiseexcept && 569 addr < (unsigned long)fetestexcept) { 570 info.op = fex_other; 571 info.op1.type = info.op2.type = 572 info.res.type = fex_nodata; 573 } 574 handler(1 << (int)e, &info); 575 __fenv_setcwsw(&cwsw); 576 __fenv_setmxcsr(&mxcsr); 577 } 578 579 __fex_st_sse_result(uap, &inst, e, &info); 580 accrued |= info.flags; 581 582 #if defined(__amd64) 583 /* 584 * In 64-bit mode, the 32-bit convert-to-integer 585 * instructions zero the upper 32 bits of the 586 * destination. (We do this here and not in 587 * __fex_st_sse_result because __fex_st_sse_result 588 * can be called from __fex_st_simd_result, too.) 589 */ 590 if (inst.op == cvtss2si || inst.op == cvttss2si || 591 inst.op == cvtsd2si || inst.op == cvttsd2si) 592 inst.op1->i[1] = 0; 593 #endif 594 } 595 596 /* advance the pc past the SSE instruction */ 597 uap->uc_mcontext.gregs[REG_PC] += len; 598 goto update_state; 599 } 600 601 /* determine which exception occurred */ 602 __fex_get_x86_exc(sip, uap); 603 switch (sip->si_code) { 604 case FPE_FLTDIV: 605 e = fex_division; 606 break; 607 case FPE_FLTOVF: 608 e = fex_overflow; 609 break; 610 case FPE_FLTUND: 611 e = fex_underflow; 612 break; 613 case FPE_FLTRES: 614 e = fex_inexact; 615 break; 616 case FPE_FLTINV: 617 if ((int)(e = __fex_get_invalid_type(sip, uap)) < 0) 618 goto not_ieee; 619 break; 620 default: 621 /* not an IEEE exception */ 622 goto not_ieee; 623 } 624 625 /* get the handling mode */ 626 mode = FEX_NOHANDLER; 627 handler = oact.sa_handler; /* for log; just looking, no need to lock */ 628 thr_handlers = __fex_get_thr_handlers(); 629 if (thr_handlers && thr_handlers[(int)e].__mode != FEX_NOHANDLER) { 630 mode = thr_handlers[(int)e].__mode; 631 handler = thr_handlers[(int)e].__handler; 632 } 633 634 /* make an entry in the log of retro. diag. if need be */ 635 #if defined(__amd64) 636 addr = (unsigned long)uap->uc_mcontext.fpregs.fp_reg_set. 637 fpchip_state.rip; 638 #else 639 addr = (unsigned long)uap->uc_mcontext.fpregs.fp_reg_set. 640 fpchip_state.state[3]; 641 #endif 642 accrued = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status & 643 ~te_bit[(int)e]; 644 if (test_sse_hw) 645 accrued |= uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state. 646 mxcsr; 647 ap = __fex_accrued(); 648 accrued |= *ap; 649 accrued &= 0x3d; 650 __fex_mklog(uap, (char *)addr, accrued, e, mode, (void *)handler); 651 652 /* handle the exception based on the mode */ 653 if (mode == FEX_NOHANDLER) 654 goto not_ieee; 655 else if (mode == FEX_ABORT) 656 abort(); 657 else if (mode == FEX_SIGNAL) { 658 handler(sig, &osip, uap); 659 return; 660 } 661 662 /* disable all traps and clear flags */ 663 __fenv_getcwsw(&cwsw); 664 cwsw = (cwsw & ~0x3f) | 0x003f0000; 665 __fenv_setcwsw(&cwsw); 666 if (test_sse_hw) { 667 __fenv_getmxcsr(&mxcsr); 668 mxcsr = (mxcsr & ~0x3f) | 0x1f80; 669 __fenv_setmxcsr(&mxcsr); 670 } 671 *ap = 0; 672 673 /* decode the operation */ 674 __fex_get_op(sip, uap, &info); 675 676 /* if a custom mode handler is installed, invoke it */ 677 if (mode == FEX_CUSTOM) { 678 /* if we got here from feraiseexcept, pass dummy info */ 679 if (addr >= (unsigned long)feraiseexcept && 680 addr < (unsigned long)fetestexcept) { 681 info.op = fex_other; 682 info.op1.type = info.op2.type = info.res.type = 683 fex_nodata; 684 } 685 686 handler(1 << (int)e, &info); 687 688 /* restore modes in case the user's handler changed them */ 689 __fenv_setcwsw(&cwsw); 690 if (test_sse_hw) 691 __fenv_setmxcsr(&mxcsr); 692 } 693 694 /* stuff the result */ 695 __fex_st_result(sip, uap, &info); 696 accrued |= info.flags; 697 698 update_state: 699 accrued &= 0x3d; 700 i = __fex_te_needed(thr_handlers, accrued); 701 *ap = accrued & i; 702 #if defined(__amd64) 703 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw &= ~0x3d; 704 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= (accrued & ~i); 705 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw |= 0x3d; 706 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw &= ~i; 707 #else 708 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] &= ~0x3d; 709 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] |= 710 (accrued & ~i); 711 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] |= 0x3d; 712 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] &= ~i; 713 #endif 714 if (test_sse_hw) { 715 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &= ~0x3d; 716 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr |= 717 0x1e80 | (accrued & ~i); 718 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &= 719 ~(i << 7); 720 } 721 return; 722 723 not_ieee: 724 /* revert to the saved handler (if any) */ 725 mutex_lock(&hdlr_lock); 726 act = oact; 727 mutex_unlock(&hdlr_lock); 728 switch ((unsigned long)act.sa_handler) { 729 case (unsigned long)SIG_DFL: 730 /* simulate trap with no handler installed */ 731 sigaction(SIGFPE, &act, NULL); 732 kill(getpid(), SIGFPE); 733 break; 734 #if !defined(__lint) 735 case (unsigned long)SIG_IGN: 736 break; 737 #endif 738 default: 739 act.sa_sigaction(sig, &osip, uap); 740 } 741 } 742 743 #else 744 #error Unknown architecture 745 #endif 746 747 /* 748 * Return a pointer to the thread-specific handler data, and 749 * initialize it if necessary 750 */ 751 struct fex_handler_data * 752 __fex_get_thr_handlers() 753 { 754 struct fex_handler_data *ptr; 755 unsigned long fsr; 756 int i, te; 757 758 if (thr_main()) { 759 if (!handlers_initialized) { 760 /* initialize to FEX_NOHANDLER if trap is enabled, 761 FEX_NONSTOP if trap is disabled */ 762 __fenv_getfsr(&fsr); 763 te = (int)__fenv_get_te(fsr); 764 for (i = 0; i < FEX_NUM_EXC; i++) 765 main_handlers[i].__mode = 766 ((te & te_bit[i])? FEX_NOHANDLER : FEX_NONSTOP); 767 handlers_initialized = 1; 768 } 769 return main_handlers; 770 } 771 else { 772 ptr = NULL; 773 mutex_lock(&handlers_key_lock); 774 if (thr_getspecific(handlers_key, (void **)&ptr) != 0 && 775 thr_keycreate(&handlers_key, free) != 0) { 776 mutex_unlock(&handlers_key_lock); 777 return NULL; 778 } 779 mutex_unlock(&handlers_key_lock); 780 if (!ptr) { 781 if ((ptr = (struct fex_handler_data *) 782 malloc(sizeof(fex_handler_t))) == NULL) { 783 return NULL; 784 } 785 if (thr_setspecific(handlers_key, (void *)ptr) != 0) { 786 (void)free(ptr); 787 return NULL; 788 } 789 /* initialize to FEX_NOHANDLER if trap is enabled, 790 FEX_NONSTOP if trap is disabled */ 791 __fenv_getfsr(&fsr); 792 te = (int)__fenv_get_te(fsr); 793 for (i = 0; i < FEX_NUM_EXC; i++) 794 ptr[i].__mode = ((te & te_bit[i])? FEX_NOHANDLER : FEX_NONSTOP); 795 } 796 return ptr; 797 } 798 } 799 800 /* 801 * Update the trap enable bits according to the selected modes 802 */ 803 void 804 __fex_update_te() 805 { 806 struct fex_handler_data *thr_handlers; 807 struct sigaction act, tmpact; 808 sigset_t blocked; 809 unsigned long fsr; 810 int te; 811 812 /* determine which traps are needed */ 813 thr_handlers = __fex_get_thr_handlers(); 814 __fenv_getfsr(&fsr); 815 te = __fex_te_needed(thr_handlers, fsr); 816 817 /* install __fex_hdlr as necessary */ 818 if (!hdlr_installed && te) { 819 act.sa_sigaction = __fex_hdlr; 820 sigemptyset(&act.sa_mask); 821 act.sa_flags = SA_SIGINFO; 822 sigaction(SIGFPE, &act, &tmpact); 823 if (tmpact.sa_sigaction != __fex_hdlr) 824 { 825 mutex_lock(&hdlr_lock); 826 oact = tmpact; 827 mutex_unlock(&hdlr_lock); 828 } 829 hdlr_installed = 1; 830 } 831 832 /* set the new trap enable bits (only if SIGFPE is not blocked) */ 833 if (sigprocmask(0, NULL, &blocked) == 0 && 834 !sigismember(&blocked, SIGFPE)) { 835 __fenv_set_te(fsr, te); 836 __fenv_setfsr(&fsr); 837 } 838 839 /* synchronize with libmtsk */ 840 __mt_fex_sync = __fex_sync_with_libmtsk; 841 842 /* synchronize with other projects */ 843 __libm_mt_fex_sync = __fex_sync_with_threads; 844 } 845