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