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

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.

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 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
@VSadov
VSadov force-pushed the copilot/implement-suppress-wakeup-preemption branch from 5a789aa to ffb920a Compare July 27, 2026 15:53
Copilot AI review requested due to automatic review settings July 27, 2026 15:53

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

VSadov commented Aug 6, 2026

Copy link
Copy Markdown
Member

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

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

Copilot AI commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

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

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

VSadov commented Aug 7, 2026

Copy link
Copy Markdown
Member

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

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

Copilot AI commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

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

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 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)
Copilot AI and 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 free to join this conversation on GitHub. Already have an account? Sign in to comment

3 participants