⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sys_float.c

📁 OTP是开放电信平台的简称
💻 C
📖 第 1 页 / 共 2 页
字号:
 /* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. *  * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. *  * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' *  *     $Id$ */#ifdef HAVE_CONFIG_H#  include "config.h"#endif#include "sys.h"#include "global.h"#include "erl_process.h"#ifdef NO_FPE_SIGNALSvoiderts_sys_init_float(void){# ifdef SIGFPE    sys_sigset(SIGFPE, SIG_IGN); /* Ignore so we can test for NaN and Inf */# endif}static ERTS_INLINE void set_current_fp_exception(void){    /* nothing to do */}#else  /* !NO_FPE_SIGNALS */#ifdef ERTS_SMPstatic erts_tsd_key_t fpe_key;/* once-only initialisation early in the main thread (via erts_sys_init_float()) */static void erts_init_fp_exception(void){    /* XXX: the wrappers prevent using a pthread destructor to       deallocate the key's value; so when/where do we do that? */    erts_tsd_key_create(&fpe_key);}void erts_thread_init_fp_exception(void){    int *fpe = erts_alloc(ERTS_ALC_T_FP_EXCEPTION, sizeof(*fpe));    erts_tsd_set(fpe_key, fpe);}static ERTS_INLINE volatile int *erts_thread_get_fp_exception(void){    return (volatile int*)erts_tsd_get(fpe_key);}#else /* !SMP */#define erts_init_fp_exception()	/*empty*/static volatile int fp_exception;#define erts_thread_get_fp_exception()	(&fp_exception)#endif /* SMP */volatile int *erts_get_current_fp_exception(void){    Process *c_p;    c_p = erts_get_current_process();    if (c_p)	return &c_p->fp_exception;    return erts_thread_get_fp_exception();}static void set_current_fp_exception(void){    volatile int *fpexnp = erts_get_current_fp_exception();    ASSERT(fpexnp != NULL);    *fpexnp = 1;}/* Is there no standard identifier for Darwin/MacOSX ? */#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__)#define __DARWIN__ 1#endif#if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__)static void unmask_x87(void){    unsigned short cw;    __asm__ __volatile__("fstcw %0" : "=m"(cw));    cw &= ~(0x01|0x04|0x08);   /* unmask IM, ZM, OM */    __asm__ __volatile__("fldcw %0" : : "m"(cw));}static void unmask_sse2(void){    unsigned int mxcsr;    __asm__ __volatile__("stmxcsr %0" : "=m"(mxcsr));    mxcsr &= ~(0x003F|0x0680); /* clear exn flags, unmask OM, ZM, IM (not PM, UM, DM) */    __asm__ __volatile__("ldmxcsr %0" : : "m"(mxcsr));}#if defined(__x86_64__) || defined(__DARWIN__)static inline int cpu_has_sse2(void) { return 1; }#else /* !__x86_64__ *//* * Check if an x86-32 processor has SSE2. */static unsigned int xor_eflags(unsigned int mask){    unsigned int eax, edx;    eax = mask;			/* eax = mask */    __asm__("pushfl\n\t"	    "popl %0\n\t"	/* edx = original EFLAGS */	    "xorl %0, %1\n\t"	/* eax = mask ^ EFLAGS */	    "pushl %1\n\t"	    "popfl\n\t"		/* new EFLAGS = mask ^ original EFLAGS */	    "pushfl\n\t"	    "popl %1\n\t"	/* eax = new EFLAGS */	    "xorl %0, %1\n\t"	/* eax = new EFLAGS ^ old EFLAGS */	    "pushl %0\n\t"	    "popfl"		/* restore original EFLAGS */	    : "=d"(edx), "=a"(eax)	    : "1"(eax));    return eax;}static __inline__ unsigned int cpuid_eax(unsigned int op){    unsigned int eax;    __asm__("cpuid"	    : "=a"(eax)	    : "0"(op)	    : "bx", "cx", "dx");    return eax;}static __inline__ unsigned int cpuid_edx(unsigned int op){    unsigned int eax, edx;    __asm__("cpuid"	    : "=a"(eax), "=d"(edx)	    : "0"(op)	    : "bx", "cx");    return edx;}/* The AC bit, bit #18, is a new bit introduced in the EFLAGS * register on the Intel486 processor to generate alignment * faults. This bit cannot be set on the Intel386 processor. */static __inline__ int is_386(void){    return ((xor_eflags(1<<18) >> 18) & 1) == 0;}/* Newer x86 processors have a CPUID instruction, as indicated by * the ID bit (#21) in EFLAGS being modifiable. */static __inline__ int has_CPUID(void){    return (xor_eflags(1<<21) >> 21) & 1;}static int cpu_has_sse2(void){    unsigned int maxlev, features;    static int has_sse2 = -1;    if (has_sse2 >= 0)	return has_sse2;    has_sse2 = 0;    if (is_386())	return 0;    if (!has_CPUID())	return 0;    maxlev = cpuid_eax(0);    /* Intel A-step Pentium had a preliminary version of CPUID.       It also didn't have SSE2. */    if ((maxlev & 0xFFFFFF00) == 0x0500)	return 0;    /* If max level is zero then CPUID cannot report any features. */    if (maxlev == 0)	return 0;    features = cpuid_edx(1);    has_sse2 = (features & (1 << 26)) != 0;    return has_sse2;}#endif /* !__x86_64__ */static void unmask_fpe(void){    unmask_x87();    if (cpu_has_sse2())	unmask_sse2();}void erts_restore_fpu(void){    __asm__ __volatile__("fninit");    unmask_x87();}#elif defined(__sparc__) && defined(__linux__)static void unmask_fpe(void){    unsigned long fsr;    __asm__("st %%fsr, %0" : "=m"(fsr));    fsr &= ~(0x1FUL << 23);	/* clear FSR[TEM] field */    fsr |= (0x1AUL << 23);	/* enable NV, OF, DZ exceptions */    __asm__ __volatile__("ld %0, %%fsr" : : "m"(fsr));}#elif (defined(__powerpc__) && defined(__linux__)) || (defined(__ppc__) && defined(__DARWIN__))#if defined(__linux__)#include <sys/prctl.h>static void set_fpexc_precise(void){    if (prctl(PR_SET_FPEXC, PR_FP_EXC_PRECISE) < 0) {	perror("PR_SET_FPEXC");	exit(1);    }}#elif defined(__DARWIN__)#include <mach/mach.h>#include <pthread.h>/* * FE0 FE1	MSR bits *  0   0	floating-point exceptions disabled *  0   1	floating-point imprecise nonrecoverable *  1   0	floating-point imprecise recoverable *  1   1	floating-point precise mode * * Apparently: * - Darwin 5.5 (MacOS X <= 10.1) starts with FE0 == FE1 == 0, *   and resets FE0 and FE1 to 0 after each SIGFPE. * - Darwin 6.0 (MacOS X 10.2) starts with FE0 == FE1 == 1, *   and does not reset FE0 or FE1 after a SIGFPE. */#define FE0_MASK	(1<<11)#define FE1_MASK	(1<<8)/* a thread cannot get or set its own MSR bits */static void *fpu_fpe_enable(void *arg){    thread_t t = *(thread_t*)arg;    struct ppc_thread_state state;    unsigned int state_size = PPC_THREAD_STATE_COUNT;    if (thread_get_state(t, PPC_THREAD_STATE, (natural_t*)&state, &state_size) != KERN_SUCCESS) {	perror("thread_get_state");	exit(1);    }    if ((state.srr1 & (FE1_MASK|FE0_MASK)) != (FE1_MASK|FE0_MASK)) {#if 0	/* This would also have to be performed in the SIGFPE handler	   to work around the MSR reset older Darwin releases do. */	state.srr1 |= (FE1_MASK|FE0_MASK);	thread_set_state(t, PPC_THREAD_STATE, (natural_t*)&state, state_size);#else	fprintf(stderr, "srr1 == 0x%08x, your Darwin is too old\n", state.srr1);	exit(1);#endif    }    return NULL; /* Ok, we appear to be on Darwin 6.0 or later */}static void set_fpexc_precise(void){    thread_t self = mach_thread_self();    pthread_t enabler;    if (pthread_create(&enabler, NULL, fpu_fpe_enable, &self)) {	perror("pthread_create");    } else if (pthread_join(enabler, NULL)) {	perror("pthread_join");    }}#endifstatic void set_fpscr(unsigned int fpscr){    union {	double d;	unsigned int fpscr[2];    } u;    u.fpscr[0] = 0xFFF80000;    u.fpscr[1] = fpscr;    __asm__ __volatile__("mtfsf 255,%0" : : "f"(u.d));}static void unmask_fpe(void){    set_fpexc_precise();    set_fpscr(0x80|0x40|0x10);	/* VE, OE, ZE; not UE or XE */}#else#define unmask_fpe()   fpsetmask(FP_X_INV | FP_X_OFL | FP_X_DZ)#endif#if (defined(__linux__) && (defined(__x86_64__) || defined(__i386__))) || (defined(__DARWIN__) && defined(__i386__)) || (defined(__FreeBSD__) && (defined(__x86_64__) || defined(__i386__))) || (defined(__OpenBSD__) && defined(__x86_64__)) || (defined(__sun__) && defined(__x86_64__))#if !(defined(__OpenBSD__) && defined(__x86_64__))#include <ucontext.h>#endif#if defined(__linux__) && defined(__x86_64__)#define mc_pc(mc)	((mc)->gregs[REG_RIP])typedef mcontext_t *erts_mcontext_ptr_t;#elif defined(__linux__) && defined(__i386__)#define mc_pc(mc)	((mc)->gregs[REG_EIP])typedef mcontext_t *erts_mcontext_ptr_t;#elif defined(__DARWIN__) && defined(__i386__)#define mc_pc(mc)	((mc)->ss.eip)typedef mcontext_t erts_mcontext_ptr_t;#elif defined(__FreeBSD__) && defined(__x86_64__)#define mc_pc(mc)	((mc)->mc_rip)typedef mcontext_t *erts_mcontext_ptr_t;#elif defined(__FreeBSD__) && defined(__i386__)#define mc_pc(mc)	((mc)->mc_eip)typedef mcontext_t *erts_mcontext_ptr_t;#elif defined(__OpenBSD__) && defined(__x86_64__)#define mc_pc(mc)	((mc)->sc_rip)typedef struct sigcontext *erts_mcontext_ptr_t;#elif defined(__sun__) && defined(__x86_64__)#define mc_pc(mc)	((mc)->gregs[REG_RIP])typedef mcontext_t *erts_mcontext_ptr_t;#endifstatic void skip_sse2_insn(erts_mcontext_ptr_t mc){    unsigned char *pc0 = (unsigned char*)mc_pc(mc);    unsigned char *pc = pc0;    unsigned int opcode;    unsigned int nr_skip_bytes;    opcode = *pc++;    switch (opcode) {    case 0x66: case 0xF2: case 0xF3:	opcode = *pc++;    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -