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, ucontext_t *uap) 227 { 228 struct fex_handler_data *thr_handlers; 229 struct sigaction act; 230 void (*handler)(), (*siamp)(); 231 int mode, i; 232 enum fex_exception e; 233 fex_info_t info; 234 unsigned long fsr, tmpfsr, addr; 235 unsigned int gsr; 236 237 /* determine which exception occurred */ 238 switch (sip->si_code) { 239 case FPE_FLTDIV: 240 e = fex_division; 241 break; 242 case FPE_FLTOVF: 243 e = fex_overflow; 244 break; 245 case FPE_FLTUND: 246 e = fex_underflow; 247 break; 248 case FPE_FLTRES: 249 e = fex_inexact; 250 break; 251 case FPE_FLTINV: 252 if ((int)(e = __fex_get_invalid_type(sip, uap)) < 0) 253 goto not_ieee; 254 break; 255 default: 256 /* not an IEEE exception */ 257 goto not_ieee; 258 } 259 260 /* get the handling mode */ 261 mode = FEX_NOHANDLER; 262 handler = oact.sa_handler; /* for log; just looking, no need to lock */ 263 thr_handlers = __fex_get_thr_handlers(); 264 if (thr_handlers && thr_handlers[(int)e].__mode != FEX_NOHANDLER) { 265 mode = thr_handlers[(int)e].__mode; 266 handler = thr_handlers[(int)e].__handler; 267 } 268 269 /* make an entry in the log of retro. diag. if need be */ 270 i = ((int)uap->uc_mcontext.fpregs.fpu_fsr >> 5) & 0x1f; 271 __fex_mklog(uap, (char *)sip->si_addr, i, e, mode, (void *)handler); 272 273 /* handle the exception based on the mode */ 274 if (mode == FEX_NOHANDLER) 275 goto not_ieee; 276 else if (mode == FEX_ABORT) 277 abort(); 278 else if (mode == FEX_SIGNAL) { 279 handler(sig, sip, uap); 280 return; 281 } 282 283 /* custom or nonstop mode; disable traps and clear flags */ 284 __fenv_getfsr(&fsr); 285 __fenv_set_te(fsr, 0); 286 __fenv_set_ex(fsr, 0); 287 288 /* if interval mode was set, clear it, then substitute the 289 interval rounding direction and clear ns mode in the fsr */ 290 #ifdef __sparcv9 291 gsr = uap->uc_mcontext.asrs[3]; 292 #else 293 gsr = 0; 294 if (uap->uc_mcontext.xrs.xrs_id == XRS_ID) 295 gsr = (*(unsigned long long*)((prxregset_t*)uap->uc_mcontext. 296 xrs.xrs_ptr)->pr_un.pr_v8p.pr_filler); 297 #endif 298 gsr = (gsr >> 25) & 7; 299 if (gsr & 4) { 300 siamp = (void (*)()) siam[0]; 301 siamp(); 302 tmpfsr = fsr; 303 fsr = (fsr & ~0xc0400000ul) | ((gsr & 3) << 30); 304 } 305 __fenv_setfsr(&fsr); 306 307 /* decode the operation */ 308 __fex_get_op(sip, uap, &info); 309 310 /* if a custom mode handler is installed, invoke it */ 311 if (mode == FEX_CUSTOM) { 312 /* if we got here from feraiseexcept, pass dummy info */ 313 addr = (unsigned long)sip->si_addr; 314 if (addr >= (unsigned long)feraiseexcept && 315 addr < (unsigned long)fetestexcept) { 316 info.op = fex_other; 317 info.op1.type = info.op2.type = info.res.type = 318 fex_nodata; 319 } 320 321 /* restore interval mode if it was set, and put the original 322 rounding direction and ns mode back in the fsr */ 323 if (gsr & 4) { 324 __fenv_setfsr(&tmpfsr); 325 siamp = (void (*)()) siam[1 + (gsr & 3)]; 326 siamp(); 327 } 328 329 handler(1 << (int)e, &info); 330 331 /* restore modes in case the user's handler changed them */ 332 if (gsr & 4) { 333 siamp = (void (*)()) siam[0]; 334 siamp(); 335 } 336 __fenv_setfsr(&fsr); 337 } 338 339 /* stuff the result */ 340 __fex_st_result(sip, uap, &info); 341 342 /* "or" in any exception flags and update traps */ 343 fsr = uap->uc_mcontext.fpregs.fpu_fsr; 344 fsr |= ((info.flags & 0x1f) << 5); 345 i = __fex_te_needed(thr_handlers, fsr); 346 __fenv_set_te(fsr, i); 347 uap->uc_mcontext.fpregs.fpu_fsr = fsr; 348 return; 349 350 not_ieee: 351 /* revert to the saved handler (if any) */ 352 mutex_lock(&hdlr_lock); 353 act = oact; 354 mutex_unlock(&hdlr_lock); 355 switch ((unsigned long)act.sa_handler) { 356 case (unsigned long)SIG_DFL: 357 /* simulate trap with no handler installed */ 358 sigaction(SIGFPE, &act, NULL); 359 kill(getpid(), SIGFPE); 360 break; 361 #if !defined(__lint) 362 case (unsigned long)SIG_IGN: 363 break; 364 #endif 365 default: 366 act.sa_handler(sig, sip, uap); 367 } 368 } 369 370 #elif defined(__x86) 371 372 #if defined(__amd64) 373 #define test_sse_hw 1 374 #else 375 extern int _sse_hw; 376 #define test_sse_hw _sse_hw 377 #endif 378 379 #if !defined(REG_PC) 380 #define REG_PC EIP 381 #endif 382 383 /* 384 * If a handling mode is in effect, apply it; otherwise invoke the 385 * saved handler 386 */ 387 static void 388 __fex_hdlr(int sig, siginfo_t *sip, ucontext_t *uap) 389 { 390 struct fex_handler_data *thr_handlers; 391 struct sigaction act; 392 void (*handler)() = NULL, (*simd_handler[4])(); 393 int mode, simd_mode[4], i, len, accrued, *ap; 394 unsigned int cwsw, oldcwsw, mxcsr, oldmxcsr; 395 enum fex_exception e, simd_e[4]; 396 fex_info_t info, simd_info[4]; 397 unsigned long addr; 398 siginfo_t osip = *sip; 399 sseinst_t inst; 400 401 /* check for an exception caused by an SSE instruction */ 402 if (!(uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status & 0x80)) { 403 len = __fex_parse_sse(uap, &inst); 404 if (len == 0) 405 goto not_ieee; 406 407 /* disable all traps and clear flags */ 408 __fenv_getcwsw(&oldcwsw); 409 cwsw = (oldcwsw & ~0x3f) | 0x003f0000; 410 __fenv_setcwsw(&cwsw); 411 __fenv_getmxcsr(&oldmxcsr); 412 mxcsr = (oldmxcsr & ~0x3f) | 0x1f80; 413 __fenv_setmxcsr(&mxcsr); 414 415 if ((int)inst.op & SIMD) { 416 __fex_get_simd_op(uap, &inst, simd_e, simd_info); 417 418 thr_handlers = __fex_get_thr_handlers(); 419 addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC]; 420 accrued = uap->uc_mcontext.fpregs.fp_reg_set. 421 fpchip_state.mxcsr; 422 423 e = (enum fex_exception)-1; 424 mode = FEX_NONSTOP; 425 for (i = 0; i < 4; i++) { 426 if ((int)simd_e[i] < 0) 427 continue; 428 429 e = simd_e[i]; 430 simd_mode[i] = FEX_NOHANDLER; 431 simd_handler[i] = oact.sa_handler; 432 if (thr_handlers && 433 thr_handlers[(int)e].__mode != 434 FEX_NOHANDLER) { 435 simd_mode[i] = 436 thr_handlers[(int)e].__mode; 437 simd_handler[i] = 438 thr_handlers[(int)e].__handler; 439 } 440 accrued &= ~te_bit[(int)e]; 441 switch (simd_mode[i]) { 442 case FEX_ABORT: 443 mode = FEX_ABORT; 444 break; 445 case FEX_SIGNAL: 446 if (mode != FEX_ABORT) 447 mode = FEX_SIGNAL; 448 handler = simd_handler[i]; 449 break; 450 case FEX_NOHANDLER: 451 if (mode != FEX_ABORT && mode != 452 FEX_SIGNAL) 453 mode = FEX_NOHANDLER; 454 break; 455 } 456 } 457 if (e == (enum fex_exception)-1) { 458 __fenv_setcwsw(&oldcwsw); 459 __fenv_setmxcsr(&oldmxcsr); 460 goto not_ieee; 461 } 462 accrued |= uap->uc_mcontext.fpregs.fp_reg_set. 463 fpchip_state.status; 464 ap = __fex_accrued(); 465 accrued |= *ap; 466 accrued &= 0x3d; 467 468 for (i = 0; i < 4; i++) { 469 if ((int)simd_e[i] < 0) 470 continue; 471 472 __fex_mklog(uap, (char *)addr, accrued, 473 simd_e[i], simd_mode[i], 474 (void *)simd_handler[i]); 475 } 476 477 if (mode == FEX_NOHANDLER) { 478 __fenv_setcwsw(&oldcwsw); 479 __fenv_setmxcsr(&oldmxcsr); 480 goto not_ieee; 481 } else if (mode == FEX_ABORT) { 482 abort(); 483 } else if (mode == FEX_SIGNAL) { 484 __fenv_setcwsw(&oldcwsw); 485 __fenv_setmxcsr(&oldmxcsr); 486 handler(sig, &osip, uap); 487 return; 488 } 489 490 *ap = 0; 491 for (i = 0; i < 4; i++) { 492 if ((int)simd_e[i] < 0) 493 continue; 494 495 if (simd_mode[i] == FEX_CUSTOM) { 496 handler(1 << (int)simd_e[i], 497 &simd_info[i]); 498 __fenv_setcwsw(&cwsw); 499 __fenv_setmxcsr(&mxcsr); 500 } 501 } 502 503 __fex_st_simd_result(uap, &inst, simd_e, simd_info); 504 for (i = 0; i < 4; i++) { 505 if ((int)simd_e[i] < 0) 506 continue; 507 508 accrued |= simd_info[i].flags; 509 } 510 511 if ((int)inst.op & INTREG) { 512 /* set MMX mode */ 513 #if defined(__amd64) 514 uap->uc_mcontext.fpregs.fp_reg_set. 515 fpchip_state.sw &= ~0x3800; 516 uap->uc_mcontext.fpregs.fp_reg_set. 517 fpchip_state.fctw = 0; 518 #else 519 uap->uc_mcontext.fpregs.fp_reg_set. 520 fpchip_state.state[1] &= ~0x3800; 521 uap->uc_mcontext.fpregs.fp_reg_set. 522 fpchip_state.state[2] = 0; 523 #endif 524 } 525 } else { 526 e = __fex_get_sse_op(uap, &inst, &info); 527 if ((int)e < 0) { 528 __fenv_setcwsw(&oldcwsw); 529 __fenv_setmxcsr(&oldmxcsr); 530 goto not_ieee; 531 } 532 533 mode = FEX_NOHANDLER; 534 handler = oact.sa_handler; 535 thr_handlers = __fex_get_thr_handlers(); 536 if (thr_handlers && thr_handlers[(int)e].__mode != 537 FEX_NOHANDLER) { 538 mode = thr_handlers[(int)e].__mode; 539 handler = thr_handlers[(int)e].__handler; 540 } 541 542 addr = (unsigned long)uap->uc_mcontext.gregs[REG_PC]; 543 accrued = uap->uc_mcontext.fpregs.fp_reg_set. 544 fpchip_state.mxcsr & ~te_bit[(int)e]; 545 accrued |= uap->uc_mcontext.fpregs.fp_reg_set. 546 fpchip_state.status; 547 ap = __fex_accrued(); 548 accrued |= *ap; 549 accrued &= 0x3d; 550 __fex_mklog(uap, (char *)addr, accrued, e, mode, 551 (void *)handler); 552 553 if (mode == FEX_NOHANDLER) { 554 __fenv_setcwsw(&oldcwsw); 555 __fenv_setmxcsr(&oldmxcsr); 556 goto not_ieee; 557 } else if (mode == FEX_ABORT) { 558 abort(); 559 } else if (mode == FEX_SIGNAL) { 560 __fenv_setcwsw(&oldcwsw); 561 __fenv_setmxcsr(&oldmxcsr); 562 handler(sig, &osip, uap); 563 return; 564 } else if (mode == FEX_CUSTOM) { 565 *ap = 0; 566 if (addr >= (unsigned long)feraiseexcept && 567 addr < (unsigned long)fetestexcept) { 568 info.op = fex_other; 569 info.op1.type = info.op2.type = 570 info.res.type = fex_nodata; 571 } 572 handler(1 << (int)e, &info); 573 __fenv_setcwsw(&cwsw); 574 __fenv_setmxcsr(&mxcsr); 575 } 576 577 __fex_st_sse_result(uap, &inst, e, &info); 578 accrued |= info.flags; 579 580 #if defined(__amd64) 581 /* 582 * In 64-bit mode, the 32-bit convert-to-integer 583 * instructions zero the upper 32 bits of the 584 * destination. (We do this here and not in 585 * __fex_st_sse_result because __fex_st_sse_result 586 * can be called from __fex_st_simd_result, too.) 587 */ 588 if (inst.op == cvtss2si || inst.op == cvttss2si || 589 inst.op == cvtsd2si || inst.op == cvttsd2si) 590 inst.op1->i[1] = 0; 591 #endif 592 } 593 594 /* advance the pc past the SSE instruction */ 595 uap->uc_mcontext.gregs[REG_PC] += len; 596 goto update_state; 597 } 598 599 /* determine which exception occurred */ 600 __fex_get_x86_exc(sip, uap); 601 switch (sip->si_code) { 602 case FPE_FLTDIV: 603 e = fex_division; 604 break; 605 case FPE_FLTOVF: 606 e = fex_overflow; 607 break; 608 case FPE_FLTUND: 609 e = fex_underflow; 610 break; 611 case FPE_FLTRES: 612 e = fex_inexact; 613 break; 614 case FPE_FLTINV: 615 if ((int)(e = __fex_get_invalid_type(sip, uap)) < 0) 616 goto not_ieee; 617 break; 618 default: 619 /* not an IEEE exception */ 620 goto not_ieee; 621 } 622 623 /* get the handling mode */ 624 mode = FEX_NOHANDLER; 625 handler = oact.sa_handler; /* for log; just looking, no need to lock */ 626 thr_handlers = __fex_get_thr_handlers(); 627 if (thr_handlers && thr_handlers[(int)e].__mode != FEX_NOHANDLER) { 628 mode = thr_handlers[(int)e].__mode; 629 handler = thr_handlers[(int)e].__handler; 630 } 631 632 /* make an entry in the log of retro. diag. if need be */ 633 #if defined(__amd64) 634 addr = (unsigned long)uap->uc_mcontext.fpregs.fp_reg_set. 635 fpchip_state.rip; 636 #else 637 addr = (unsigned long)uap->uc_mcontext.fpregs.fp_reg_set. 638 fpchip_state.state[3]; 639 #endif 640 accrued = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status & 641 ~te_bit[(int)e]; 642 if (test_sse_hw) 643 accrued |= uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state. 644 mxcsr; 645 ap = __fex_accrued(); 646 accrued |= *ap; 647 accrued &= 0x3d; 648 __fex_mklog(uap, (char *)addr, accrued, e, mode, (void *)handler); 649 650 /* handle the exception based on the mode */ 651 if (mode == FEX_NOHANDLER) 652 goto not_ieee; 653 else if (mode == FEX_ABORT) 654 abort(); 655 else if (mode == FEX_SIGNAL) { 656 handler(sig, &osip, uap); 657 return; 658 } 659 660 /* disable all traps and clear flags */ 661 __fenv_getcwsw(&cwsw); 662 cwsw = (cwsw & ~0x3f) | 0x003f0000; 663 __fenv_setcwsw(&cwsw); 664 if (test_sse_hw) { 665 __fenv_getmxcsr(&mxcsr); 666 mxcsr = (mxcsr & ~0x3f) | 0x1f80; 667 __fenv_setmxcsr(&mxcsr); 668 } 669 *ap = 0; 670 671 /* decode the operation */ 672 __fex_get_op(sip, uap, &info); 673 674 /* if a custom mode handler is installed, invoke it */ 675 if (mode == FEX_CUSTOM) { 676 /* if we got here from feraiseexcept, pass dummy info */ 677 if (addr >= (unsigned long)feraiseexcept && 678 addr < (unsigned long)fetestexcept) { 679 info.op = fex_other; 680 info.op1.type = info.op2.type = info.res.type = 681 fex_nodata; 682 } 683 684 handler(1 << (int)e, &info); 685 686 /* restore modes in case the user's handler changed them */ 687 __fenv_setcwsw(&cwsw); 688 if (test_sse_hw) 689 __fenv_setmxcsr(&mxcsr); 690 } 691 692 /* stuff the result */ 693 __fex_st_result(sip, uap, &info); 694 accrued |= info.flags; 695 696 update_state: 697 accrued &= 0x3d; 698 i = __fex_te_needed(thr_handlers, accrued); 699 *ap = accrued & i; 700 #if defined(__amd64) 701 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw &= ~0x3d; 702 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= (accrued & ~i); 703 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw |= 0x3d; 704 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw &= ~i; 705 #else 706 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] &= ~0x3d; 707 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[1] |= 708 (accrued & ~i); 709 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] |= 0x3d; 710 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[0] &= ~i; 711 #endif 712 if (test_sse_hw) { 713 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &= ~0x3d; 714 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr |= 715 0x1e80 | (accrued & ~i); 716 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.mxcsr &= 717 ~(i << 7); 718 } 719 return; 720 721 not_ieee: 722 /* revert to the saved handler (if any) */ 723 mutex_lock(&hdlr_lock); 724 act = oact; 725 mutex_unlock(&hdlr_lock); 726 switch ((unsigned long)act.sa_handler) { 727 case (unsigned long)SIG_DFL: 728 /* simulate trap with no handler installed */ 729 sigaction(SIGFPE, &act, NULL); 730 kill(getpid(), SIGFPE); 731 break; 732 #if !defined(__lint) 733 case (unsigned long)SIG_IGN: 734 break; 735 #endif 736 default: 737 act.sa_handler(sig, &osip, uap); 738 } 739 } 740 741 #else 742 #error Unknown architecture 743 #endif 744 745 /* 746 * Return a pointer to the thread-specific handler data, and 747 * initialize it if necessary 748 */ 749 struct fex_handler_data * 750 __fex_get_thr_handlers() 751 { 752 struct fex_handler_data *ptr; 753 unsigned long fsr; 754 int i, te; 755 756 if (thr_main()) { 757 if (!handlers_initialized) { 758 /* initialize to FEX_NOHANDLER if trap is enabled, 759 FEX_NONSTOP if trap is disabled */ 760 __fenv_getfsr(&fsr); 761 te = (int)__fenv_get_te(fsr); 762 for (i = 0; i < FEX_NUM_EXC; i++) 763 main_handlers[i].__mode = 764 ((te & te_bit[i])? FEX_NOHANDLER : FEX_NONSTOP); 765 handlers_initialized = 1; 766 } 767 return main_handlers; 768 } 769 else { 770 ptr = NULL; 771 mutex_lock(&handlers_key_lock); 772 if (thr_getspecific(handlers_key, (void **)&ptr) != 0 && 773 thr_keycreate(&handlers_key, free) != 0) { 774 mutex_unlock(&handlers_key_lock); 775 return NULL; 776 } 777 mutex_unlock(&handlers_key_lock); 778 if (!ptr) { 779 if ((ptr = (struct fex_handler_data *) 780 malloc(sizeof(fex_handler_t))) == NULL) { 781 return NULL; 782 } 783 if (thr_setspecific(handlers_key, (void *)ptr) != 0) { 784 (void)free(ptr); 785 return NULL; 786 } 787 /* initialize to FEX_NOHANDLER if trap is enabled, 788 FEX_NONSTOP if trap is disabled */ 789 __fenv_getfsr(&fsr); 790 te = (int)__fenv_get_te(fsr); 791 for (i = 0; i < FEX_NUM_EXC; i++) 792 ptr[i].__mode = ((te & te_bit[i])? FEX_NOHANDLER : FEX_NONSTOP); 793 } 794 return ptr; 795 } 796 } 797 798 /* 799 * Update the trap enable bits according to the selected modes 800 */ 801 void 802 __fex_update_te() 803 { 804 struct fex_handler_data *thr_handlers; 805 struct sigaction act, tmpact; 806 sigset_t blocked; 807 unsigned long fsr; 808 int te; 809 810 /* determine which traps are needed */ 811 thr_handlers = __fex_get_thr_handlers(); 812 __fenv_getfsr(&fsr); 813 te = __fex_te_needed(thr_handlers, fsr); 814 815 /* install __fex_hdlr as necessary */ 816 if (!hdlr_installed && te) { 817 act.sa_handler = __fex_hdlr; 818 sigemptyset(&act.sa_mask); 819 act.sa_flags = SA_SIGINFO; 820 sigaction(SIGFPE, &act, &tmpact); 821 if (tmpact.sa_handler != __fex_hdlr) 822 { 823 mutex_lock(&hdlr_lock); 824 oact = tmpact; 825 mutex_unlock(&hdlr_lock); 826 } 827 hdlr_installed = 1; 828 } 829 830 /* set the new trap enable bits (only if SIGFPE is not blocked) */ 831 if (sigprocmask(0, NULL, &blocked) == 0 && 832 !sigismember(&blocked, SIGFPE)) { 833 __fenv_set_te(fsr, te); 834 __fenv_setfsr(&fsr); 835 } 836 837 /* synchronize with libmtsk */ 838 __mt_fex_sync = __fex_sync_with_libmtsk; 839 840 /* synchronize with other projects */ 841 __libm_mt_fex_sync = __fex_sync_with_threads; 842 }