Skip to content

Suppress wake-up preemption on Linux in LowLevelLifoSemaphore (parallel to Windows SetThreadPriorityBoost) - #129395

Draft
VSadov with Copilot wants to merge 5 commits into
mainfrom
copilot/implement-suppress-wakeup-preemption
Draft

Suppress wake-up preemption on Linux in LowLevelLifoSemaphore (parallel to Windows SetThreadPriorityBoost)#129395
VSadov with Copilot wants to merge 5 commits into
mainfrom
copilot/implement-suppress-wakeup-preemption

Conversation

CopilotAI commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Note

AI-generated draft.

This change implements the Linux counterpart to the existing Windows wake-preemption suppression used around LowLevelLifoSemaphore.Block. The goal is the same on both platforms: a worker waking from park should rejoin queue processing without receiving a transient wake-up scheduling advantage over already-running workers.

  • LowLevelLifoSemaphore integration

    • Replaced the Windows-only SetThreadPriorityBoost block in Block with platform-agnostic SuppressWakePreemption() / RestoreWakePreemption(...) helpers.
    • Kept suppression scoped exactly to the _blocker.TimedWait(...) window.
  • Linux wake-preemption mechanism (System.Native)

    • Added SystemNative_SuppressWakePreemption() — sets the calling thread to SCHED_BATCH before the wait.
    • Added SystemNative_RestoreWakePreemption() — restores the thread to the default SCHED_OTHER (priority 0) after the wait.
    • Both functions are parameterless; no previous state is captured or restored. Threadpool threads are expected to run at default scheduler settings, and reverting to defaults is the correct behavior even if a user changed the thread's scheduler settings.
    • Non-Linux Unix targets compile the functions as no-ops.
  • Managed interop and wrapper

    • Added Unix interop surface: Interop.WakePreemption.cs.
    • Added LowLevelLifoSemaphore.WakePreemption.cs with WakePreemptionScope:
      • Windows: wraps SetThreadPriorityBoost(true/false).
      • Linux: sets SCHED_BATCH on suppress and restores SCHED_OTHER on restore; WakePreemptionScope carries a single bool Suppressed field.
      • Other platforms: no-op.
    • Added Debug.Assert on the return values of both SuppressWakePreemption and RestoreWakePreemption interop calls to catch unexpected syscall failures in debug builds. Failures are otherwise ignored as benign.
  • Entry point and project plumbing

    • Registered new native exports in entrypoints.c (unconditional).
    • Wired new interop and wrapper source files into System.Private.CoreLib.Shared.projitems.
if(blockerNode!=null){WakePreemptionScopewakePreemptionScope=SuppressWakePreemption();try{while(!blockerNode._blocker.TimedWait(timeoutMs)){if(TryRemove(blockerNode))returnfalse;timeoutMs=10;}}finally{RestoreWakePreemption(wakePreemptionScope);}}

@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.

CopilotAI requested review from Copilot and removed request for CopilotJune 14, 2026 18:16
CopilotAI changed the title [WIP] Implement per-thread suppress wake-up preemption mechanism on LinuxSuppress wake-up preemption on Linux in LowLevelLifoSemaphore (parallel to Windows SetThreadPriorityBoost)Jun 14, 2026
CopilotAI requested a review from VSadovJune 14, 2026 18:24
@VSadov
VSadov requested a review from CopilotJune 14, 2026 18:49

CopilotAI 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 extends LowLevelLifoSemaphore.Block to suppress OS “wakeup advantage” during the blocking wait window, generalizing the existing Windows behavior (priority-boost suppression) and adding a Unix/Linux-native mechanism via System.Native.

Changes:

  • Added SystemNative_SuppressWakePreemption / SystemNative_RestoreWakePreemption to System.Native and wired them into entrypoints.c.
  • Introduced Unix interop (Interop.WakePreemption.cs) and a managed wrapper (LowLevelLifoSemaphore.WakePreemption.cs) to scope suppression/restoration.
  • Updated LowLevelLifoSemaphore.Block to use the new platform-agnostic suppression helpers instead of Windows-only SetThreadPriorityBoost directly.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 8 comments.

Show a summary per file
FileDescription
src/native/libs/System.Native/pal_threading.hDeclares new wake-preemption suppression/restoration exports.
src/native/libs/System.Native/pal_threading.cImplements suppression/restoration (Linux uses sched_*; other targets are stubbed).
src/native/libs/System.Native/entrypoints.cRegisters new exports in the System.Native entrypoint table.
src/libraries/Common/src/Interop/Unix/System.Native/Interop.WakePreemption.csAdds LibraryImport declarations for the new System.Native APIs.
src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelLifoSemaphore.WakePreemption.csAdds managed WakePreemptionScope + suppress/restore helpers (Windows/Linux/no-op).
src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelLifoSemaphore.csUses the new suppression scope around _blocker.TimedWait(...) and updates the explanatory comment.
src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitemsWires the new interop + managed helper file into the build.

Comment threadsrc/native/libs/System.Native/entrypoints.c
Comment threadsrc/native/libs/System.Native/pal_threading.c
Comment threadsrc/native/libs/System.Native/pal_threading.c
@VSadov
VSadovforce-pushed the copilot/implement-suppress-wakeup-preemption branch from 5a789aa to ffb920aCompareJuly 27, 2026 15:53
CopilotAI review requested due to automatic review settings July 27, 2026 15:53

CopilotAI 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 7 out of 7 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

src/native/libs/System.Native/entrypoints.c:262

  • SystemNative_SuppressWakePreemption / SystemNative_RestoreWakePreemption are added to the s_sysNative entrypoint table unconditionally, but pal_threading_wasi.c (used for WASI per System.Native/CMakeLists.txt) does not define these functions. Because DllImportEntry takes the address of the symbol, this will cause a link failure for WASI static builds. The simplest fix is to put these entries under the existing #if !defined(TARGET_WASI) guard with the futex entries.
 DllImportEntry(SystemNative_LowLevelFutex_WakeByAddressSingle)
#endif
DllImportEntry(SystemNative_SuppressWakePreemption)
DllImportEntry(SystemNative_RestoreWakePreemption)
DllImportEntry(SystemNative_LoadLibrary)

@VSadov

Copy link
Copy Markdown
Member

@copilot there are failures on musl. Can that be fixed?

CopilotAI review requested due to automatic review settings August 6, 2026 23:40

CopilotAI commented Aug 6, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot there are failures on musl. Can that be fixed?

Fixed in 7aac3f78.

The musl failures were due to debug assert aborts when sched_setscheduler returned ENOSYS. I updated SuppressWakePreemption assert logic to treat ENOSYS as an expected non-asserting outcome while still asserting on other unexpected errors.

CopilotAI 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 7 out of 7 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/native/libs/System.Native/entrypoints.c:262

  • These new DllImportEntry(SystemNative_SuppressWakePreemption) / ...RestoreWakePreemption entries are unconditionally taking the address of the symbols (see minipal/entrypoints.h), but the WASI build uses pal_threading_wasi.c (CMakeLists.txt) which does not define these functions. This will cause undefined-symbol link failures for WASI static builds unless the entries are guarded out (similar to the futex entries) or WASI stubs are added.
#if !defined(TARGET_WASI)
DllImportEntry(SystemNative_LowLevelFutex_WaitOnAddress)
DllImportEntry(SystemNative_LowLevelFutex_WaitOnAddressTimeout)
DllImportEntry(SystemNative_LowLevelFutex_WakeByAddressSingle)
#endif
DllImportEntry(SystemNative_SuppressWakePreemption)
DllImportEntry(SystemNative_RestoreWakePreemption)
DllImportEntry(SystemNative_LoadLibrary)

@VSadov

Copy link
Copy Markdown
Member

@copilot i think we do not want to exclude musl. Can we bypass libc and do syscall directly?

CopilotAI review requested due to automatic review settings August 7, 2026 01:37

CopilotAI commented Aug 7, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot i think we do not want to exclude musl. Can we bypass libc and do syscall directly?

Yes — done in 47a711eb.

musl deliberately stubs sched_setscheduler to always fail with ENOSYS (it doesn't implement the POSIX process-wide semantics). The kernel interface, however, is per-thread, which is exactly what we want here, so the native helper now issues syscall(SYS_sched_setscheduler, 0, policy, &param) directly with a local struct matching the kernel's single-member sched_param. SCHED_BATCH is also defined locally if the libc headers don't provide it.

With that, musl behaves the same as glibc, so I removed the ENOSYS exemption from the Debug.Assert — any failure now asserts.

Verified locally: the direct syscall succeeds for both SCHED_BATCH and SCHED_OTHER, and native libs + CoreLib build clean.

Note

This comment was generated by GitHub Copilot.

CopilotAI 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 7 out of 7 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/native/libs/System.Native/entrypoints.c:261

  • SystemNative_SuppressWakePreemption / SystemNative_RestoreWakePreemption are exported unconditionally, but System.Native uses pal_threading_wasi.c for WASI builds (see src/native/libs/System.Native/CMakeLists.txt), and that file does not define these symbols. This will cause a WASI link failure similar to why futex exports are guarded out for TARGET_WASI.
 DllImportEntry(SystemNative_LowLevelFutex_WakeByAddressSingle)
#endif
DllImportEntry(SystemNative_SuppressWakePreemption)
DllImportEntry(SystemNative_RestoreWakePreemption)

CopilotAIand others added 5 commits August 30, 2026 17:39
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Sign up for freeto 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

@VSadov