/* $Id: defer_sig.c,v 1.8 2012/01/15 15:46:58 kostik Exp $ */ #include #include #include #include #include #include #include #include #include #if defined(__amd64__) || defined (__i386__) #define X86 #include #include #if defined(__amd64__) #include #endif #if defined(__i386__) #include #endif #endif #ifdef X86 static int avx; #endif static void handler(int sig __unused, siginfo_t *si __unused, void *uacp) { ucontext_t *ucp; mcontext_t *mcp; #if defined(__amd64__) struct savefpu *savefpu; struct savefpu_xstate *xstate; #elif defined (__i386__) struct savexmm *savefpu; struct savexmm_xstate *xstate; #endif #ifdef X86 char v[32]; int i; #endif ucp = uacp; mcp = &ucp->uc_mcontext; #ifdef X86 if (avx) { if ((mcp->mc_flags & _MC_HASFPXSTATE) == 0) { warnx("no fpxstate in context, flags %x", mcp->mc_flags); abort(); } savefpu = (void *)&mcp->mc_fpstate; xstate = (void *)mcp->mc_xfpustate; bcopy(&savefpu->sv_xmm[0], &v[0], sizeof(v) / 2); bcopy(&xstate->sx_ymm[0], &v[sizeof(v) / 2], sizeof(v) / 2); for (i = 0; i < (int)sizeof(v); i++) { if (i != v[i]) errx(1, "i %d v[i] %d", i, v[i]); } } else { if ((mcp->mc_flags & _MC_HASFPXSTATE) != 0) { warnx("fpxstate in context but no AVX, flags %x", mcp->mc_flags); abort(); } } #endif } static void * test_thread(void *arg) { pthread_barrier_t *b; pthread_key_t key; #ifdef X86 char v[32]; int i; if (avx) { for (i = 0; i < (int)sizeof(v); i++) v[i] = i; __asm __volatile("vmovdqu\t%0,%%ymm0" : : "m" (*v)); } #endif b = arg; pthread_barrier_wait(b); for (;;) { pthread_key_create(&key, NULL); pthread_key_delete(key); } return (NULL); } int main(void) { pthread_t thr; struct sigaction sa; pthread_barrier_t b; int error; #ifdef X86 u_int cp[4]; do_cpuid(1, cp); if ((cp[2] & (CPUID2_OSXSAVE | CPUID2_AVX)) == (CPUID2_OSXSAVE | CPUID2_AVX)) { avx = 1; printf("Detected AVX\n"); } else printf("No AVX detected\n"); #endif bzero(&sa, sizeof(sa)); sa.sa_sigaction = handler; sa.sa_flags = SA_SIGINFO; if (sigaction(SIGHUP, &sa, NULL) == -1) err(1, "sigaction"); pthread_barrier_init(&b, NULL, 2); error = pthread_create(&thr, NULL, test_thread, &b); if (error != 0) errc(1, error, "pthread_create"); pthread_barrier_wait(&b); for (;;) pthread_kill(thr, SIGHUP); return (0); }