Conversation
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: 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. |
|
Tagging subscribers to this area: @JulieLeeMSFT, @VSadov |
There was a problem hiding this comment.
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, andThreadNative_CheckForPendingInterruptQCalls to operate onGetThread()(current thread) rather than a passedQCall::ThreadHandle. - Remove
m_WeOwnThreadHandleand corresponding conditional handle-close logic, assuming installed thread handles are always owned by the runtime. - Make
ThreadNative_GetOSHandlethrow a Win32 exception whenDuplicateHandlefails, instead of silently returningINVALID_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);
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
There was a problem hiding this comment.
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>
There was a problem hiding this comment.
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.Andcan’t operate directly on aNativeThreadStateenum field. Reinterpret the enum field asintand pass anintmask 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);
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
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_Stateis declared as managedSystem.Threading.ThreadState, but it represents the nativeThread::m_Statebitfield. This causes a type mismatch withInterlocked.Or/And(which operate onint/uint) and also makes the layout misleading. Represent the field as anint(native state bits) and avoid naming the nested enumThreadStateto prevent confusion with the managedThreadStateenum.
{
public ThreadState m_State;
internal enum ThreadState
{
src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs:332
- Similarly,
Interlocked.Andrequires anintmask; apply the bitwise complement to anintvalue (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);
}
There was a problem hiding this comment.
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;
There was a problem hiding this comment.
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
ThreadStateinsideNativeThreadis easy to confuse withSystem.Threading.ThreadStateused throughout this file. Renaming it (and optionally marking it[Flags]) would make it clearer that these are nativeThread::m_Statebits, 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 withSystem.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 withSystem.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);
Simplifies current-thread QCalls and removes obsolete Thread state and handle-ownership code.
SetWaitSleepJoinState,ClearWaitSleepJoinState, andCheckForPendingInterruptobtain the native thread withGetThread().ThreadNative_GetOSHandlecannot duplicate a handle.Related to #107473