mirror of https://code.videolan.org/videolan/dav1d
checkasm: Make signal handling async-signal-safe
This commit is contained in:
parent
ceeb535d94
commit
8501a4b201
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -36,12 +37,15 @@
|
|||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#ifndef SIGBUS
|
||||
/* non-standard, use the same value as mingw-w64 */
|
||||
#define SIGBUS 10
|
||||
#endif
|
||||
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x04
|
||||
#endif
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
|
@ -139,7 +143,7 @@ static struct {
|
|||
int bench;
|
||||
int verbose;
|
||||
int function_listing;
|
||||
int catch_signals;
|
||||
volatile sig_atomic_t catch_signals;
|
||||
int suffix_length;
|
||||
int max_function_name_length;
|
||||
#if ARCH_X86_64
|
||||
|
@ -440,31 +444,30 @@ static LONG NTAPI signal_handler(EXCEPTION_POINTERS *const e) {
|
|||
if (!state.catch_signals)
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
const char *err;
|
||||
int s;
|
||||
switch (e->ExceptionRecord->ExceptionCode) {
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
err = "fatal arithmetic error";
|
||||
s = SIGFPE;
|
||||
break;
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
err = "illegal instruction";
|
||||
s = SIGILL;
|
||||
break;
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
err = "segmentation fault";
|
||||
s = SIGSEGV;
|
||||
break;
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
err = "bus error";
|
||||
s = SIGBUS;
|
||||
break;
|
||||
default:
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
state.catch_signals = 0;
|
||||
checkasm_fail_func(err);
|
||||
checkasm_load_context();
|
||||
checkasm_load_context(s);
|
||||
return EXCEPTION_CONTINUE_EXECUTION; /* never reached, but shuts up gcc */
|
||||
}
|
||||
#endif
|
||||
|
@ -472,11 +475,7 @@ static LONG NTAPI signal_handler(EXCEPTION_POINTERS *const e) {
|
|||
static void signal_handler(const int s) {
|
||||
if (state.catch_signals) {
|
||||
state.catch_signals = 0;
|
||||
checkasm_fail_func(s == SIGFPE ? "fatal arithmetic error" :
|
||||
s == SIGILL ? "illegal instruction" :
|
||||
s == SIGBUS ? "bus error" :
|
||||
"segmentation fault");
|
||||
checkasm_load_context();
|
||||
checkasm_load_context(s);
|
||||
} else {
|
||||
/* fall back to the default signal handler */
|
||||
static const struct sigaction default_sa = { .sa_handler = SIG_DFL };
|
||||
|
@ -687,11 +686,8 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
#ifdef readtime
|
||||
if (state.bench) {
|
||||
static int testing = 0;
|
||||
checkasm_save_context();
|
||||
if (!testing) {
|
||||
if (!checkasm_save_context()) {
|
||||
checkasm_set_signal_handler_state(1);
|
||||
testing = 1;
|
||||
readtime();
|
||||
checkasm_set_signal_handler_state(0);
|
||||
} else {
|
||||
|
@ -890,6 +886,16 @@ void checkasm_set_signal_handler_state(const int enabled) {
|
|||
state.catch_signals = enabled;
|
||||
}
|
||||
|
||||
int checkasm_handle_signal(const int s) {
|
||||
if (s) {
|
||||
checkasm_fail_func(s == SIGFPE ? "fatal arithmetic error" :
|
||||
s == SIGILL ? "illegal instruction" :
|
||||
s == SIGBUS ? "bus error" :
|
||||
"segmentation fault");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static int check_err(const char *const file, const int line,
|
||||
const char *const name, const int w, const int h,
|
||||
int *const err)
|
||||
|
|
|
@ -39,19 +39,24 @@
|
|||
* functions without unwind information. */
|
||||
#include <windows.h>
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||
#define checkasm_context CONTEXT
|
||||
#define checkasm_save_context() RtlCaptureContext(&checkasm_context_buf)
|
||||
#define checkasm_load_context() RtlRestoreContext(&checkasm_context_buf, NULL)
|
||||
typedef struct { CONTEXT c; int status; } checkasm_context;
|
||||
#define checkasm_save_context() \
|
||||
(checkasm_context_buf.status = 0, \
|
||||
RtlCaptureContext(&checkasm_context_buf.c), \
|
||||
checkasm_handle_signal(checkasm_context_buf.status))
|
||||
#define checkasm_load_context(s) \
|
||||
(checkasm_context_buf.status = s, \
|
||||
RtlRestoreContext(&checkasm_context_buf.c, NULL))
|
||||
#else
|
||||
#define checkasm_context void*
|
||||
#define checkasm_save_context() do {} while (0)
|
||||
typedef void* checkasm_context;
|
||||
#define checkasm_save_context() 0
|
||||
#define checkasm_load_context() do {} while (0)
|
||||
#endif
|
||||
#else
|
||||
#include <setjmp.h>
|
||||
#define checkasm_context jmp_buf
|
||||
#define checkasm_save_context() setjmp(checkasm_context_buf)
|
||||
#define checkasm_load_context() longjmp(checkasm_context_buf, 1)
|
||||
typedef jmp_buf checkasm_context;
|
||||
#define checkasm_save_context() checkasm_handle_signal(setjmp(checkasm_context_buf))
|
||||
#define checkasm_load_context(s) longjmp(checkasm_context_buf, s)
|
||||
#endif
|
||||
|
||||
#include "include/common/attributes.h"
|
||||
|
@ -82,6 +87,7 @@ int checkasm_fail_func(const char *msg, ...);
|
|||
void checkasm_update_bench(int iterations, uint64_t cycles);
|
||||
void checkasm_report(const char *name, ...);
|
||||
void checkasm_set_signal_handler_state(int enabled);
|
||||
int checkasm_handle_signal(int s);
|
||||
extern checkasm_context checkasm_context_buf;
|
||||
|
||||
/* float compare utilities */
|
||||
|
|
Loading…
Reference in New Issue