diff --git a/spec/std/thread_spec.cr b/spec/std/thread_spec.cr index 599a1968f52f..136026667137 100644 --- a/spec/std/thread_spec.cr +++ b/spec/std/thread_spec.cr @@ -49,4 +49,17 @@ describe Thread do thread.join end + + it "names the thread" do + Thread.current.name.should be_nil + name = nil + + thread = Thread.new(name: "some-name") do + name = Thread.current.name + end + thread.name.should eq("some-name") + + thread.join + name.should eq("some-name") + end end diff --git a/src/crystal/scheduler.cr b/src/crystal/scheduler.cr index fa963595bf6d..101a287d23bb 100644 --- a/src/crystal/scheduler.cr +++ b/src/crystal/scheduler.cr @@ -234,7 +234,7 @@ class Crystal::Scheduler Thread.current.scheduler.enqueue worker_loop Thread.current else - Thread.new do + Thread.new(name: "CRYSTAL-MT-#{i}") do scheduler = Thread.current.scheduler pending.sub(1) scheduler.run_loop diff --git a/src/crystal/system/thread.cr b/src/crystal/system/thread.cr index 88784ed68330..b40a7dceb32b 100644 --- a/src/crystal/system/thread.cr +++ b/src/crystal/system/thread.cr @@ -17,6 +17,8 @@ module Crystal::System::Thread # private def system_close # private def stack_address : Void* + + # private def system_name=(String) : String end {% if flag?(:wasi) %} @@ -49,12 +51,14 @@ class Thread # :nodoc: property previous : Thread? + getter name : String? + def self.unsafe_each(&) threads.unsafe_each { |thread| yield thread } end # Creates and starts a new system thread. - def initialize(&@func : ->) + def initialize(@name : String? = nil, &@func : ->) @system_handle = uninitialized Crystal::System::Thread::Handle init_handle end @@ -104,6 +108,12 @@ class Thread Crystal::System::Thread.yield_current end + # Changes the name of the current thread. + def self.name=(name : String) : String + thread = Thread.current + thread.name = name + end + # :nodoc: getter scheduler : Crystal::Scheduler { Crystal::Scheduler.new(self) } @@ -112,6 +122,10 @@ class Thread Thread.current = self @main_fiber = fiber = Fiber.new(stack_address, self) + if name = @name + self.system_name = name + end + begin @func.call rescue ex @@ -123,6 +137,10 @@ class Thread end end + protected def name=(@name : String) + self.system_name = name + end + # Holds the GC thread handler property gc_thread_handler : Void* = Pointer(Void).null end diff --git a/src/crystal/system/unix/pthread.cr b/src/crystal/system/unix/pthread.cr index ca16080621e3..5d6e2a332adc 100644 --- a/src/crystal/system/unix/pthread.cr +++ b/src/crystal/system/unix/pthread.cr @@ -112,6 +112,23 @@ module Crystal::System::Thread address end + + # Warning: must be called from the current thread itself, because Darwin + # doesn't allow to set the name of any thread but the current one! + private def system_name=(name : String) : String + {% if flag?(:darwin) %} + LibC.pthread_setname_np(name) + {% elsif flag?(:netbsd) %} + LibC.pthread_setname_np(@system_handle, name, nil) + {% elsif LibC.has_method?(:pthread_setname_np) %} + LibC.pthread_setname_np(@system_handle, name) + {% elsif LibC.has_method?(:pthread_set_name_np) %} + LibC.pthread_set_name_np(@system_handle, name) + {% else %} + {% raise "No `Crystal::System::Thread#system_name` implementation available" %} + {% end %} + name + 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 5dbcbabbfad9..2b44f66c28ce 100644 --- a/src/crystal/system/win32/thread.cr +++ b/src/crystal/system/win32/thread.cr @@ -72,4 +72,11 @@ module Crystal::System::Thread low_limit {% end %} end + + private def system_name=(name : String) : String + {% if LibC.has_method?(:SetThreadDescription) %} + LibC.SetThreadDescription(@system_handle, System.to_wstr(name)) + {% end %} + name + end end diff --git a/src/lib_c/aarch64-android/c/pthread.cr b/src/lib_c/aarch64-android/c/pthread.cr index d761bcb3ceb2..fbab59bd07d7 100644 --- a/src/lib_c/aarch64-android/c/pthread.cr +++ b/src/lib_c/aarch64-android/c/pthread.cr @@ -38,6 +38,7 @@ lib LibC fun pthread_mutex_unlock(__mutex : PthreadMutexT*) : Int fun pthread_self : PthreadT + fun pthread_setname_np(__key : PthreadT, __name : Char*) : Int fun pthread_setspecific(__key : PthreadKeyT, __value : Void*) : Int end diff --git a/src/lib_c/aarch64-darwin/c/pthread.cr b/src/lib_c/aarch64-darwin/c/pthread.cr index dd262f7d9c12..d146e227197f 100644 --- a/src/lib_c/aarch64-darwin/c/pthread.cr +++ b/src/lib_c/aarch64-darwin/c/pthread.cr @@ -25,4 +25,5 @@ lib LibC fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT + fun pthread_setname_np(Char*) : Int end diff --git a/src/lib_c/aarch64-linux-gnu/c/pthread.cr b/src/lib_c/aarch64-linux-gnu/c/pthread.cr index 643fca7c015a..5d9f7b94e225 100644 --- a/src/lib_c/aarch64-linux-gnu/c/pthread.cr +++ b/src/lib_c/aarch64-linux-gnu/c/pthread.cr @@ -36,4 +36,5 @@ lib LibC fun pthread_mutex_trylock(mutex : PthreadMutexT*) : Int fun pthread_mutex_unlock(mutex : PthreadMutexT*) : Int fun pthread_self : PthreadT + fun pthread_setname_np(PthreadT, Char*) : Int end diff --git a/src/lib_c/aarch64-linux-musl/c/pthread.cr b/src/lib_c/aarch64-linux-musl/c/pthread.cr index c318bb5f4357..6ee1a20d90a6 100644 --- a/src/lib_c/aarch64-linux-musl/c/pthread.cr +++ b/src/lib_c/aarch64-linux-musl/c/pthread.cr @@ -27,4 +27,5 @@ lib LibC fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT + fun pthread_setname_np(PthreadT, Char*) : Int end diff --git a/src/lib_c/arm-linux-gnueabihf/c/pthread.cr b/src/lib_c/arm-linux-gnueabihf/c/pthread.cr index 643fca7c015a..5d9f7b94e225 100644 --- a/src/lib_c/arm-linux-gnueabihf/c/pthread.cr +++ b/src/lib_c/arm-linux-gnueabihf/c/pthread.cr @@ -36,4 +36,5 @@ lib LibC fun pthread_mutex_trylock(mutex : PthreadMutexT*) : Int fun pthread_mutex_unlock(mutex : PthreadMutexT*) : Int fun pthread_self : PthreadT + fun pthread_setname_np(PthreadT, Char*) : Int end diff --git a/src/lib_c/i386-linux-gnu/c/pthread.cr b/src/lib_c/i386-linux-gnu/c/pthread.cr index ab943b23587d..33274a6cf51d 100644 --- a/src/lib_c/i386-linux-gnu/c/pthread.cr +++ b/src/lib_c/i386-linux-gnu/c/pthread.cr @@ -35,4 +35,5 @@ lib LibC fun pthread_mutex_trylock(mutex : PthreadMutexT*) : Int fun pthread_mutex_unlock(mutex : PthreadMutexT*) : Int fun pthread_self : PthreadT + fun pthread_setname_np(PthreadT, Char*) : Int end diff --git a/src/lib_c/i386-linux-musl/c/pthread.cr b/src/lib_c/i386-linux-musl/c/pthread.cr index c318bb5f4357..6ee1a20d90a6 100644 --- a/src/lib_c/i386-linux-musl/c/pthread.cr +++ b/src/lib_c/i386-linux-musl/c/pthread.cr @@ -27,4 +27,5 @@ lib LibC fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT + fun pthread_setname_np(PthreadT, Char*) : Int end diff --git a/src/lib_c/x86_64-darwin/c/pthread.cr b/src/lib_c/x86_64-darwin/c/pthread.cr index dd262f7d9c12..d146e227197f 100644 --- a/src/lib_c/x86_64-darwin/c/pthread.cr +++ b/src/lib_c/x86_64-darwin/c/pthread.cr @@ -25,4 +25,5 @@ lib LibC fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT + fun pthread_setname_np(Char*) : Int end diff --git a/src/lib_c/x86_64-dragonfly/c/pthread.cr b/src/lib_c/x86_64-dragonfly/c/pthread.cr index 87ae8c05c358..90bf0c6285a0 100644 --- a/src/lib_c/x86_64-dragonfly/c/pthread.cr +++ b/src/lib_c/x86_64-dragonfly/c/pthread.cr @@ -29,4 +29,5 @@ lib LibC fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT + fun pthread_setname_np(PthreadT, Char*) : Int end diff --git a/src/lib_c/x86_64-freebsd/c/pthread.cr b/src/lib_c/x86_64-freebsd/c/pthread.cr index 87ae8c05c358..9cc78c2f2850 100644 --- a/src/lib_c/x86_64-freebsd/c/pthread.cr +++ b/src/lib_c/x86_64-freebsd/c/pthread.cr @@ -29,4 +29,5 @@ lib LibC fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT + fun pthread_set_name_np(PthreadT, Char*) end diff --git a/src/lib_c/x86_64-linux-gnu/c/pthread.cr b/src/lib_c/x86_64-linux-gnu/c/pthread.cr index ab943b23587d..33274a6cf51d 100644 --- a/src/lib_c/x86_64-linux-gnu/c/pthread.cr +++ b/src/lib_c/x86_64-linux-gnu/c/pthread.cr @@ -35,4 +35,5 @@ lib LibC fun pthread_mutex_trylock(mutex : PthreadMutexT*) : Int fun pthread_mutex_unlock(mutex : PthreadMutexT*) : Int fun pthread_self : PthreadT + fun pthread_setname_np(PthreadT, Char*) : Int end diff --git a/src/lib_c/x86_64-linux-musl/c/pthread.cr b/src/lib_c/x86_64-linux-musl/c/pthread.cr index c318bb5f4357..6ee1a20d90a6 100644 --- a/src/lib_c/x86_64-linux-musl/c/pthread.cr +++ b/src/lib_c/x86_64-linux-musl/c/pthread.cr @@ -27,4 +27,5 @@ lib LibC fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT + fun pthread_setname_np(PthreadT, Char*) : Int end diff --git a/src/lib_c/x86_64-netbsd/c/pthread.cr b/src/lib_c/x86_64-netbsd/c/pthread.cr index 133d4922c57f..e0f477018777 100644 --- a/src/lib_c/x86_64-netbsd/c/pthread.cr +++ b/src/lib_c/x86_64-netbsd/c/pthread.cr @@ -35,5 +35,6 @@ lib LibC fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT + fun pthread_setname_np(PthreadT, Char*, Void*) : Int fun pthread_setspecific(PthreadKeyT, Void*) : Int end diff --git a/src/lib_c/x86_64-openbsd/c/pthread.cr b/src/lib_c/x86_64-openbsd/c/pthread.cr index 788823c40a31..15773336f239 100644 --- a/src/lib_c/x86_64-openbsd/c/pthread.cr +++ b/src/lib_c/x86_64-openbsd/c/pthread.cr @@ -30,6 +30,7 @@ lib LibC fun pthread_mutex_trylock(x0 : PthreadMutexT*) : Int fun pthread_mutex_unlock(x0 : PthreadMutexT*) : Int fun pthread_self : PthreadT + fun pthread_set_name_np(PthreadT, Char*) fun pthread_setspecific(PthreadKeyT, Void*) : Int fun pthread_stackseg_np(PthreadT, StackT*) : Int 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 9c22d4530c81..efa684075162 100644 --- a/src/lib_c/x86_64-windows-msvc/c/processthreadsapi.cr +++ b/src/lib_c/x86_64-windows-msvc/c/processthreadsapi.cr @@ -50,6 +50,9 @@ lib LibC bInheritHandles : BOOL, dwCreationFlags : DWORD, lpEnvironment : Void*, lpCurrentDirectory : LPWSTR, lpStartupInfo : STARTUPINFOW*, lpProcessInformation : PROCESS_INFORMATION*) : BOOL + {% if LibC::WIN32_WINNT >= LibC::WIN32_WINNT_WIN10 %} + fun SetThreadDescription(hThread : HANDLE, lpThreadDescription : LPWSTR) : LONG + {% end %} fun SetThreadStackGuarantee(stackSizeInBytes : DWORD*) : BOOL fun GetProcessTimes(hProcess : HANDLE, lpCreationTime : FILETIME*, lpExitTime : FILETIME*, lpKernelTime : FILETIME*, lpUserTime : FILETIME*) : BOOL