Skip to content

Simplify CoreCLR Thread interop - #132388

Open
jkotas with Copilot wants to merge 14 commits into
mainfrom
copilot/simplify-thread-functionality
Open

Simplify CoreCLR Thread interop#132388
jkotas with Copilot wants to merge 14 commits into
mainfrom
copilot/simplify-thread-functionality

Conversation

Copilot AI commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Simplifies current-thread QCalls and removes obsolete Thread state and handle-ownership code.

  • Current-thread QCalls
    • SetWaitSleepJoinState, ClearWaitSleepJoinState, and CheckForPendingInterrupt obtain the native thread with GetThread().
  • Handle duplication
    • Throws the Win32 error when ThreadNative_GetOSHandle cannot duplicate a handle.

Related to #107473

Copilot AI and others added 3 commits August 17, 2026 05:15
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Comment thread src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs Outdated
Comment thread src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs Outdated
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @VSadov
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR simplifies CoreCLR thread interop by making several “current thread” QCalls derive the native Thread* via GetThread() instead of marshaling/passing a managed thread handle, while also removing redundant native thread-handle ownership state and tightening error handling when duplicating OS thread handles.

Changes:

  • Update ThreadNative_SetWaitSleepJoinState, ThreadNative_ClearWaitSleepJoinState, and ThreadNative_CheckForPendingInterrupt QCalls to operate on GetThread() (current thread) rather than a passed QCall::ThreadHandle.
  • Remove m_WeOwnThreadHandle and corresponding conditional handle-close logic, assuming installed thread handles are always owned by the runtime.
  • Make ThreadNative_GetOSHandle throw a Win32 exception when DuplicateHandle fails, instead of silently returning INVALID_HANDLE_VALUE.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/coreclr/vm/threads.h Removes m_WeOwnThreadHandle and leaves thread-handle state tracking in the Thread type.
src/coreclr/vm/threads.cpp Removes ownership-flag initialization/usage and makes handle-close paths unconditional for installed handles.
src/coreclr/vm/comsynchronizable.h Updates QCall declarations to remove thread-handle parameters for current-thread operations.
src/coreclr/vm/comsynchronizable.cpp Implements current-thread QCalls via GetThread() and adds failure handling for DuplicateHandle.
src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs Adjusts managed QCall signatures/call sites to match the new native current-thread QCall shapes and removes unused managed state.
Suppressed comments (1)

src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs:331

  • GC.KeepAlive(this) is now redundant: ClearWaitSleepJoinStateNative no longer uses the managed Thread instance (it operates on the current native Thread via GetThread()). Removing the KeepAlive avoids an extra call on a hot wait/sleep/join path and makes the intent clearer.
            ClearWaitSleepJoinStateNative();
            GC.KeepAlive(this);

Comment thread src/coreclr/vm/threads.h Outdated
Comment thread src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 17, 2026 06:03
Copilot AI requested a review from jkotas August 17, 2026 06:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/coreclr/vm/threads.h:2601

  • The comment for m_ThreadHandleForClose still describes conditional handle ownership ("may need to be closed if we are the owner"), but handle ownership tracking was removed in this change. Updating the comment avoids misleading future maintainers about when the handle is closed.
    // <TODO> It would be nice to remove m_ThreadHandleForClose to simplify Thread.Join,
    //   but at the moment that isn't possible without extensive work.
    //   This handle is used by SwitchOut to store the old handle which may need to be closed
    //   if we are the owner.  The handle can't be closed before checking the external count
    //   which we can't do in SwitchOut since that may require locking or switching threads.</TODO>

Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 17, 2026 06:27

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs:337

  • Same issue as above: Interlocked.And can’t operate directly on a NativeThreadState enum field. Reinterpret the enum field as int and pass an int mask so the operation is atomic on the underlying 32-bit state.
            NativeThreadClass* nativeThread = (NativeThreadClass*)GetNativeHandle().Value;
            Interlocked.And(ref nativeThread->m_State, ~NativeThreadState.TS_WaitSleepJoin);

Comment thread src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs Outdated
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 17, 2026 12:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs Outdated
Comment thread src/coreclr/vm/threads.h Outdated
Comment thread src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 17, 2026 16:35
Comment thread src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs Outdated
Comment thread src/coreclr/vm/threads.h Outdated
Comment thread src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs:621

  • NativeThread.m_State is declared as managed System.Threading.ThreadState, but it represents the native Thread::m_State bitfield. This causes a type mismatch with Interlocked.Or/And (which operate on int/uint) and also makes the layout misleading. Represent the field as an int (native state bits) and avoid naming the nested enum ThreadState to prevent confusion with the managed ThreadState enum.
        {
            public ThreadState m_State;

            internal enum ThreadState
            {

src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs:332

  • Similarly, Interlocked.And requires an int mask; apply the bitwise complement to an int value (and reference the renamed native-state enum) so the call compiles and clears the intended native flag.
            NativeThread* nativeThread = GetNativeThreadForCurrentThread();
            Interlocked.And(ref nativeThread->m_State, ~NativeThread.ThreadState.TS_WaitSleepJoin);
        }

Copilot AI review requested due to automatic review settings August 17, 2026 16:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs:324

  • Interlocked.Or/And doesn’t have overloads that accept enum refs, so using it with nativeThread->m_State (currently an enum field) won’t compile. Also, the flag being OR’d is a native Thread::TS_* bit, not System.Threading.ThreadState, so this should operate on an int/uint native state field.
            // It sets the state in the native layer to indicate that the thread is waiting.
            NativeThread* nativeThread = GetNativeThreadForCurrentThread();
            Interlocked.Or(ref nativeThread->m_State, NativeThread.ThreadState.TS_WaitSleepJoin);
        }

src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs:619

  • NativeThread is meant to overlay the beginning of the native Thread object (Thread::m_State is a native bitfield). Declaring m_State as System.Threading.ThreadState is misleading and also prevents using Interlocked correctly. Use an integral field for the native state and give the nested enum a distinct name to avoid confusion with managed ThreadState.
        [StructLayout(LayoutKind.Sequential)]
        private struct NativeThread
        {
            public ThreadState m_State;

Copilot AI review requested due to automatic review settings August 17, 2026 17:58
@jkotas
jkotas marked this pull request as ready for review August 17, 2026 17:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs:622

  • The nested enum name ThreadState inside NativeThread is easy to confuse with System.Threading.ThreadState used throughout this file. Renaming it (and optionally marking it [Flags]) would make it clearer that these are native Thread::m_State bits, not the managed thread state enum.
            public ThreadState m_State;

            internal enum ThreadState
            {
                TS_WaitSleepJoin = 0x02000000, // Thread is waiting, sleeping or joining

src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs:331

  • If the nested enum is renamed (e.g. to NativeThreadState), update this reference accordingly to avoid ambiguity with System.Threading.ThreadState.
            Interlocked.And(ref nativeThread->m_State, ~NativeThread.ThreadState.TS_WaitSleepJoin);

src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs:323

  • If the nested enum is renamed (e.g. to NativeThreadState), update this reference accordingly to avoid ambiguity with System.Threading.ThreadState.

This issue also appears in the following locations of the same file:

  • line 331
  • line 618
            Interlocked.Or(ref nativeThread->m_State, NativeThread.ThreadState.TS_WaitSleepJoin);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants