mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Merge pull request #3831 from Feoramund/fix-darwin-test-runner-cancel
Let Darwin safely panic in a test
This commit is contained in:
+1
-14
@@ -34,20 +34,7 @@ when ODIN_OS == .Windows {
|
|||||||
SIGTERM :: 15
|
SIGTERM :: 15
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Haiku || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD {
|
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Haiku || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD || ODIN_OS == .Darwin {
|
||||||
SIG_ERR :: rawptr(~uintptr(0))
|
|
||||||
SIG_DFL :: rawptr(uintptr(0))
|
|
||||||
SIG_IGN :: rawptr(uintptr(1))
|
|
||||||
|
|
||||||
SIGABRT :: 6
|
|
||||||
SIGFPE :: 8
|
|
||||||
SIGILL :: 4
|
|
||||||
SIGINT :: 2
|
|
||||||
SIGSEGV :: 11
|
|
||||||
SIGTERM :: 15
|
|
||||||
}
|
|
||||||
|
|
||||||
when ODIN_OS == .Darwin {
|
|
||||||
SIG_ERR :: rawptr(~uintptr(0))
|
SIG_ERR :: rawptr(~uintptr(0))
|
||||||
SIG_DFL :: rawptr(uintptr(0))
|
SIG_DFL :: rawptr(uintptr(0))
|
||||||
SIG_IGN :: rawptr(uintptr(1))
|
SIG_IGN :: rawptr(uintptr(1))
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ Stop_Reason :: enum {
|
|||||||
Illegal_Instruction,
|
Illegal_Instruction,
|
||||||
Arithmetic_Error,
|
Arithmetic_Error,
|
||||||
Segmentation_Fault,
|
Segmentation_Fault,
|
||||||
|
Unhandled_Trap,
|
||||||
}
|
}
|
||||||
|
|
||||||
test_assertion_failure_proc :: proc(prefix, message: string, loc: runtime.Source_Code_Location) -> ! {
|
test_assertion_failure_proc :: proc(prefix, message: string, loc: runtime.Source_Code_Location) -> ! {
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ import "core:os"
|
|||||||
@(private="file", thread_local)
|
@(private="file", thread_local)
|
||||||
local_test_index: libc.sig_atomic_t
|
local_test_index: libc.sig_atomic_t
|
||||||
|
|
||||||
|
// Windows does not appear to have a SIGTRAP, so this is defined here, instead
|
||||||
|
// of in the libc package, just so there's no confusion about it being
|
||||||
|
// available there.
|
||||||
|
SIGTRAP :: 5
|
||||||
|
|
||||||
@(private="file")
|
@(private="file")
|
||||||
stop_runner_callback :: proc "c" (sig: libc.int) {
|
stop_runner_callback :: proc "c" (sig: libc.int) {
|
||||||
prev := intrinsics.atomic_add(&stop_runner_flag, 1)
|
prev := intrinsics.atomic_add(&stop_runner_flag, 1)
|
||||||
@@ -110,6 +115,10 @@ _setup_signal_handler :: proc() {
|
|||||||
// For tests:
|
// For tests:
|
||||||
// Catch asserts and panics.
|
// Catch asserts and panics.
|
||||||
libc.signal(libc.SIGILL, stop_test_callback)
|
libc.signal(libc.SIGILL, stop_test_callback)
|
||||||
|
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Haiku || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD || ODIN_OS == .Darwin {
|
||||||
|
// Catch panics on Darwin and unhandled calls to `debug_trap`.
|
||||||
|
libc.signal(SIGTRAP, stop_test_callback)
|
||||||
|
}
|
||||||
// Catch arithmetic errors.
|
// Catch arithmetic errors.
|
||||||
libc.signal(libc.SIGFPE, stop_test_callback)
|
libc.signal(libc.SIGFPE, stop_test_callback)
|
||||||
// Catch segmentation faults (illegal memory access).
|
// Catch segmentation faults (illegal memory access).
|
||||||
@@ -141,6 +150,7 @@ _should_stop_test :: proc() -> (test_index: int, reason: Stop_Reason, ok: bool)
|
|||||||
case libc.SIGFPE: reason = .Arithmetic_Error
|
case libc.SIGFPE: reason = .Arithmetic_Error
|
||||||
case libc.SIGILL: reason = .Illegal_Instruction
|
case libc.SIGILL: reason = .Illegal_Instruction
|
||||||
case libc.SIGSEGV: reason = .Segmentation_Fault
|
case libc.SIGSEGV: reason = .Segmentation_Fault
|
||||||
|
case SIGTRAP: reason = .Unhandled_Trap
|
||||||
}
|
}
|
||||||
ok = true
|
ok = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,8 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
|
|||||||
__unix_thread_entry_proc :: proc "c" (t: rawptr) -> rawptr {
|
__unix_thread_entry_proc :: proc "c" (t: rawptr) -> rawptr {
|
||||||
t := (^Thread)(t)
|
t := (^Thread)(t)
|
||||||
|
|
||||||
when ODIN_OS != .Darwin {
|
// We need to give the thread a moment to start up before we enable cancellation.
|
||||||
// We need to give the thread a moment to start up before we enable cancellation.
|
can_set_thread_cancel_state := unix.pthread_setcancelstate(unix.PTHREAD_CANCEL_ENABLE, nil) == 0
|
||||||
can_set_thread_cancel_state := unix.pthread_setcancelstate(unix.PTHREAD_CANCEL_ENABLE, nil) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
sync.lock(&t.mutex)
|
sync.lock(&t.mutex)
|
||||||
|
|
||||||
@@ -42,12 +40,10 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS != .Darwin {
|
// Enable thread's cancelability.
|
||||||
// Enable thread's cancelability.
|
if can_set_thread_cancel_state {
|
||||||
if can_set_thread_cancel_state {
|
unix.pthread_setcanceltype (unix.PTHREAD_CANCEL_ASYNCHRONOUS, nil)
|
||||||
unix.pthread_setcanceltype (unix.PTHREAD_CANCEL_ASYNCHRONOUS, nil)
|
unix.pthread_setcancelstate(unix.PTHREAD_CANCEL_ENABLE, nil)
|
||||||
unix.pthread_setcancelstate(unix.PTHREAD_CANCEL_ENABLE, nil)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -169,10 +165,17 @@ _destroy :: proc(t: ^Thread) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_terminate :: proc(t: ^Thread, exit_code: int) {
|
_terminate :: proc(t: ^Thread, exit_code: int) {
|
||||||
// `pthread_cancel` is unreliable on Darwin for unknown reasons.
|
// NOTE(Feoramund): For thread cancellation to succeed on BSDs and
|
||||||
when ODIN_OS != .Darwin {
|
// possibly Darwin systems, the thread must call one of the pthread
|
||||||
unix.pthread_cancel(t.unix_thread)
|
// cancelation points at some point after this.
|
||||||
}
|
//
|
||||||
|
// The most obvious one of these is `pthread_cancel`, but there is an
|
||||||
|
// entire list of functions that act as cancelation points available in the
|
||||||
|
// pthreads manual page.
|
||||||
|
//
|
||||||
|
// This is in contrast to behavior I have seen on Linux where the thread is
|
||||||
|
// just terminated.
|
||||||
|
unix.pthread_cancel(t.unix_thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
_yield :: proc() {
|
_yield :: proc() {
|
||||||
|
|||||||
Reference in New Issue
Block a user