Skip to content

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

Draft
Copilot wants to merge 4 commits into
mainfrom
copilot/implement-suppress-wakeup-preemption
Draft

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

Conversation

Copilot AI 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)
{
    WakePreemptionScope wakePreemptionScope = SuppressWakePreemption();
    try
    {
        while (!blockerNode._blocker.TimedWait(timeoutMs))
        {
            if (TryRemove(blockerNode))
                return false;

            timeoutMs = 10;
        }
    }
    finally
    {
        RestoreWakePreemption(wakePreemptionScope);
    }
}

Copilot AI requested review from Copilot and removed request for Copilot June 14, 2026 17:38
@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.

Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot June 14, 2026 18:16
Copilot AI changed the title [WIP] Implement per-thread suppress wake-up preemption mechanism on Linux Suppress wake-up preemption on Linux in LowLevelLifoSemaphore (parallel to Windows SetThreadPriorityBoost) Jun 14, 2026
Copilot AI requested a review from VSadov June 14, 2026 18:24
@VSadov VSadov requested a review from Copilot June 14, 2026 18:49

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 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
File Description
src/native/libs/System.Native/pal_threading.h Declares new wake-preemption suppression/restoration exports.
src/native/libs/System.Native/pal_threading.c Implements suppression/restoration (Linux uses sched_*; other targets are stubbed).
src/native/libs/System.Native/entrypoints.c Registers new exports in the System.Native entrypoint table.
src/libraries/Common/src/Interop/Unix/System.Native/Interop.WakePreemption.cs Adds LibraryImport declarations for the new System.Native APIs.
src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelLifoSemaphore.WakePreemption.cs Adds managed WakePreemptionScope + suppress/restore helpers (Windows/Linux/no-op).
src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelLifoSemaphore.cs Uses the new suppression scope around _blocker.TimedWait(...) and updates the explanatory comment.
src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems Wires the new interop + managed helper file into the build.

Comment thread src/native/libs/System.Native/entrypoints.c
Comment thread src/native/libs/System.Native/pal_threading.c
Comment thread src/native/libs/System.Native/pal_threading.c
Comment on lines +325 to +329
// A transient wake-up advantage provides no benefit here and can result in
// the woken thread preempting already-working threads. On Windows this
// disables SetThreadPriorityBoost. On Linux this temporarily switches the
// thread to SCHED_BATCH, which sched(7) documents as applying "a small
// scheduling penalty with respect to wakeup behavior".
// disables SetThreadPriorityBoost. On Linux this temporarily switches the
// thread to SCHED_BATCH, which sched(7) documents as applying "a small
// scheduling penalty with respect to wakeup behavior".
WakePreemptionScope wakePreemptionScope = SuppressWakePreemption();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These are threadpool threads under control of the runtime. We do not need to optimize/anticipate cases where these syscalls do not work since not working is both unexpected and benign.

@copilot Add an assert to make sure that the syscalls work in common/typical scenarios.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added Debug.Assert(result == 0, ...) after each call to SuppressWakePreemption and RestoreWakePreemption in LowLevelLifoSemaphore.WakePreemption.cs. These will fire in debug builds if either syscall unexpectedly fails. Commit: 6ed4b5d.

{
internal sealed partial class LowLevelLifoSemaphore
{
private readonly struct WakePreemptionScope

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@copilot these are threadpool threads. The user is not expected to change varioaus parameters like scheduler or priority from defaults. Even if user does so, it would be ok and perhaps even a mildly good thing if suppressing/restoring would revert thread state to defaults.

I do not think we need to capture and revert to the original state. We should revert to default.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Simplified as requested. RestoreWakePreemption now unconditionally sets SCHED_OTHER (priority 0) instead of capturing and restoring the previous state. The native API is now parameterless — suppress sets SCHED_BATCH, restore sets SCHED_OTHER. WakePreemptionScope on Linux carries only a bool Suppressed to guard the restore call. Commit: b7de4e3.

Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Co-authored-by: VSadov <8218165+VSadov@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot June 15, 2026 01:29
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