From 6eb8062fa669f2890b31be200c255a6458bfc564 Mon Sep 17 00:00:00 2001 From: Julien Portalier Date: Tue, 18 Jun 2024 10:41:58 +0200 Subject: [PATCH 1/8] Add GC.stop_world and GC.start_world (undocumented API) --- src/crystal/system/thread.cr | 28 ++++++++ src/crystal/system/unix/pthread.cr | 56 +++++++++++++++ src/crystal/system/wasi/thread.cr | 15 ++++ src/crystal/system/win32/thread.cr | 30 ++++++++ src/gc/boehm.cr | 38 ++++++++++ src/gc/none.cr | 70 +++++++++++++++++++ .../c/processthreadsapi.cr | 4 ++ 7 files changed, 241 insertions(+) diff --git a/src/crystal/system/thread.cr b/src/crystal/system/thread.cr index d9dc6acf17dc..f703238733ae 100644 --- a/src/crystal/system/thread.cr +++ b/src/crystal/system/thread.cr @@ -23,6 +23,14 @@ module Crystal::System::Thread # private def stack_address : Void* # private def system_name=(String) : String + + # def self.init_suspend_resume : Nil + + # def system_suspend : Nil + + # def system_wait_suspended : Nil + + # def system_resume : Nil end {% if flag?(:wasi) %} @@ -66,6 +74,14 @@ class Thread @@threads.try(&.unsafe_each { |thread| yield thread }) end + def self.lock : Nil + threads.@mutex.lock + end + + def self.unlock : Nil + threads.@mutex.unlock + end + # Creates and starts a new system thread. def initialize(@name : String? = nil, &@func : Thread ->) @system_handle = uninitialized Crystal::System::Thread::Handle @@ -168,6 +184,18 @@ class Thread # Holds the GC thread handler property gc_thread_handler : Void* = Pointer(Void).null + + def suspend : Nil + system_suspend + end + + def wait_suspended : Nil + system_wait_suspended + end + + def resume : Nil + system_resume + end end require "./thread_linked_list" diff --git a/src/crystal/system/unix/pthread.cr b/src/crystal/system/unix/pthread.cr index d38e52ee012a..b7bcb213d979 100644 --- a/src/crystal/system/unix/pthread.cr +++ b/src/crystal/system/unix/pthread.cr @@ -153,6 +153,62 @@ module Crystal::System::Thread {% end %} name end + + @suspended = Atomic(Bool).new(false) + + def self.init_suspend_resume : Nil + install_sig_suspend_signal_handler + install_sig_resume_signal_handler + end + + private def self.install_sig_suspend_signal_handler + action = LibC::Sigaction.new + action.sa_flags = LibC::SA_SIGINFO + action.sa_sigaction = LibC::SigactionHandlerT.new do |_, _, _| + # notify that the thread has been interrupted + Thread.current.@suspended.set(true) + + # block all signals but sig_resume + mask = LibC::SigsetT.new + LibC.sigfillset(pointerof(mask)) + LibC.sigdelset(pointerof(mask), sig_resume) + + # suspend the thread until it receives the sig_resume signal + LibC.sigsuspend(pointerof(mask)) + end + LibC.sigemptyset(pointerof(action.@sa_mask)) + LibC.sigaction(sig_suspend, pointerof(action), nil) + end + + private def self.install_sig_resume_signal_handler + action = LibC::Sigaction.new + action.sa_flags = 0 + action.sa_sigaction = LibC::SigactionHandlerT.new do |_, _, _| + # do nothing (a handler is still required to receive the signal) + end + LibC.sigemptyset(pointerof(action.@sa_mask)) + LibC.sigaction(sig_resume, pointerof(action), nil) + end + + def system_suspend : Nil + @suspended.set(false) + + if LibC.pthread_kill(@system_handle, GC.sig_suspend) == -1 + Crystal::System.panic("pthread_kill()") + end + end + + def system_wait_suspended : Nil + until @suspended.get + Thread.yield + end + end + + def system_resume : Nil + if LibC.pthread_kill(@system_handle, GC.sig_resume) == -1 + Crystal::System.panic("pthread_kill()") + end + end end # In musl (alpine) the calls to unwind API segfaults diff --git a/src/crystal/system/wasi/thread.cr b/src/crystal/system/wasi/thread.cr index 6f0c0cbe8260..d0dec50e33ad 100644 --- a/src/crystal/system/wasi/thread.cr +++ b/src/crystal/system/wasi/thread.cr @@ -38,4 +38,19 @@ module Crystal::System::Thread # TODO: Implement Pointer(Void).null end + + def self.init_suspend_resume : Nil + end + + def system_suspend : Nil + raise NotImplementedError.new("Crystal::System::Thread.system_suspend") + end + + def system_wait_suspended : Nil + raise NotImplementedError.new("Crystal::System::Thread.system_wait_suspended") + end + + def system_resume : Nil + raise NotImplementedError.new("Crystal::System::Thread.system_resume") + end end diff --git a/src/crystal/system/win32/thread.cr b/src/crystal/system/win32/thread.cr index ddfe3298b20a..c64d88d43ef2 100644 --- a/src/crystal/system/win32/thread.cr +++ b/src/crystal/system/win32/thread.cr @@ -87,4 +87,34 @@ module Crystal::System::Thread {% end %} name end + + def self.init_suspend_resume : Nil + end + + def system_suspend : Nil + if LibC.SuspendThread(@system_handle) == -1 + Crystal::System.panic("SuspendThread()") + end + end + + def system_wait_suspended : Nil + # context must be aligned on 16 bytes but we lack a mean to force the + # alignment on the struct, so we overallocate then realign the pointer: + # + # we only need to reserve UInt8[sizeof(LibC::CONTEXT) + 16] but that's + # invalid crystal + local = uninitialized LibC::CONTEXT[2] + thread_context = Pointer(LibC::CONTEXT).new(local.to_unsafe.address &+ 15_u64 & ~15_u64) + thread_context.value.contextFlags = LibC::CONTEXT_FULL + + if LibC.GetThreadContext(@system_handle, thread_context) == -1 + Crystal::System.panic("GetThreadContext()") + end + end + + def system_resume : Nil + if LibC.ResumeThread(@system_handle) == -1 + Crystal::System.panic("ResumeThread()") + end + end end diff --git a/src/gc/boehm.cr b/src/gc/boehm.cr index 8ccc1bb7b6e8..a4d73e57e42a 100644 --- a/src/gc/boehm.cr +++ b/src/gc/boehm.cr @@ -161,6 +161,14 @@ lib LibGC alias WarnProc = LibC::Char*, Word -> fun set_warn_proc = GC_set_warn_proc(WarnProc) $warn_proc = GC_current_warn_proc : WarnProc + + fun get_suspend_signal = GC_get_suspend_signal : Int + fun get_thr_restart_signal = GC_get_thr_restart_signal : Int + fun set_suspend_signal = GC_set_suspend_signal(Int) : Int + fun set_thr_restart_signal = GC_set_thr_restart_signal(Int) : Int + + fun stop_world_external = GC_stop_world_external + fun start_world_external = GC_start_world_external end module GC @@ -470,4 +478,34 @@ module GC GC.unlock_write end {% end %} + + # :nodoc: + def sig_suspend : Int32 + LibGC.get_suspend_signal + end + + # :nodoc: + def sig_suspend=(value : Int32) : Int32 + LibGC.set_suspend_signal(value) + end + + # :nodoc: + def sig_resume : Int32 + LibGC.get_thr_restart_signal + end + + # :nodoc: + def sig_resume=(value : Int32) : Int32 + LibGC.set_thr_restart_signal(value) + end + + # :nodoc: + def self.stop_world : Nil + LibGC.stop_world_external + end + + # :nodoc: + def self.start_world : Nil + LibGC.start_world_external + end end diff --git a/src/gc/none.cr b/src/gc/none.cr index 1121caef1bf4..d9f255773192 100644 --- a/src/gc/none.cr +++ b/src/gc/none.cr @@ -5,6 +5,7 @@ require "crystal/tracing" module GC def self.init + Crystal::System::Thread.init_suspend_resume end # :nodoc: @@ -136,4 +137,73 @@ module GC # :nodoc: def self.push_stack(stack_top, stack_bottom) end + + # Stop and start the world. + # + # This isn't a GC-safe stop-the-world implementation (it may allocate objects + # while stopping the world), but the guarantees are enough for the purpose of + # gc_none. + # + # Thread safety is guaranteed by the mutex in Crystal::PointerLinkedList: + # either a thread is starting and hasn't added itself to the list (it will + # block until it can acquire the lock), or is currently adding itself (the + # current thread will block until it can acquire the lock). + # + # In both cases there can't be a deadlock since we won't suspend another + # thread until it has successfuly added (or removed) itself to the linked + # list and released the lock, and the other thread won't progress until it + # can add (or remove) itself from the list. + # + # Finally, we lock the mutex and keep it locked until we resume the world, + # so any thread waiting on the mutex will only be resumed when the world is + # resumed. + + # :nodoc: + class_property(sig_suspend : Int32) do + {% if flag?(:unix) %} + LibC::SIGUSR1 + {% else %} + -1 + {% end %} + end + + # :nodoc: + class_property(sig_resume : Int32) do + {% if flag?(:unix) %} + LibC::SIGUSR2 + {% else %} + -1 + {% end %} + end + + # :nodoc: + def self.stop_world : Nil + current_thread = Thread.current + + # grab the lock (and keep it until the world is restarted) + Thread.lock + + # tell all threads to stop (async) + Thread.unsafe_each do |thread| + thread.suspend unless thread == current_thread + end + + # wait for all threads to have stopped + Thread.unsafe_each do |thread| + thread.wait_suspended unless thread == current_thread + end + end + + # :nodoc: + def self.start_world : Nil + current_thread = Thread.current + + # tell all threads to resume + Thread.unsafe_each do |thread| + thread.resume unless thread == current_thread + end + + # finally, we can release the lock + Thread.unlock + end end diff --git a/src/lib_c/x86_64-windows-msvc/c/processthreadsapi.cr b/src/lib_c/x86_64-windows-msvc/c/processthreadsapi.cr index d1e13eced324..1fcaee65a01c 100644 --- a/src/lib_c/x86_64-windows-msvc/c/processthreadsapi.cr +++ b/src/lib_c/x86_64-windows-msvc/c/processthreadsapi.cr @@ -59,5 +59,9 @@ lib LibC fun SwitchToThread : BOOL fun QueueUserAPC(pfnAPC : PAPCFUNC, hThread : HANDLE, dwData : ULONG_PTR) : DWORD + fun GetThreadContext(hThread : HANDLE, lpContext : CONTEXT*) : DWORD + fun ResumeThread(hThread : HANDLE) : DWORD + fun SuspendThread(hThread : HANDLE) : DWORD + PROCESS_QUERY_INFORMATION = 0x0400 end From 0c89473e25d8a7241ce674c809962c6b48f4f6b9 Mon Sep 17 00:00:00 2001 From: Julien Portalier Date: Tue, 18 Jun 2024 11:09:23 +0200 Subject: [PATCH 2/8] Fix: missing sigsuspend/pthread_kill + typos --- src/crystal/system/unix/pthread.cr | 21 +++++++++++---------- src/crystal/system/win32/thread.cr | 1 + src/lib_c/aarch64-android/c/signal.cr | 2 ++ src/lib_c/aarch64-darwin/c/signal.cr | 2 ++ src/lib_c/aarch64-linux-gnu/c/signal.cr | 2 ++ src/lib_c/aarch64-linux-musl/c/signal.cr | 2 ++ src/lib_c/arm-linux-gnueabihf/c/signal.cr | 2 ++ src/lib_c/i386-linux-gnu/c/signal.cr | 2 ++ src/lib_c/i386-linux-musl/c/signal.cr | 2 ++ src/lib_c/x86_64-darwin/c/signal.cr | 2 ++ src/lib_c/x86_64-dragonfly/c/signal.cr | 2 ++ src/lib_c/x86_64-freebsd/c/signal.cr | 2 ++ src/lib_c/x86_64-linux-gnu/c/signal.cr | 2 ++ src/lib_c/x86_64-linux-musl/c/signal.cr | 2 ++ src/lib_c/x86_64-netbsd/c/signal.cr | 2 ++ src/lib_c/x86_64-openbsd/c/signal.cr | 2 ++ src/lib_c/x86_64-solaris/c/signal.cr | 2 ++ 17 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/crystal/system/unix/pthread.cr b/src/crystal/system/unix/pthread.cr index b7bcb213d979..4ac0aa728bf0 100644 --- a/src/crystal/system/unix/pthread.cr +++ b/src/crystal/system/unix/pthread.cr @@ -1,5 +1,6 @@ require "c/pthread" require "c/sched" +require "../panic" module Crystal::System::Thread alias Handle = LibC::PthreadT @@ -166,18 +167,18 @@ module Crystal::System::Thread action.sa_flags = LibC::SA_SIGINFO action.sa_sigaction = LibC::SigactionHandlerT.new do |_, _, _| # notify that the thread has been interrupted - Thread.current.@suspended.set(true) + Thread.current_thread.@suspended.set(true) # block all signals but sig_resume mask = LibC::SigsetT.new LibC.sigfillset(pointerof(mask)) - LibC.sigdelset(pointerof(mask), sig_resume) + LibC.sigdelset(pointerof(mask), GC.sig_resume) # suspend the thread until it receives the sig_resume signal LibC.sigsuspend(pointerof(mask)) end LibC.sigemptyset(pointerof(action.@sa_mask)) - LibC.sigaction(sig_suspend, pointerof(action), nil) + LibC.sigaction(GC.sig_suspend, pointerof(action), nil) end private def self.install_sig_resume_signal_handler @@ -187,26 +188,26 @@ module Crystal::System::Thread # do nothing (a handler is still required to receive the signal) end LibC.sigemptyset(pointerof(action.@sa_mask)) - LibC.sigaction(sig_resume, pointerof(action), nil) + LibC.sigaction(GC.sig_resume, pointerof(action), nil) end - def system_suspend : Nil + private def system_suspend : Nil @suspended.set(false) if LibC.pthread_kill(@system_handle, GC.sig_suspend) == -1 - Crystal::System.panic("pthread_kill()") + System.panic("pthread_kill()") end end - def system_wait_suspended : Nil + private def system_wait_suspended : Nil until @suspended.get - Thread.yield + Thread.yield_current end end - def system_resume : Nil + private def system_resume : Nil if LibC.pthread_kill(@system_handle, GC.sig_resume) == -1 - Crystal::System.panic("pthread_kill()") + System.panic("pthread_kill()") end end end diff --git a/src/crystal/system/win32/thread.cr b/src/crystal/system/win32/thread.cr index c64d88d43ef2..6a961e1d3e89 100644 --- a/src/crystal/system/win32/thread.cr +++ b/src/crystal/system/win32/thread.cr @@ -1,5 +1,6 @@ require "c/processthreadsapi" require "c/synchapi" +require "../panic" module Crystal::System::Thread alias Handle = LibC::HANDLE diff --git a/src/lib_c/aarch64-android/c/signal.cr b/src/lib_c/aarch64-android/c/signal.cr index 741c8f0efb65..27676c3f733f 100644 --- a/src/lib_c/aarch64-android/c/signal.cr +++ b/src/lib_c/aarch64-android/c/signal.cr @@ -79,6 +79,7 @@ lib LibC fun kill(__pid : PidT, __signal : Int) : Int fun pthread_sigmask(__how : Int, __new_set : SigsetT*, __old_set : SigsetT*) : Int + fun pthread_kill(__thread : PthreadT, __sig : Int) : Int fun sigaction(__signal : Int, __new_action : Sigaction*, __old_action : Sigaction*) : Int fun sigaltstack(__new_signal_stack : StackT*, __old_signal_stack : StackT*) : Int {% if ANDROID_API >= 21 %} @@ -89,5 +90,6 @@ lib LibC fun sigaddset(__set : SigsetT*, __signal : Int) : Int fun sigdelset(__set : SigsetT*, __signal : Int) : Int fun sigismember(__set : SigsetT*, __signal : Int) : Int + fun sigsuspend(__mask : SigsetT*) : Int {% end %} end diff --git a/src/lib_c/aarch64-darwin/c/signal.cr b/src/lib_c/aarch64-darwin/c/signal.cr index e58adc30289f..0034eef42834 100644 --- a/src/lib_c/aarch64-darwin/c/signal.cr +++ b/src/lib_c/aarch64-darwin/c/signal.cr @@ -77,6 +77,7 @@ lib LibC fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int + fun pthread_kill(PthreadT, Int) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int @@ -85,4 +86,5 @@ lib LibC fun sigaddset(SigsetT*, Int) : Int fun sigdelset(SigsetT*, Int) : Int fun sigismember(SigsetT*, Int) : Int + fun sigsuspend(SigsetT*) : Int end diff --git a/src/lib_c/aarch64-linux-gnu/c/signal.cr b/src/lib_c/aarch64-linux-gnu/c/signal.cr index 1f7d82eb2145..7ff9fcda1b07 100644 --- a/src/lib_c/aarch64-linux-gnu/c/signal.cr +++ b/src/lib_c/aarch64-linux-gnu/c/signal.cr @@ -78,6 +78,7 @@ lib LibC fun kill(pid : PidT, sig : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int + fun pthread_kill(PthreadT, Int) : Int fun signal(sig : Int, handler : Int -> Void) : Int -> Void fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int @@ -86,4 +87,5 @@ lib LibC fun sigaddset(SigsetT*, Int) : Int fun sigdelset(SigsetT*, Int) : Int fun sigismember(SigsetT*, Int) : Int + fun sigsuspend(SigsetT*) : Int end diff --git a/src/lib_c/aarch64-linux-musl/c/signal.cr b/src/lib_c/aarch64-linux-musl/c/signal.cr index 5bfa187b14ec..c65fbb0ff653 100644 --- a/src/lib_c/aarch64-linux-musl/c/signal.cr +++ b/src/lib_c/aarch64-linux-musl/c/signal.cr @@ -77,6 +77,7 @@ lib LibC fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int + fun pthread_kill(PthreadT, Int) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int @@ -85,4 +86,5 @@ lib LibC fun sigaddset(SigsetT*, Int) : Int fun sigdelset(SigsetT*, Int) : Int fun sigismember(SigsetT*, Int) : Int + fun sigsuspend(SigsetT*) : Int end diff --git a/src/lib_c/arm-linux-gnueabihf/c/signal.cr b/src/lib_c/arm-linux-gnueabihf/c/signal.cr index d94d657e1ca8..0113c045341c 100644 --- a/src/lib_c/arm-linux-gnueabihf/c/signal.cr +++ b/src/lib_c/arm-linux-gnueabihf/c/signal.cr @@ -77,6 +77,7 @@ lib LibC fun kill(pid : PidT, sig : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int + fun pthread_kill(PthreadT, Int) : Int fun signal(sig : Int, handler : Int -> Void) : Int -> Void fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int @@ -85,4 +86,5 @@ lib LibC fun sigaddset(SigsetT*, Int) : Int fun sigdelset(SigsetT*, Int) : Int fun sigismember(SigsetT*, Int) : Int + fun sigsuspend(SigsetT*) : Int end diff --git a/src/lib_c/i386-linux-gnu/c/signal.cr b/src/lib_c/i386-linux-gnu/c/signal.cr index 11aab8bfe6bb..1a5260073c2d 100644 --- a/src/lib_c/i386-linux-gnu/c/signal.cr +++ b/src/lib_c/i386-linux-gnu/c/signal.cr @@ -77,6 +77,7 @@ lib LibC fun kill(pid : PidT, sig : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int + fun pthread_kill(PthreadT, Int) : Int fun signal(sig : Int, handler : Int -> Void) : Int -> Void fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int @@ -85,4 +86,5 @@ lib LibC fun sigaddset(SigsetT*, Int) : Int fun sigdelset(SigsetT*, Int) : Int fun sigismember(SigsetT*, Int) : Int + fun sigsuspend(SigsetT*) : Int end diff --git a/src/lib_c/i386-linux-musl/c/signal.cr b/src/lib_c/i386-linux-musl/c/signal.cr index f2e554942b69..ac374b684c76 100644 --- a/src/lib_c/i386-linux-musl/c/signal.cr +++ b/src/lib_c/i386-linux-musl/c/signal.cr @@ -76,6 +76,7 @@ lib LibC fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int + fun pthread_kill(PthreadT, Int) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int @@ -84,4 +85,5 @@ lib LibC fun sigaddset(SigsetT*, Int) : Int fun sigdelset(SigsetT*, Int) : Int fun sigismember(SigsetT*, Int) : Int + fun sigsuspend(SigsetT*) : Int end diff --git a/src/lib_c/x86_64-darwin/c/signal.cr b/src/lib_c/x86_64-darwin/c/signal.cr index e58adc30289f..0034eef42834 100644 --- a/src/lib_c/x86_64-darwin/c/signal.cr +++ b/src/lib_c/x86_64-darwin/c/signal.cr @@ -77,6 +77,7 @@ lib LibC fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int + fun pthread_kill(PthreadT, Int) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int @@ -85,4 +86,5 @@ lib LibC fun sigaddset(SigsetT*, Int) : Int fun sigdelset(SigsetT*, Int) : Int fun sigismember(SigsetT*, Int) : Int + fun sigsuspend(SigsetT*) : Int end diff --git a/src/lib_c/x86_64-dragonfly/c/signal.cr b/src/lib_c/x86_64-dragonfly/c/signal.cr index 1751eeed3176..e362ef1fa218 100644 --- a/src/lib_c/x86_64-dragonfly/c/signal.cr +++ b/src/lib_c/x86_64-dragonfly/c/signal.cr @@ -90,6 +90,7 @@ lib LibC fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int + fun pthread_kill(PthreadT, Int) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int @@ -98,4 +99,5 @@ lib LibC fun sigaddset(SigsetT*, Int) : Int fun sigdelset(SigsetT*, Int) : Int fun sigismember(SigsetT*, Int) : Int + fun sigsuspend(SigsetT*) : Int end diff --git a/src/lib_c/x86_64-freebsd/c/signal.cr b/src/lib_c/x86_64-freebsd/c/signal.cr index fd8d07cfd4cc..1878c373c22a 100644 --- a/src/lib_c/x86_64-freebsd/c/signal.cr +++ b/src/lib_c/x86_64-freebsd/c/signal.cr @@ -85,6 +85,7 @@ lib LibC fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int + fun pthread_kill(PthreadT, Int) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int @@ -93,4 +94,5 @@ lib LibC fun sigaddset(SigsetT*, Int) : Int fun sigdelset(SigsetT*, Int) : Int fun sigismember(SigsetT*, Int) : Int + fun sigsuspend(SigsetT*) : Int end diff --git a/src/lib_c/x86_64-linux-gnu/c/signal.cr b/src/lib_c/x86_64-linux-gnu/c/signal.cr index 07d8e0fe1ae6..b5ed2f8c8fb3 100644 --- a/src/lib_c/x86_64-linux-gnu/c/signal.cr +++ b/src/lib_c/x86_64-linux-gnu/c/signal.cr @@ -78,6 +78,7 @@ lib LibC fun kill(pid : PidT, sig : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int + fun pthread_kill(PthreadT, Int) : Int fun signal(sig : Int, handler : Int -> Void) : Int -> Void fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int @@ -86,4 +87,5 @@ lib LibC fun sigaddset(SigsetT*, Int) : Int fun sigdelset(SigsetT*, Int) : Int fun sigismember(SigsetT*, Int) : Int + fun sigsuspend(SigsetT*) : Int end diff --git a/src/lib_c/x86_64-linux-musl/c/signal.cr b/src/lib_c/x86_64-linux-musl/c/signal.cr index bba7e0c7c21a..42c2aead3e0f 100644 --- a/src/lib_c/x86_64-linux-musl/c/signal.cr +++ b/src/lib_c/x86_64-linux-musl/c/signal.cr @@ -77,6 +77,7 @@ lib LibC fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int + fun pthread_kill(PthreadT, Int) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int @@ -85,4 +86,5 @@ lib LibC fun sigaddset(SigsetT*, Int) : Int fun sigdelset(SigsetT*, Int) : Int fun sigismember(SigsetT*, Int) : Int + fun sigsuspend(SigsetT*) : Int end diff --git a/src/lib_c/x86_64-netbsd/c/signal.cr b/src/lib_c/x86_64-netbsd/c/signal.cr index 93d42e38b093..0b21c5c3f839 100644 --- a/src/lib_c/x86_64-netbsd/c/signal.cr +++ b/src/lib_c/x86_64-netbsd/c/signal.cr @@ -77,6 +77,7 @@ lib LibC fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int + fun pthread_kill(PthreadT, Int) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void fun sigaction = __sigaction14(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int fun sigaltstack = __sigaltstack14(x0 : StackT*, x1 : StackT*) : Int @@ -85,4 +86,5 @@ lib LibC fun sigaddset = __sigaddset14(SigsetT*, Int) : Int fun sigdelset = __sigdelset14(SigsetT*, Int) : Int fun sigismember = __sigismember14(SigsetT*, Int) : Int + fun sigsuspend(SigsetT*) : Int end diff --git a/src/lib_c/x86_64-openbsd/c/signal.cr b/src/lib_c/x86_64-openbsd/c/signal.cr index 04aa27000219..1c9b86137e4a 100644 --- a/src/lib_c/x86_64-openbsd/c/signal.cr +++ b/src/lib_c/x86_64-openbsd/c/signal.cr @@ -76,6 +76,7 @@ lib LibC fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int + fun pthread_kill(PthreadT, Int) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int @@ -84,4 +85,5 @@ lib LibC fun sigaddset(SigsetT*, Int) : Int fun sigdelset(SigsetT*, Int) : Int fun sigismember(SigsetT*, Int) : Int + fun sigsuspend(SigsetT*) : Int end diff --git a/src/lib_c/x86_64-solaris/c/signal.cr b/src/lib_c/x86_64-solaris/c/signal.cr index 9bde30946054..ee502aa621e4 100644 --- a/src/lib_c/x86_64-solaris/c/signal.cr +++ b/src/lib_c/x86_64-solaris/c/signal.cr @@ -90,6 +90,7 @@ lib LibC fun kill(x0 : PidT, x1 : Int) : Int fun pthread_sigmask(Int, SigsetT*, SigsetT*) : Int + fun pthread_kill(PthreadT, Int) : Int fun signal(x0 : Int, x1 : Int -> Void) : Int -> Void fun sigaction(x0 : Int, x1 : Sigaction*, x2 : Sigaction*) : Int fun sigaltstack(x0 : StackT*, x1 : StackT*) : Int @@ -98,4 +99,5 @@ lib LibC fun sigaddset(SigsetT*, Int) : Int fun sigdelset(SigsetT*, Int) : Int fun sigismember(SigsetT*, Int) : Int + fun sigsuspend(SigsetT*) : Int end From 196253fbfc7da02ac4aa442d74ee1466ebdc8351 Mon Sep 17 00:00:00 2001 From: Julien Portalier Date: Tue, 18 Jun 2024 12:02:41 +0200 Subject: [PATCH 3/8] Use same suspend/resume signals has bdwgc --- src/gc/none.cr | 16 ++++++++++++++-- src/lib_c/x86_64-freebsd/c/signal.cr | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/gc/none.cr b/src/gc/none.cr index d9f255773192..b0fc11a97713 100644 --- a/src/gc/none.cr +++ b/src/gc/none.cr @@ -160,8 +160,15 @@ module GC # :nodoc: class_property(sig_suspend : Int32) do + # follows bdwgc {% if flag?(:unix) %} - LibC::SIGUSR1 + {% if flag?(:linux) %} + LibC::SIGPWR + {% elsif LibC.has_constant?(:SIGRTMIN) %} + LibC::SIGRTMIN + 6 + {% else %} + LibC::SIGXFSZ + {% end %} {% else %} -1 {% end %} @@ -169,8 +176,13 @@ module GC # :nodoc: class_property(sig_resume : Int32) do + # follows bdwgc {% if flag?(:unix) %} - LibC::SIGUSR2 + {% if LibC.has_constant?(:SIGRTMIN) %} + LibC::SIGRTMIN + 5 + {% else %} + LibC::SIGXCPU + {% end %} {% else %} -1 {% end %} diff --git a/src/lib_c/x86_64-freebsd/c/signal.cr b/src/lib_c/x86_64-freebsd/c/signal.cr index 1878c373c22a..0b7c89b8d20f 100644 --- a/src/lib_c/x86_64-freebsd/c/signal.cr +++ b/src/lib_c/x86_64-freebsd/c/signal.cr @@ -33,6 +33,8 @@ lib LibC SIGEMT = 7 SIGINFO = 29 SIGWINCH = 28 + SIGRTMIN = 65 + SIGRTMIN = 126 SIGSTKSZ = 2048 + 32768 # MINSIGSTKSZ + 32768 SIG_SETMASK = 3 From c0802b98891e2941e81048e0da2fd903eb6707a5 Mon Sep 17 00:00:00 2001 From: Julien Portalier Date: Tue, 18 Jun 2024 12:35:29 +0200 Subject: [PATCH 4/8] Fix: private Thread#system_suspend and other methods --- src/crystal/system/thread.cr | 6 +++--- src/crystal/system/wasi/thread.cr | 6 +++--- src/crystal/system/win32/thread.cr | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/crystal/system/thread.cr b/src/crystal/system/thread.cr index f703238733ae..bedfcab388d4 100644 --- a/src/crystal/system/thread.cr +++ b/src/crystal/system/thread.cr @@ -26,11 +26,11 @@ module Crystal::System::Thread # def self.init_suspend_resume : Nil - # def system_suspend : Nil + # private def system_suspend : Nil - # def system_wait_suspended : Nil + # private def system_wait_suspended : Nil - # def system_resume : Nil + # private def system_resume : Nil end {% if flag?(:wasi) %} diff --git a/src/crystal/system/wasi/thread.cr b/src/crystal/system/wasi/thread.cr index d0dec50e33ad..1e8f6957d526 100644 --- a/src/crystal/system/wasi/thread.cr +++ b/src/crystal/system/wasi/thread.cr @@ -42,15 +42,15 @@ module Crystal::System::Thread def self.init_suspend_resume : Nil end - def system_suspend : Nil + private def system_suspend : Nil raise NotImplementedError.new("Crystal::System::Thread.system_suspend") end - def system_wait_suspended : Nil + private def system_wait_suspended : Nil raise NotImplementedError.new("Crystal::System::Thread.system_wait_suspended") end - def system_resume : Nil + private def system_resume : Nil raise NotImplementedError.new("Crystal::System::Thread.system_resume") end end diff --git a/src/crystal/system/win32/thread.cr b/src/crystal/system/win32/thread.cr index 6a961e1d3e89..fa012268f145 100644 --- a/src/crystal/system/win32/thread.cr +++ b/src/crystal/system/win32/thread.cr @@ -92,13 +92,13 @@ module Crystal::System::Thread def self.init_suspend_resume : Nil end - def system_suspend : Nil + private def system_suspend : Nil if LibC.SuspendThread(@system_handle) == -1 Crystal::System.panic("SuspendThread()") end end - def system_wait_suspended : Nil + private def system_wait_suspended : Nil # context must be aligned on 16 bytes but we lack a mean to force the # alignment on the struct, so we overallocate then realign the pointer: # @@ -113,7 +113,7 @@ module Crystal::System::Thread end end - def system_resume : Nil + private def system_resume : Nil if LibC.ResumeThread(@system_handle) == -1 Crystal::System.panic("ResumeThread()") end From b8c235d6e225c5574d8ee05aaa92fb16f540abf2 Mon Sep 17 00:00:00 2001 From: Julien Portalier Date: Tue, 18 Jun 2024 12:41:12 +0200 Subject: [PATCH 5/8] Fix: typo + format --- src/lib_c/x86_64-freebsd/c/signal.cr | 54 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/lib_c/x86_64-freebsd/c/signal.cr b/src/lib_c/x86_64-freebsd/c/signal.cr index 0b7c89b8d20f..c79d0630511b 100644 --- a/src/lib_c/x86_64-freebsd/c/signal.cr +++ b/src/lib_c/x86_64-freebsd/c/signal.cr @@ -8,33 +8,33 @@ lib LibC SIGILL = 4 SIGTRAP = 5 SIGIOT = LibC::SIGABRT - SIGABRT = 6 - SIGFPE = 8 - SIGKILL = 9 - SIGBUS = 10 - SIGSEGV = 11 - SIGSYS = 12 - SIGPIPE = 13 - SIGALRM = 14 - SIGTERM = 15 - SIGURG = 16 - SIGSTOP = 17 - SIGTSTP = 18 - SIGCONT = 19 - SIGCHLD = 20 - SIGTTIN = 21 - SIGTTOU = 22 - SIGIO = 23 - SIGXCPU = 24 - SIGXFSZ = 25 - SIGVTALRM = 26 - SIGUSR1 = 30 - SIGUSR2 = 31 - SIGEMT = 7 - SIGINFO = 29 - SIGWINCH = 28 - SIGRTMIN = 65 - SIGRTMIN = 126 + SIGABRT = 6 + SIGFPE = 8 + SIGKILL = 9 + SIGBUS = 10 + SIGSEGV = 11 + SIGSYS = 12 + SIGPIPE = 13 + SIGALRM = 14 + SIGTERM = 15 + SIGURG = 16 + SIGSTOP = 17 + SIGTSTP = 18 + SIGCONT = 19 + SIGCHLD = 20 + SIGTTIN = 21 + SIGTTOU = 22 + SIGIO = 23 + SIGXCPU = 24 + SIGXFSZ = 25 + SIGVTALRM = 26 + SIGUSR1 = 30 + SIGUSR2 = 31 + SIGEMT = 7 + SIGINFO = 29 + SIGWINCH = 28 + SIGRTMIN = 65 + SIGRTMAX = 126 SIGSTKSZ = 2048 + 32768 # MINSIGSTKSZ + 32768 SIG_SETMASK = 3 From e0bfda1094c56e73e094b032d44fd1cc1077e6f6 Mon Sep 17 00:00:00 2001 From: Julien Portalier Date: Wed, 19 Jun 2024 13:08:23 +0200 Subject: [PATCH 6/8] Fix: add Thread.start/stop_world + remove GC.sig_suspend/resume Thread is now the entrypoint for stopping the world. Delegating to the GC is an implementation detail. The `sig_resume` and `sig_suspend` properties are now set on Crystal::System::Thread and only for UNIX. --- src/crystal/system/thread.cr | 8 +++++ src/crystal/system/unix/pthread.cr | 30 ++++++++++++++--- src/crystal/system/win32/thread.cr | 5 +-- src/gc/boehm.cr | 25 -------------- src/gc/none.cr | 52 +++++++----------------------- 5 files changed, 46 insertions(+), 74 deletions(-) diff --git a/src/crystal/system/thread.cr b/src/crystal/system/thread.cr index bedfcab388d4..15a71a22756e 100644 --- a/src/crystal/system/thread.cr +++ b/src/crystal/system/thread.cr @@ -196,6 +196,14 @@ class Thread def resume : Nil system_resume end + + def stop_world : Nil + GC.stop_world + end + + def start_world : Nil + GC.start_world + end end require "./thread_linked_list" diff --git a/src/crystal/system/unix/pthread.cr b/src/crystal/system/unix/pthread.cr index 4ac0aa728bf0..aecd9e630224 100644 --- a/src/crystal/system/unix/pthread.cr +++ b/src/crystal/system/unix/pthread.cr @@ -172,13 +172,13 @@ module Crystal::System::Thread # block all signals but sig_resume mask = LibC::SigsetT.new LibC.sigfillset(pointerof(mask)) - LibC.sigdelset(pointerof(mask), GC.sig_resume) + LibC.sigdelset(pointerof(mask), sig_resume) # suspend the thread until it receives the sig_resume signal LibC.sigsuspend(pointerof(mask)) end LibC.sigemptyset(pointerof(action.@sa_mask)) - LibC.sigaction(GC.sig_suspend, pointerof(action), nil) + LibC.sigaction(sig_suspend, pointerof(action), nil) end private def self.install_sig_resume_signal_handler @@ -188,13 +188,13 @@ module Crystal::System::Thread # do nothing (a handler is still required to receive the signal) end LibC.sigemptyset(pointerof(action.@sa_mask)) - LibC.sigaction(GC.sig_resume, pointerof(action), nil) + LibC.sigaction(sig_resume, pointerof(action), nil) end private def system_suspend : Nil @suspended.set(false) - if LibC.pthread_kill(@system_handle, GC.sig_suspend) == -1 + if LibC.pthread_kill(@system_handle, Thread.sig_suspend) == -1 System.panic("pthread_kill()") end end @@ -206,10 +206,30 @@ module Crystal::System::Thread end private def system_resume : Nil - if LibC.pthread_kill(@system_handle, GC.sig_resume) == -1 + if LibC.pthread_kill(@system_handle, Thread.sig_resume) == -1 System.panic("pthread_kill()") end end + + protected class_property(sig_suspend : Int32) do + # follows bdwgc + {% if flag?(:linux) %} + LibC::SIGPWR + {% elsif LibC.has_constant?(:SIGRTMIN) %} + LibC::SIGRTMIN + 6 + {% else %} + LibC::SIGXFSZ + {% end %} + end + + protected class_property(sig_resume : Int32) do + # follows bdwgc + {% if LibC.has_constant?(:SIGRTMIN) %} + LibC::SIGRTMIN + 5 + {% else %} + LibC::SIGXCPU + {% end %} + end end # In musl (alpine) the calls to unwind API segfaults diff --git a/src/crystal/system/win32/thread.cr b/src/crystal/system/win32/thread.cr index fa012268f145..91b9676d6e5b 100644 --- a/src/crystal/system/win32/thread.cr +++ b/src/crystal/system/win32/thread.cr @@ -101,10 +101,7 @@ module Crystal::System::Thread private def system_wait_suspended : Nil # context must be aligned on 16 bytes but we lack a mean to force the # alignment on the struct, so we overallocate then realign the pointer: - # - # we only need to reserve UInt8[sizeof(LibC::CONTEXT) + 16] but that's - # invalid crystal - local = uninitialized LibC::CONTEXT[2] + local = uninitialized UInt8[sizeof(Tuple(LibC::CONTEXT, UInt8[15]))] thread_context = Pointer(LibC::CONTEXT).new(local.to_unsafe.address &+ 15_u64 & ~15_u64) thread_context.value.contextFlags = LibC::CONTEXT_FULL diff --git a/src/gc/boehm.cr b/src/gc/boehm.cr index a4d73e57e42a..0ce6a1366b6d 100644 --- a/src/gc/boehm.cr +++ b/src/gc/boehm.cr @@ -162,11 +162,6 @@ lib LibGC fun set_warn_proc = GC_set_warn_proc(WarnProc) $warn_proc = GC_current_warn_proc : WarnProc - fun get_suspend_signal = GC_get_suspend_signal : Int - fun get_thr_restart_signal = GC_get_thr_restart_signal : Int - fun set_suspend_signal = GC_set_suspend_signal(Int) : Int - fun set_thr_restart_signal = GC_set_thr_restart_signal(Int) : Int - fun stop_world_external = GC_stop_world_external fun start_world_external = GC_start_world_external end @@ -479,26 +474,6 @@ module GC end {% end %} - # :nodoc: - def sig_suspend : Int32 - LibGC.get_suspend_signal - end - - # :nodoc: - def sig_suspend=(value : Int32) : Int32 - LibGC.set_suspend_signal(value) - end - - # :nodoc: - def sig_resume : Int32 - LibGC.get_thr_restart_signal - end - - # :nodoc: - def sig_resume=(value : Int32) : Int32 - LibGC.set_thr_restart_signal(value) - end - # :nodoc: def self.stop_world : Nil LibGC.stop_world_external diff --git a/src/gc/none.cr b/src/gc/none.cr index b0fc11a97713..6f51fd69bae2 100644 --- a/src/gc/none.cr +++ b/src/gc/none.cr @@ -142,52 +142,24 @@ module GC # # This isn't a GC-safe stop-the-world implementation (it may allocate objects # while stopping the world), but the guarantees are enough for the purpose of - # gc_none. + # gc_none. It could be GC-safe if Thread::LinkedList(T) became a struct, and + # Thread::Mutex either became a struct or provide low level abstraction + # methods that directly interact with syscalls (without allocating). # - # Thread safety is guaranteed by the mutex in Crystal::PointerLinkedList: - # either a thread is starting and hasn't added itself to the list (it will - # block until it can acquire the lock), or is currently adding itself (the - # current thread will block until it can acquire the lock). + # Thread safety is guaranteed by the mutex in Thread::LinkedList: either a + # thread is starting and hasn't added itself to the list (it will block until + # it can acquire the lock), or is currently adding itself (the current thread + # will block until it can acquire the lock). # # In both cases there can't be a deadlock since we won't suspend another - # thread until it has successfuly added (or removed) itself to the linked - # list and released the lock, and the other thread won't progress until it - # can add (or remove) itself from the list. + # thread until it has successfuly added (or removed) itself to (from) the + # linked list and released the lock, and the other thread won't progress until + # it can add (or remove) itself from the list. # - # Finally, we lock the mutex and keep it locked until we resume the world, - # so any thread waiting on the mutex will only be resumed when the world is + # Finally, we lock the mutex and keep it locked until we resume the world, so + # any thread waiting on the mutex will only be resumed when the world is # resumed. - # :nodoc: - class_property(sig_suspend : Int32) do - # follows bdwgc - {% if flag?(:unix) %} - {% if flag?(:linux) %} - LibC::SIGPWR - {% elsif LibC.has_constant?(:SIGRTMIN) %} - LibC::SIGRTMIN + 6 - {% else %} - LibC::SIGXFSZ - {% end %} - {% else %} - -1 - {% end %} - end - - # :nodoc: - class_property(sig_resume : Int32) do - # follows bdwgc - {% if flag?(:unix) %} - {% if LibC.has_constant?(:SIGRTMIN) %} - LibC::SIGRTMIN + 5 - {% else %} - LibC::SIGXCPU - {% end %} - {% else %} - -1 - {% end %} - end - # :nodoc: def self.stop_world : Nil current_thread = Thread.current From 8c7da1c1cc18fdb5a802f7223171773a7c976285 Mon Sep 17 00:00:00 2001 From: Julien Portalier Date: Wed, 19 Jun 2024 13:31:09 +0200 Subject: [PATCH 7/8] fixup! Fix: add Thread.start/stop_world + remove GC.sig_suspend/resume --- src/crystal/system/thread.cr | 4 ++-- src/crystal/system/unix/pthread.cr | 24 +++++++++++------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/crystal/system/thread.cr b/src/crystal/system/thread.cr index 15a71a22756e..431708c5cc11 100644 --- a/src/crystal/system/thread.cr +++ b/src/crystal/system/thread.cr @@ -197,11 +197,11 @@ class Thread system_resume end - def stop_world : Nil + def self.stop_world : Nil GC.stop_world end - def start_world : Nil + def self.start_world : Nil GC.start_world end end diff --git a/src/crystal/system/unix/pthread.cr b/src/crystal/system/unix/pthread.cr index aecd9e630224..41f7bf182316 100644 --- a/src/crystal/system/unix/pthread.cr +++ b/src/crystal/system/unix/pthread.cr @@ -169,16 +169,16 @@ module Crystal::System::Thread # notify that the thread has been interrupted Thread.current_thread.@suspended.set(true) - # block all signals but sig_resume + # block all signals but SIG_RESUME mask = LibC::SigsetT.new LibC.sigfillset(pointerof(mask)) - LibC.sigdelset(pointerof(mask), sig_resume) + LibC.sigdelset(pointerof(mask), SIG_RESUME) - # suspend the thread until it receives the sig_resume signal + # suspend the thread until it receives the SIG_RESUME signal LibC.sigsuspend(pointerof(mask)) end LibC.sigemptyset(pointerof(action.@sa_mask)) - LibC.sigaction(sig_suspend, pointerof(action), nil) + LibC.sigaction(SIG_SUSPEND, pointerof(action), nil) end private def self.install_sig_resume_signal_handler @@ -188,13 +188,13 @@ module Crystal::System::Thread # do nothing (a handler is still required to receive the signal) end LibC.sigemptyset(pointerof(action.@sa_mask)) - LibC.sigaction(sig_resume, pointerof(action), nil) + LibC.sigaction(SIG_RESUME, pointerof(action), nil) end private def system_suspend : Nil @suspended.set(false) - if LibC.pthread_kill(@system_handle, Thread.sig_suspend) == -1 + if LibC.pthread_kill(@system_handle, SIG_SUSPEND) == -1 System.panic("pthread_kill()") end end @@ -206,13 +206,14 @@ module Crystal::System::Thread end private def system_resume : Nil - if LibC.pthread_kill(@system_handle, Thread.sig_resume) == -1 + if LibC.pthread_kill(@system_handle, SIG_RESUME) == -1 System.panic("pthread_kill()") end end - protected class_property(sig_suspend : Int32) do - # follows bdwgc + # the suspend/resume signals follow BDWGC + + private SIG_SUSPEND = {% if flag?(:linux) %} LibC::SIGPWR {% elsif LibC.has_constant?(:SIGRTMIN) %} @@ -220,16 +221,13 @@ module Crystal::System::Thread {% else %} LibC::SIGXFSZ {% end %} - end - protected class_property(sig_resume : Int32) do - # follows bdwgc + private SIG_RESUME = {% if LibC.has_constant?(:SIGRTMIN) %} LibC::SIGRTMIN + 5 {% else %} LibC::SIGXCPU {% end %} - end end # In musl (alpine) the calls to unwind API segfaults From 88d2be3e8aa5811e5b60bd993325a8e2f0e5e9b9 Mon Sep 17 00:00:00 2001 From: Julien Portalier Date: Thu, 27 Jun 2024 11:44:57 +0200 Subject: [PATCH 8/8] Fix: Crystal::System.panic needs explicit Errno/WinError --- src/crystal/system/unix/pthread.cr | 4 ++-- src/crystal/system/win32/thread.cr | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/crystal/system/unix/pthread.cr b/src/crystal/system/unix/pthread.cr index 41f7bf182316..b55839ff2784 100644 --- a/src/crystal/system/unix/pthread.cr +++ b/src/crystal/system/unix/pthread.cr @@ -195,7 +195,7 @@ module Crystal::System::Thread @suspended.set(false) if LibC.pthread_kill(@system_handle, SIG_SUSPEND) == -1 - System.panic("pthread_kill()") + System.panic("pthread_kill()", Errno.value) end end @@ -207,7 +207,7 @@ module Crystal::System::Thread private def system_resume : Nil if LibC.pthread_kill(@system_handle, SIG_RESUME) == -1 - System.panic("pthread_kill()") + System.panic("pthread_kill()", Errno.value) end end diff --git a/src/crystal/system/win32/thread.cr b/src/crystal/system/win32/thread.cr index 91b9676d6e5b..1a4f61a41738 100644 --- a/src/crystal/system/win32/thread.cr +++ b/src/crystal/system/win32/thread.cr @@ -94,7 +94,7 @@ module Crystal::System::Thread private def system_suspend : Nil if LibC.SuspendThread(@system_handle) == -1 - Crystal::System.panic("SuspendThread()") + Crystal::System.panic("SuspendThread()", WinError.value) end end @@ -106,13 +106,13 @@ module Crystal::System::Thread thread_context.value.contextFlags = LibC::CONTEXT_FULL if LibC.GetThreadContext(@system_handle, thread_context) == -1 - Crystal::System.panic("GetThreadContext()") + Crystal::System.panic("GetThreadContext()", WinError.value) end end private def system_resume : Nil if LibC.ResumeThread(@system_handle) == -1 - Crystal::System.panic("ResumeThread()") + Crystal::System.panic("ResumeThread()", WinError.value) end end end