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