Repository navigation
Specialize CoreLib synchronization for single-threaded CoreCLR - #135903
Merged
jkoritzinsky merged 11 commits intoOct 27, 2026
Merged
Conversation
Co-authored-by: Copilot App <223556219+Copilot@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. |
Contributor
|
Tagging subscribers to this area: @JulieLeeMSFT, @VSadov |
This was referenced Oct 16, 2026
Closed
jkotas
reviewed
Oct 16, 2026
jkotas
reviewed
Oct 16, 2026
jkotas
reviewed
Oct 16, 2026
Honor positive finite wait and SpinLock timeouts, retain single-threaded Mono guards, restore original timeout assertions, and remove the redundant wait-array helper. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Preserve satisfied and zero-timeout ManualResetEventSlim, SemaphoreSlim, Task and Monitor waits from #135413 in both source partitions. Keep validation, recursion and wait-handle state behavior consistent, and retain the upstream Roslyn workspace test ungates. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use consistent non-Windows Thread wait-info guards, rely on the conditional runtime guard helper, and match the threaded-browser Monitor annotation to the existing reference contract. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
jkotas
reviewed
Oct 19, 2026
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The timing test can fail on Windows, and the finite-timeout compatibility description conflicts with the implementation and tests.
2 open issues
What changed in this PR
Specializes CoreLib synchronization for single-threaded browser/WASI CoreCLR, reducing synchronization state while retaining separate multithreaded implementations.
Changes:
- Splits locks, synchronization primitives, and task waits into threading-specific implementations.
- Adds native finite sleep and stores pending interruptions directly on
Thread. - Adds compatibility tests and updates source selection, native layouts, and Wasm imports.
Builds and tests were not run during this review.
| File | Description |
|---|---|
| src/native/libs/System.Native/pal_time.h | Declares native sleep. |
| src/native/libs/System.Native/pal_time.c | Implements interruption-retrying native sleep. |
| src/native/libs/System.Native/entrypoints.c | Registers sleep entry point. |
| src/libraries/System.Threading/tests/SpinLockTests.cs | Tests ownership and timeout behavior. |
| src/libraries/System.Threading/tests/SemaphoreSlimTests.cs | Tests permits, cancellation, and waits. |
| src/libraries/System.Threading/tests/ReaderWriterLockSlimTests.cs | Tests recursion and ownership counts. |
| src/libraries/System.Threading/tests/MutexTests.cs | Tests named-handle ownership and lifetime. |
| src/libraries/System.Threading/tests/MonitorTests.cs | Tests headers, recursion, and wait validation. |
| src/libraries/System.Threading/tests/ManualResetEventSlimTests.cs | Tests state and blocking restrictions. |
| src/libraries/System.Threading.ThreadPool/tests/RegisteredWaitTests.cs | Tests registration validation. |
| src/libraries/System.Threading.Thread/tests/ThreadTests.cs | Tests sleep and interruption behavior. |
| src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/TaskFactory/TaskFactory_FromAsyncTests.cs | Tests completed and unsupported asynchronous results. |
| src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/Task/TaskArgumentValidationTests.cs | Tests task waits and inline execution. |
| src/libraries/System.Runtime/tests/System.Threading.Tasks.Tests/Task/AsyncEnumerableToBlockingEnumerableTests.cs | Tests deferred enumeration failure. |
| src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Threading/WaitHandleTests.cs | Tests signals, timeouts, and interruptions. |
| src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.MultiThreading.cs | Isolates waiter and ownership machinery. |
| src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.Unix.cs | Delegates multithreaded wait mechanics. |
| src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.WaitableObject.SingleThreading.cs | Adds compact signal and mutex state. |
| src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.Unix.cs | Updates documentation and array cleanup. |
| src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.ThreadWaitInfo.Unix.MultiThreading.cs | Adjusts switch-block formatting. |
| src/libraries/System.Private.CoreLib/src/System/Threading/WaitSubsystem.SingleThreading.cs | Adds single-threaded handles, waits, and sleep. |
| src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs | Removes redundant wrapper guards. |
| src/libraries/System.Private.CoreLib/src/System/Threading/Thread.SingleThreading.cs | Removes empty join notification helper. |
| src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TaskFactory_T.SingleThreading.cs | Rejects unsupported waits before promise creation. |
| src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TaskFactory_T.MultiThreading.cs | Retains multithreaded FromAsync implementation. |
| src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TaskFactory_T.cs | Delegates to threading-specific implementation. |
| src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TaskAsyncEnumerableExtensions.ToBlockingEnumerable.SingleThreading.cs | Defers unsupported enumeration failure. |
| src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TaskAsyncEnumerableExtensions.ToBlockingEnumerable.MultiThreading.cs | Retains blocking iterator implementation. |
| src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TaskAsyncEnumerableExtensions.ToBlockingEnumerable.cs | Shares the public enumeration wrapper. |
| src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.SingleThreading.cs | Specializes task wait paths. |
| src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.MultiThreading.cs | Isolates multithreaded task waits. |
| src/libraries/System.Private.CoreLib/src/System/Threading/SpinLock.SingleThreading.cs | Adds simplified ownership and timeout handling. |
| src/libraries/System.Private.CoreLib/src/System/Threading/SpinLock.MultiThreading.cs | Retains spinning and atomic ownership. |
| src/libraries/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.SingleThreading.cs | Specializes permit and waiter management. |
| src/libraries/System.Private.CoreLib/src/System/Threading/ReaderWriterLockSlim.SingleThreading.cs | Tracks single-threaded recursion counts. |
| src/libraries/System.Private.CoreLib/src/System/Threading/Monitor.SingleThreading.cs | Provides single-threaded wait entry point. |
| src/libraries/System.Private.CoreLib/src/System/Threading/Monitor.MultiThreading.cs | Provides multithreaded wait entry point. |
| src/libraries/System.Private.CoreLib/src/System/Threading/Monitor.cs | Moves wait entry point into variants. |
| src/libraries/System.Private.CoreLib/src/System/Threading/ManualResetEventSlim.SingleThreading.cs | Simplifies event state and waits. |
| src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelLock.SingleThreading.cs | Adds minimal lock state. |
| src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelLock.MultiThreading.cs | Retains atomic locking and blocking. |
| src/libraries/System.Private.CoreLib/src/System/Threading/Lock.SingleThreading.cs | Specializes recursive locking and monitor operations. |
| src/libraries/System.Private.CoreLib/src/System/Threading/Condition.SingleThreading.cs | Delegates condition operations to Lock. |
| src/libraries/System.Private.CoreLib/src/System/Threading/Condition.MultiThreading.cs | Retains condition waiter machinery. |
| src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems | Selects threading-specific shared sources. |
| src/libraries/Common/src/Interop/Unix/System.Native/Interop.ThreadSleep.cs | Adds managed native-sleep import. |
| src/coreclr/vm/wasm/wasi/callhelpers-pinvoke.cpp | Updates WASI static imports. |
| src/coreclr/vm/wasm/browser/callhelpers-pinvoke.cpp | Updates browser static imports. |
| src/coreclr/vm/object.h | Aligns native Thread fields. |
| src/coreclr/vm/corelib.h | Updates field bindings and feature guards. |
| src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj | Selects object-header implementation. |
| src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.SingleThreading.cs | Stores pending interruption directly. |
| src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.Multithreading.cs | Houses multithreaded wait-info access. |
| src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs | Restricts wait fields and exit cleanup. |
| src/coreclr/System.Private.CoreLib/src/System/Threading/ObjectHeader.CoreCLR.SingleThreading.cs | Adds simplified thin-lock operations. |
| src/coreclr/System.Private.CoreLib/src/System/Threading/ObjectHeader.CoreCLR.MultiThreading.cs | Retains atomic thin-lock operations. |
| src/coreclr/System.Private.CoreLib/src/System/Threading/ObjectHeader.CoreCLR.cs | Keeps shared object-header functionality. |
| src/coreclr/System.Private.CoreLib/src/System/Threading/ManagedThreadId.CoreCLR.cs | Names the single-thread ID constant. |
Review effort: Balanced
Use the shared single-threaded Task implementation for Mono builds without multithreading and remove the unreachable fallback branches from Task.MultiThreading.cs. Enable the existing single-threaded Task contract tests on Mono. Restore the semaphore blocking-path guard and restrict the SpinLock timeout timing test to single-threaded CoreCLR. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
jkotas
reviewed
Oct 22, 2026
pavelsavara
reviewed
Oct 22, 2026
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
jkotas
reviewed
Oct 22, 2026
pavelsavara
reviewed
Oct 23, 2026
Member
|
NAOT doesn't compile here. Overall LGTM |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Regenerate WASI call helpers from the merged Release framework to retain upstream compression imports and specialized single-threaded waits. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
jkotas
approved these changes
Oct 27, 2026
Member
Author
|
/ba-g failures are in #136534 |
jkoritzinsky
deleted the
dev/jkoritzinsky/single-threaded-synchronization
branch
October 27, 2026 18:32
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

True single-threaded CoreCLR platforms still carry synchronization machinery designed for competing threads, even when a blocking wait cannot make progress. This specializes those paths for browser/WASI while retaining the existing implementations for multithreaded configurations and Mono.
Approach
.SingleThreading.csand.MultiThreading.csfiles, keeping common API wrappers shared. This covers object-header locks,Lock,Condition, low-level locks, slim primitives,SpinLock, and task blocking paths.Thread, removing the single-threadedThreadWaitInfotype and allocation. Update the native Thread layout, binder checks, source selection, and Wasm static imports accordingly.TaskFactory.FromAsyncwaits before allocating/attaching a promise, avoiding an orphanedAttachedToParentchild when the operation throws.Behavior and compatibility
Already-satisfied and zero-timeout wait-handle operations retain signal consumption, recursive ownership, validation, and interruption behavior. Unsatisfied wait-handle operations with positive finite timeouts sleep for the requested timeout and then return the normal timeout result. Contended anonymous
SpinLock.TryEntercalls with positive finite timeouts likewise sleep and return without acquiring the lock. These finite delays are supported for compatibility and do not pump the managed event loop.Unsatisfied infinite wait-handle operations, infinite sleep, and contended anonymous
SpinLockacquisitions with infinite timeouts throwPlatformNotSupportedExceptionrather than entering waits or spin loops that cannot make progress. These are intentional behavioral changes that need breaking-change documentation.Finite
Thread.Sleepand self-Thread.Joindelays remain supported through nativenanosleep, without a monitor or managed event-loop pumping. Task inline execution and blocking-enumeration deferred failure are preserved. Shared multithreading implementations retain the guards needed by single-threaded Mono and threaded-Wasm JS-interop restrictions. No public API signatures or Mono-only sources change.Validation
Local validation was performed during implementation; it was not rerun after the final manual review edits.
--rsp-quoting=windows; no publisher changes are included.ReadyToRun CoreLib size
Compared PR head
ece2693fe1213a604e59f8f105ccd8eb0e8666b5against691418a89493b63a87f3a19862ec573b2cc3eb96, found usinggit merge-base HEAD origin/mainafter fetchingorigin/main.Measured the full, untrimmed browser-wasm Release
System.Private.CoreLib.wasm. The verified clean merge-base artifact was reused and the final PR head was freshly rebuilt with unchanged compiler sources and build configuration.Both Brotli measurements use
.NET BrotliStreamwithCompressionLevel.SmallestSize. This measures R2R CoreLib alone, including its embedded IL; it excludesdotnet.native.wasmand is not a final trimmed-application download-size measurement.Development measurements
Single-threaded WASI managed allocation measurements:
Desktop BenchmarkDotNet comparisons retained the same allocations for completed APM calls (256 B) and blocking enumeration (80 B). Small timing differences reversed on repeat; normalized non-tiered WaitAll/iterator instructions were identical. These are development measurements, not a final application-download-size or Wasm-throughput claim.
Note
This description and portions of the implementation were generated with GitHub Copilot and reviewed and adjusted by the author.