From 7b14dd8ebe4986a26dea5fc223b99b97d33c3e4c Mon Sep 17 00:00:00 2001 From: Denis Feklushkin Date: Sat, 4 Jul 2026 19:36:31 +0300 Subject: [PATCH 1/8] osthread: gettid() alias added --- druntime/src/core/thread/osthread.d | 4 ++-- druntime/src/core/thread/posix_impl.d | 2 ++ druntime/src/core/thread/windows_impl.d | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/druntime/src/core/thread/osthread.d b/druntime/src/core/thread/osthread.d index 61ed05cac048..f9729ac276c3 100644 --- a/druntime/src/core/thread/osthread.d +++ b/druntime/src/core/thread/osthread.d @@ -1155,7 +1155,7 @@ private extern (D) bool suspend( Thread t ) nothrow @nogc version (Windows) { - if ( t.m_addr != GetCurrentThreadId() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF ) + if ( t.m_addr != gettid() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF ) { if ( !t.isRunning ) { @@ -1476,7 +1476,7 @@ private extern (D) bool suspend( Thread t ) nothrow @nogc } else version (Posix) { - if ( t.m_addr != pthread_self() ) + if ( t.m_addr != gettid() ) { if ( pthread_kill( t.m_addr, suspendSignalNumber ) != 0 ) { diff --git a/druntime/src/core/thread/posix_impl.d b/druntime/src/core/thread/posix_impl.d index 036068184d6e..d284c4dc1034 100644 --- a/druntime/src/core/thread/posix_impl.d +++ b/druntime/src/core/thread/posix_impl.d @@ -584,3 +584,5 @@ class Thread : ThreadBase sched_yield(); } } + +package alias gettid = imported!"core.sys.posix.pthread".pthread_self; diff --git a/druntime/src/core/thread/windows_impl.d b/druntime/src/core/thread/windows_impl.d index a3372fe18972..ff74b592e34e 100644 --- a/druntime/src/core/thread/windows_impl.d +++ b/druntime/src/core/thread/windows_impl.d @@ -242,3 +242,5 @@ class Thread : ThreadBase SwitchToThread(); } } + +package alias gettid = imported!"core.sys.windows.winbase".GetCurrentThreadId; From 19c7e3e9ca98d8823820ffcca713309a49812aa6 Mon Sep 17 00:00:00 2001 From: Denis Feklushkin Date: Sat, 4 Jul 2026 20:09:50 +0300 Subject: [PATCH 2/8] suspendThreadImpl added, implemented for Darwin, Posix and Windows --- druntime/src/core/thread/osthread.d | 18 +++++++++++++++--- druntime/src/core/thread/windows_impl.d | 6 ++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/druntime/src/core/thread/osthread.d b/druntime/src/core/thread/osthread.d index f9729ac276c3..5b2626566822 100644 --- a/druntime/src/core/thread/osthread.d +++ b/druntime/src/core/thread/osthread.d @@ -1129,6 +1129,18 @@ private extern(D) void* getStackBottom() nothrow @nogc static assert(false, "Platform not supported."); } + +// Returns true on success +// TODO: move to posix_impl module +version (Posix) +package bool suspendThreadImpl(Thread t) @nogc nothrow +{ + version (Darwin) + return thread_suspend(t.m_tmach) == KERN_SUCCESS; + else + return pthread_kill(t.m_addr, suspendSignalNumber) == 0; +} + /** * Suspend the specified thread and load stack and register information for * use by thread_scanAll. If the supplied thread is the calling thread, @@ -1155,7 +1167,7 @@ private extern (D) bool suspend( Thread t ) nothrow @nogc version (Windows) { - if ( t.m_addr != gettid() && SuspendThread( t.m_hndl ) == 0xFFFFFFFF ) + if ( t.m_addr != gettid() && !suspendThreadImpl( t ) ) { if ( !t.isRunning ) { @@ -1214,7 +1226,7 @@ private extern (D) bool suspend( Thread t ) nothrow @nogc } else version (Darwin) { - if ( t.m_addr != pthread_self() && thread_suspend( t.m_tmach ) != KERN_SUCCESS ) + if ( t.m_addr != gettid() && !suspendThreadImpl( t ) ) { if ( !t.isRunning ) { @@ -1478,7 +1490,7 @@ private extern (D) bool suspend( Thread t ) nothrow @nogc { if ( t.m_addr != gettid() ) { - if ( pthread_kill( t.m_addr, suspendSignalNumber ) != 0 ) + if ( !suspendThreadImpl( t ) ) { if ( !t.isRunning ) { diff --git a/druntime/src/core/thread/windows_impl.d b/druntime/src/core/thread/windows_impl.d index ff74b592e34e..d24052b21d02 100644 --- a/druntime/src/core/thread/windows_impl.d +++ b/druntime/src/core/thread/windows_impl.d @@ -244,3 +244,9 @@ class Thread : ThreadBase } package alias gettid = imported!"core.sys.windows.winbase".GetCurrentThreadId; + +// Returns true on success +package bool suspendThreadImpl(Thread t) @nogc nothrow +{ + return SuspendThread(t.m_hndl) != 0xFFFFFFFF; +} From 8ac650dc96a5a55b163acead6f0d3039265eb2c9 Mon Sep 17 00:00:00 2001 From: Denis Feklushkin Date: Sat, 4 Jul 2026 20:32:13 +0300 Subject: [PATCH 3/8] suspendThreadImpl used by Solaris version --- druntime/src/core/thread/osthread.d | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/druntime/src/core/thread/osthread.d b/druntime/src/core/thread/osthread.d index 5b2626566822..2d0b31309308 100644 --- a/druntime/src/core/thread/osthread.d +++ b/druntime/src/core/thread/osthread.d @@ -1137,6 +1137,8 @@ package bool suspendThreadImpl(Thread t) @nogc nothrow { version (Darwin) return thread_suspend(t.m_tmach) == KERN_SUCCESS; + else version (Solaris) + return thr_suspend(t.m_addr) == 0; else return pthread_kill(t.m_addr, suspendSignalNumber) == 0; } @@ -1351,9 +1353,9 @@ private extern (D) bool suspend( Thread t ) nothrow @nogc } else version (Solaris) { - if (t.m_addr != pthread_self()) + if (t.m_addr != gettid()) { - if (thr_suspend(t.m_addr) != 0) + if (!suspendThreadImpl(t)) { if (!t.isRunning) { From abf9fb1bd38acc898efd79abec4b576b01c54044 Mon Sep 17 00:00:00 2001 From: Denis Feklushkin Date: Sat, 4 Jul 2026 20:42:15 +0300 Subject: [PATCH 4/8] WASI: gettid and suspendThreadImpl stubs added --- druntime/src/core/thread/wasi_impl.d | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/druntime/src/core/thread/wasi_impl.d b/druntime/src/core/thread/wasi_impl.d index 752634641819..a65ef00b4412 100644 --- a/druntime/src/core/thread/wasi_impl.d +++ b/druntime/src/core/thread/wasi_impl.d @@ -156,3 +156,16 @@ class Thread : ThreadBase // do nothing } } + +package ThreadID gettid() @nogc nothrow +{ + onThreadError( "Unable to get WASI thread ID" ); + assert(0); +} + +// Returns true on success +package bool suspendThreadImpl(Thread t) @nogc nothrow +{ + onThreadError( "Unable to suspend thread" ); + assert(0); +} From 786e82989daf12e9363cd26e75ad85209454ba29 Mon Sep 17 00:00:00 2001 From: Denis Feklushkin Date: Sat, 4 Jul 2026 21:16:42 +0300 Subject: [PATCH 5/8] osthread: suspend() is unified for all OSes, loadStackAndRegInfo implements external differences --- druntime/src/core/thread/osthread.d | 58 ++++++++++------------------- 1 file changed, 19 insertions(+), 39 deletions(-) diff --git a/druntime/src/core/thread/osthread.d b/druntime/src/core/thread/osthread.d index 2d0b31309308..3999097bd1fc 100644 --- a/druntime/src/core/thread/osthread.d +++ b/druntime/src/core/thread/osthread.d @@ -1167,18 +1167,31 @@ private extern (D) bool suspend( Thread t ) nothrow @nogc return false; } - version (Windows) + const sameThread = t.m_addr == gettid(); + + if (!sameThread) { - if ( t.m_addr != gettid() && !suspendThreadImpl( t ) ) + if (!suspendThreadImpl(t)) { - if ( !t.isRunning ) + if (t.isRunning) + onThreadError( "Unable to suspend thread" ); + else { Thread.remove( t ); return false; } - onThreadError( "Unable to suspend thread" ); } + } + + loadStackAndRegInfo(t, sameThread); + + return true; +} +private void loadStackAndRegInfo(Thread t, const bool sameThread) nothrow @nogc +{ + version (Windows) + { CONTEXT context = void; context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL; @@ -1228,16 +1241,6 @@ private extern (D) bool suspend( Thread t ) nothrow @nogc } else version (Darwin) { - if ( t.m_addr != gettid() && !suspendThreadImpl( t ) ) - { - if ( !t.isRunning ) - { - Thread.remove( t ); - return false; - } - onThreadError( "Unable to suspend thread" ); - } - version (X86) { x86_thread_state32_t state = void; @@ -1353,18 +1356,8 @@ private extern (D) bool suspend( Thread t ) nothrow @nogc } else version (Solaris) { - if (t.m_addr != gettid()) + if (!sameThread) { - if (!suspendThreadImpl(t)) - { - if (!t.isRunning) - { - Thread.remove(t); - return false; - } - onThreadError("Unable to suspend thread"); - } - static int getLwpStatus(ulong lwpid, out lwpstatus_t status) { import core.sys.posix.fcntl : open, O_RDONLY; @@ -1490,19 +1483,7 @@ private extern (D) bool suspend( Thread t ) nothrow @nogc } else version (Posix) { - if ( t.m_addr != gettid() ) - { - if ( !suspendThreadImpl( t ) ) - { - if ( !t.isRunning ) - { - Thread.remove( t ); - return false; - } - onThreadError( "Unable to suspend thread" ); - } - } - else if ( !t.m_lock ) + if (sameThread && !t.m_lock) { t.m_curr.tstack = getStackTop(); } @@ -1513,7 +1494,6 @@ private extern (D) bool suspend( Thread t ) nothrow @nogc } else static assert(0, "unsupported os"); - return true; } /** From f9c3e55f5021517d335bffaf8a76ee26e69ab6f5 Mon Sep 17 00:00:00 2001 From: Denis Feklushkin Date: Sat, 4 Jul 2026 21:42:44 +0300 Subject: [PATCH 6/8] osthread: resumeThreadImpl implemented for all platforms --- druntime/src/core/thread/osthread.d | 13 +++++++++++++ druntime/src/core/thread/wasi_impl.d | 7 +++++++ druntime/src/core/thread/windows_impl.d | 6 ++++++ 3 files changed, 26 insertions(+) diff --git a/druntime/src/core/thread/osthread.d b/druntime/src/core/thread/osthread.d index 3999097bd1fc..0f8d0a1d68e6 100644 --- a/druntime/src/core/thread/osthread.d +++ b/druntime/src/core/thread/osthread.d @@ -1143,6 +1143,19 @@ package bool suspendThreadImpl(Thread t) @nogc nothrow return pthread_kill(t.m_addr, suspendSignalNumber) == 0; } +// Returns true on success +// TODO: move to posix_impl module +version (Posix) +package bool resumeThreadImpl(Thread t) @nogc nothrow +{ + version (Darwin) + return thread_resume(t.m_tmach) == KERN_SUCCESS; + else version (Solaris) + return thr_continue(t.m_addr) == 0; + else + return pthread_kill(t.m_addr, resumeSignalNumber) == 0; +} + /** * Suspend the specified thread and load stack and register information for * use by thread_scanAll. If the supplied thread is the calling thread, diff --git a/druntime/src/core/thread/wasi_impl.d b/druntime/src/core/thread/wasi_impl.d index a65ef00b4412..20294e80e5fa 100644 --- a/druntime/src/core/thread/wasi_impl.d +++ b/druntime/src/core/thread/wasi_impl.d @@ -169,3 +169,10 @@ package bool suspendThreadImpl(Thread t) @nogc nothrow onThreadError( "Unable to suspend thread" ); assert(0); } + +// Returns true on success +package bool resumeThreadImpl(Thread t) @nogc nothrow +{ + onThreadError( "Unable to suspend thread" ); + assert(0); +} diff --git a/druntime/src/core/thread/windows_impl.d b/druntime/src/core/thread/windows_impl.d index d24052b21d02..3de78afc3ccf 100644 --- a/druntime/src/core/thread/windows_impl.d +++ b/druntime/src/core/thread/windows_impl.d @@ -250,3 +250,9 @@ package bool suspendThreadImpl(Thread t) @nogc nothrow { return SuspendThread(t.m_hndl) != 0xFFFFFFFF; } + +// Returns true on success +package bool resumeThreadImpl(Thread t) @nogc nothrow +{ + return ResumeThread(t.m_hndl) != 0xFFFFFFFF; +} From bdb8ea3e28e0030cf3e5eb284251997dbf16eeaf Mon Sep 17 00:00:00 2001 From: Denis Feklushkin Date: Sat, 4 Jul 2026 21:52:54 +0300 Subject: [PATCH 7/8] osthread: resume() code deduplication --- druntime/src/core/thread/osthread.d | 52 +++++++++-------------------- 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/druntime/src/core/thread/osthread.d b/druntime/src/core/thread/osthread.d index 0f8d0a1d68e6..eb21f3197fd6 100644 --- a/druntime/src/core/thread/osthread.d +++ b/druntime/src/core/thread/osthread.d @@ -1622,70 +1622,48 @@ extern (C) void thread_suspendAll() nothrow private extern (D) void resume(ThreadBase _t) nothrow @nogc { Thread t = _t.toThread; + const sameThread = t.m_addr == gettid(); - version (Windows) + if (!sameThread) { - if ( t.m_addr != GetCurrentThreadId() && ResumeThread( t.m_hndl ) == 0xFFFFFFFF ) + if (!resumeThreadImpl(t)) { - if ( !t.isRunning ) + if (t.isRunning) + onThreadError( "Unable to resume thread" ); + else { Thread.remove( t ); return; } - onThreadError( "Unable to resume thread" ); } + } + + storeStackAndRegInfo(t, sameThread); +} +private void storeStackAndRegInfo(Thread t, const bool sameThread) nothrow @nogc +{ + version (Windows) + { if ( !t.m_lock ) t.m_curr.tstack = t.m_curr.bstack; t.m_reg[0 .. $] = 0; } else version (Darwin) { - if ( t.m_addr != pthread_self() && thread_resume( t.m_tmach ) != KERN_SUCCESS ) - { - if ( !t.isRunning ) - { - Thread.remove( t ); - return; - } - onThreadError( "Unable to resume thread" ); - } - if ( !t.m_lock ) t.m_curr.tstack = t.m_curr.bstack; t.m_reg[0 .. $] = 0; } else version (Solaris) { - if (t.m_addr != pthread_self() && thr_continue(t.m_addr) != 0) - { - if (!t.isRunning) - { - Thread.remove(t); - return; - } - onThreadError("Unable to resume thread"); - } - if (!t.m_lock) t.m_curr.tstack = t.m_curr.bstack; t.m_reg[0 .. $] = 0; } else version (Posix) { - if ( t.m_addr != pthread_self() ) - { - if ( pthread_kill( t.m_addr, resumeSignalNumber ) != 0 ) - { - if ( !t.isRunning ) - { - Thread.remove( t ); - return; - } - onThreadError( "Unable to resume thread" ); - } - } - else if ( !t.m_lock ) + if (sameThread && !t.m_lock) { t.m_curr.tstack = t.m_curr.bstack; } From 776b6d4c2b902a2a775c3dce7468d5de7088f258 Mon Sep 17 00:00:00 2001 From: Denis Feklushkin Date: Sat, 4 Jul 2026 22:29:53 +0300 Subject: [PATCH 8/8] wasi: suspend -> resume typo --- druntime/src/core/thread/wasi_impl.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/druntime/src/core/thread/wasi_impl.d b/druntime/src/core/thread/wasi_impl.d index 20294e80e5fa..16ad76ddce26 100644 --- a/druntime/src/core/thread/wasi_impl.d +++ b/druntime/src/core/thread/wasi_impl.d @@ -173,6 +173,6 @@ package bool suspendThreadImpl(Thread t) @nogc nothrow // Returns true on success package bool resumeThreadImpl(Thread t) @nogc nothrow { - onThreadError( "Unable to suspend thread" ); + onThreadError( "Unable to resume thread" ); assert(0); }