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