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