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