Linux wakeup_count Handshakes: Detect a New Event Between Userspace Policy and Suspend
Use the Linux wakeup_count handshake to detect when a userspace sleep decision became stale before system suspend. Read a count, evaluate and prepare the policy decision, then write back that same count. If the write fails, do not request sleep on the old decision. If it succeeds, the kernel checks for newly reported wakeup events during the subsequent transition.
Applicability: this article pins the sysfs ABI and implementation to Linux v6.12. It concerns a single coordinated userspace suspend policy using /sys/power/wakeup_count and the supported system-sleep interface. It does not make unreported hardware events visible or establish that a particular platform can wake from every sleep state.

1. Identify the decision the handshake protects
Suppose a hypothetical controller has processed its pending work and is considering system sleep. A new event can arrive after that decision but before tasks are frozen. Without a handshake, the system may go to sleep while the newly arrived work remains unfinished.
The v6.12 system-power ABI defines a global wakeup-event count. A read waits while wakeup events are being processed. A successful write of the observed count enables detection of events that would invalidate the following sleep transition.
This is not the per-device wakeup_count statistic under a device’s power directory. Nor is the number an application queue length. Keep the global handshake value as a token associated with one policy attempt, not as a persistent sequence number or proof that every application subsystem is idle.
2. Preserve the read, policy, write ordering
- Read the global count: require a successful complete read before creating the policy attempt.
- Evaluate current work: inspect the application conditions that determine whether sleep is still wanted and perform the approved preparations.
- Write the original value: use the count read for this attempt, without silently replacing it with a newer one.
- Check the write result: on rejection, abandon this attempt and revisit current work.
- Request the supported sleep state: only after a successful handshake, then inspect the resulting transition outcome.
The ordering is described in the v6.12 sysfs implementation commentary. Reading a new count immediately before writing, while retaining a much older no-work decision, removes the very comparison that should reveal intervening events.
Use one coordinator for the policy and serialize competing requests. Independent programs writing the same global interface can disturb each other’s attempts. A count equality is not an ownership lock for multiple unrelated suspend managers.
3. Distinguish a changed count from an active event
The exact v6.12 pm_save_wakeup_count implementation accepts a value only when it matches the current event count and no wakeup event is in progress. Both conditions matter. A matching number alone is insufficient while a source remains active.
In a hypothetical attempt, userspace reads 40. One new completed event is then registered, making the count 41. Writing 40 is rejected. The correct response is to process or reconsider the new work, not to loop over writes until one happens to succeed.
In another attempt, a wakeup source becomes active before the write. Even if the completed-event count still appears unchanged at that instant, the in-progress condition prevents acceptance. A blocked read or rejected save can therefore be evidence of work still protected by a wakeup source, rather than a broken sysfs file.
Keep event-generation evidence separate from the number of count changes. A driver’s wakeup-source reporting policy determines how activity is represented. Do not infer one count increment per packet, button bounce, or physical edge without checking that producer’s contract.
4. Keep protection after a successful save
Now consider a successful save of 40 followed by a newly reported event before or during the sleep transition. The ABI states that this causes the subsequent transition to abort. The save is not a promise that the machine will sleep; it establishes a check against new reported activity.
Record handshake acceptance and suspend outcome as separate events. A rejected transition following an accepted count can be correct behavior. Investigate whether new work arrived before treating every aborted sleep as a power-management failure.
The protection depends on the relevant driver reporting wakeup activity through the framework and on the platform’s supported wake path. A peripheral that never reports its event, or loses it electrically before the host can see it, is outside what a counter comparison can repair.
5. Classify interface errors before retrying
In v6.12, the sysfs store returns -EINVAL for a failed count save or invalid input, and rejects manual count writes with -EBUSY while autosleep is active. The read path can return -EINTR when an interrupted wait leaves events in progress. These implementation details are visible in kernel/power/main.c.
Preserve the operation, return status, original value, and policy-attempt identifier. Do not collapse interrupted reads, rejected writes, unsupported interfaces, and suspend failures into a single “sleep failed” counter. They require different next actions.
If another framework owns autosleep, coordinate with that framework instead of racing it with a second manual policy. If a required interface is unavailable in the target configuration, record the limitation and use the platform’s supported suspend manager; do not pretend a direct state write provides the missing handshake.
6. Test the interleavings deliberately
| Proposed event placement | Expected evidence |
|---|---|
| No event during the attempt | Count save can succeed; other suspend prerequisites still apply. |
| Event between read and save | The stale attempt is rejected or blocked by active-event state. |
| Source remains active during read | The read waits, subject to interruption and error handling. |
| Event after successful save | The subsequent transition detects the new reported activity and aborts. |
| Policy decides to stay awake | No sleep request is issued for that attempt. |
Use an isolated development target and a controlled wakeup-source producer. Record source activation/completion, count read, policy decision, save result, sleep request, and transition outcome on one timeline. A test that only sleeps repeatedly without placing events at the boundaries does not exercise the handshake.
No sysfs write or suspend attempt was performed for this article. The deliverable is a race-focused policy trace showing that stale decisions are discarded and new reported activity remains visible through entry, with unsupported hardware and reporting assumptions stated explicitly.