Fundamentals 11 min read

Mastering Linux Process Sleep and Wake‑Up: How to Prevent Invalid Wake‑Ups

This article explains how Linux processes transition between running, sleeping, and waking states, describes the two sleep modes (interruptible and uninterruptible), illustrates the problem of invalid wake‑ups with example code, and shows kernel‑level techniques to avoid them safely.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Mastering Linux Process Sleep and Wake‑Up: How to Prevent Invalid Wake‑Ups

1 Linux Process Sleep and Wake‑Up

In Linux, a process that is only waiting for CPU time is called a runnable process and is placed on a run queue with the state flag TASK_RUNNING. When a running process exhausts its time slice, the scheduler removes it from the CPU and selects another runnable process.

A process can also voluntarily give up the CPU by calling the scheduling function schedule(). When the process is rescheduled, it resumes execution at the line following the schedule() call.

Sometimes a process must wait for a specific event (device initialization, I/O completion, timer expiry, etc.). In that case the process is removed from the run queue and placed on a wait queue, entering a sleep state.

Linux defines two sleep states:

TASK_INTERRUPTIBLE : the process sleeps until a condition becomes true, such as a hardware interrupt, resource release, or signal.

TASK_UNINTERRUPTIBLE : similar to interruptible sleep, but signals cannot wake the process; it is used when the process must not be interrupted.

Typical code to put a running process to sleep looks like this:

sleeping_task = current;
set_current_state(TASK_INTERRUPTIBLE);
schedule();
func1();
/* Rest of the code ... */

After the call to wake_up_process(sleeping_task), the sleeping process’s state is set to TASK_RUNNING and the scheduler will place it back on the run queue.

2 Invalid Wake‑Up

An invalid wake‑up occurs when a process checks a condition, finds it true, and then goes to sleep, causing it to remain asleep even though the condition has already been satisfied. This typically happens due to a race condition between condition checking and state change.

Example scenario: Process A checks whether a linked list is empty. If empty, it sleeps. Process B adds a node to the list and calls wake_up_process(). If B wakes A before A has set its state to sleep, the wake‑up is ineffective, and A will later sleep indefinitely.

// Process A
spin_lock(&list_lock);
if (list_empty(&list_head)) {
    spin_unlock(&list_lock);
    set_current_state(TASK_INTERRUPTIBLE);
    schedule();
    spin_lock(&list_lock);
}
// ...
// Process B
spin_lock(&list_lock);
list_add_tail(&list_head, new_node);
spin_unlock(&list_lock);
wake_up_process(processa_task);

3 Avoiding Invalid Wake‑Ups

To prevent invalid wake‑ups, the check of the condition and the transition to the sleep state must be atomic. One common solution is to set the process state to TASK_INTERRUPTIBLE *before* checking the condition, and if the condition is already satisfied, immediately set the state back to TASK_RUNNING before calling schedule().

set_current_state(TASK_INTERRUPTIBLE);
spin_lock(&list_lock);
if (list_empty(&list_head)) {
    spin_unlock(&list_lock);
    schedule();
} else {
    set_current_state(TASK_RUNNING);
    spin_unlock(&list_lock);
}

This guarantees that a wake‑up occurring after the condition check will find the process in a sleepable state and will succeed.

4 Linux Kernel Example

The Linux kernel itself follows this pattern. A typical kernel sleep loop looks like:

DECLARE_WAITQUEUE(wait, current);
add_wait_queue(q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
while (!condition) {
    schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(q, &wait);

In the kernel’s migration thread ( migration_thread), the code is:

// Wait for kthread_stop
set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop()) {
    schedule();
    set_current_state(TASK_INTERRUPTIBLE);
}
__set_current_state(TASK_RUNNING);
return 0;

Here the condition ( kthread_should_stop()) is evaluated only after the process state has been set to TASK_INTERRUPTIBLE, ensuring that any wake‑up before the next schedule() will not be lost.

Conclusion

Preventing invalid wake‑ups in Linux requires setting the process state to a sleep state before checking the condition and restoring it to TASK_RUNNING if the condition is already satisfied. This approach, used throughout the kernel, guarantees that processes do not mistakenly enter sleep when they should remain runnable.

Linux process sleep illustration
Linux process sleep illustration
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Linuxprocess schedulingsleep statewake upinvalid wake-up
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.