Linux Timer Slack: Find the Per-Thread Coalescing Policy Behind a Late Wait

Two ordinary Linux threads can request the same timed wait yet have different coalescing allowances. Timer slack belongs to the calling thread, and a newly created thread takes its initial slack policy from its creator. A launcher that changes that policy before creating workers can therefore influence waits far from the configuration code.

This review uses the Linux man-pages 6.19 PR_SET_TIMERSLACK contract, read on 2026-10-19. It concerns ordinary non-real-time reporting threads. No scheduling policy, process setting or target timer was changed.

Separate allowance from observed latency

Timer slack permits the kernel to group nearby timer expirations, potentially reducing wake-ups. It allows affected expirations to occur late by the configured slack, not early. That allowance is only one contributor to when application code resumes.

Consider a synthetic timed wait with an intended expiration at 100 ms and a current slack of 5 ms. Coalescing may move the expiration within the additional allowance. If the thread actually resumes at 108 ms, the trace cannot attribute all eight milliseconds to a five-millisecond slack policy. Scheduling delay or other interference needs separate evidence.

Likewise, resuming near 100 ms does not prove slack is zero. The allowance need not be fully used on every wait. Keep intended timeout, timer expiration and thread execution as separate events when interpreting a trace.

Worker A inherits five milliseconds of current and default slack; worker B created later inherits fifty microseconds, and resetting A restores its own original default.
Original thread-inheritance diagram; no latency or power benchmark.

Read current and default as different values

The API maintains a current slack and a default slack for each thread. A positive argument sets the current value in nanoseconds. Passing zero restores the thread’s default; it does not request zero nanoseconds of slack.

These illustrative calls show the argument units and types, not a tuning recommendation:

prctl(PR_SET_TIMERSLACK, 5000000UL, 0UL, 0UL, 0UL);
/* Current slack is requested as 5 ms; check the return value. */
prctl(PR_SET_TIMERSLACK, 0UL, 0UL, 0UL, 0UL);
/* Restore this thread's default, which need not be 5 ms. */

An implementation must use the appropriate headers, check errors and record the thread to which the operation applies. Executing a configuration helper in another thread does not automatically set the waiting worker’s current value.

The default is not a mutable application-wide baseline. A design that needs a particular worker policy should establish it deliberately in that worker’s lifecycle rather than assume that a reset call means the same number everywhere.

Follow the creation-time inheritance

For a concrete source-derived fixture, suppose a creator’s known current slack is initially 50,000 ns. It changes current slack to 5,000,000 ns and creates worker A. Both A’s current and default values begin at 5,000,000 ns.

The creator then restores its own known 50,000 ns policy and creates worker B. B begins with that smaller current and default value. Changing the creator later does not retroactively rewrite the already-created A’s policy.

If A temporarily changes its current value and then calls the zero reset form, it returns to its own inherited 5,000,000 ns default. It does not discover the creator’s later value. This is why a reset in a library worker can preserve a surprisingly large allowance.

The manual also documents inheritance across fork() and preservation across execve(). Review process launchers and thread pools as part of the policy chain, rather than limiting the search to the function performing the late wait. The values above are synthetic inputs, not measurements or a claim that every deployed service starts with the same default.

Confirm that the wait is in scope

The documented affected interfaces include the select and poll families, epoll_wait, epoll_pwait, nanosleep, clock_nanosleep, and futex-based timed waits. The latter category includes documented pthread timed synchronization operations.

Do not infer that every Linux timer mechanism receives this allowance. Identify the actual wait implementation used by the library and platform. A device interrupt, a periodic timer object and a blocking wait timeout are not interchangeable evidence simply because all appear in a timing log.

The manual excludes threads scheduled under a real-time policy from timer-slack application. That exception is a scope boundary, not a recommendation to change a product’s scheduling class to solve unexplained lateness.

Compare policies without inventing a guarantee

A proposed controlled experiment would hold the timeout, workload and scheduling class constant while recording the waiting thread’s slack and creation history. Compare distributions over repeated runs and retain the actual thread-resume timestamps. Separate interruption or early readiness from timeout expiry.

Any power-saving claim would require its own measurement. Any maximum response-time claim would require a broader analysis of scheduling and interference. Reducing slack alone cannot certify a hard deadline.

The useful diagnostic result is a per-thread policy map explaining how each worker obtained its current and default values. It can reveal a hidden coalescing allowance without turning that allowance into a universal explanation for every late wake-up.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *