What is Linux Kernel Sleep Functions: msleep, usleep_range & ssleep Explained-Best Linux Device Driver Training Online

← Previous Lecture    Next Lecture →

Linux Kernel Sleep Functions: msleep, usleep_range & ssleep Explained
A Free Linux Kernel Development Course Lecture — Kernel 6.x
15+ min read
Beginner to Intermediate
Kernel 6.x Ready

If you are writing Linux device drivers or kernel modules, sooner or later you will need to pause execution for a short duration without wasting CPU cycles. This is exactly what Linux kernel sleep functions are designed for. Unlike busy-wait delay routines that keep the CPU spinning, sleep functions such as usleep_range(), msleep(), and ssleep() let the scheduler put your process context to sleep and hand the CPU to other tasks until the timer expires. In this free Linux kernel development course lecture, we break down every commonly used blocking sleep API, explain when to use each one, and update the concepts for modern kernel 6.x systems.

This lecture is part of EmbeddedPathashala’s free Linux device drivers course and free embedded systems course series, where we take real kernel subsystems and turn them into practical, beginner-friendly tutorials.

linux kernel sleep functions msleep vs usleep_range free linux kernel development course free linux device drivers course kernel process context sleep schedule_timeout

What You Will Learn

  • Why blocking sleep functions exist in the Linux kernel
  • How usleep_range() works and why it is the recommended choice
  • The difference between msleep() and msleep_interruptible()
  • When to reach for ssleep()
  • Interruptible vs uninterruptible sleep states
  • Writing your own kernel module that demonstrates safe sleeping
  • Common mistakes, performance, and security considerations

Prerequisites

Before starting this Linux kernel sleep functions tutorial, you should be comfortable with:

  • Basic Linux kernel module structure (module_init / module_exit)
  • Compiling out-of-tree kernel modules with a Makefile
  • The difference between process context and interrupt context
  • A Linux system running kernel 5.15 or later (kernel 6.x recommended)

Why Linux Kernel Sleep Functions Matter

Every driver eventually needs to wait — for hardware to settle, for a sensor to warm up, for a bus transaction to finish. The wrong choice here is expensive: spinning the CPU in a busy loop for tens of milliseconds wastes power and starves other tasks. This is precisely the gap that Linux kernel sleep functions fill. They are only valid in process context, meaning any code path where it is legal to call schedule() and hand off the CPU. Interrupt handlers, spinlock critical sections, and other atomic contexts must never call these functions.

Process Context Sleep — Simplified Flow
1. Driver code → calls msleep(50)
2. Kernel → arms a timer for 50 ms
3. Kernel → marks task TASK_UNINTERRUPTIBLE, calls schedule()
4. Scheduler → runs other runnable tasks
5. Timer fires → task moved back to runnable state
6. Driver code → resumes after ~50 ms

usleep_range() — The Recommended Kernel Sleep Function

usleep_range(min, max) is the go-to Linux kernel sleep function for short delays, typically between 10 microseconds and 20 milliseconds. Instead of asking for an exact duration, you give the scheduler a window — a minimum and a maximum — which lets it coalesce your wakeup with other pending timer events. On modern kernel 6.x systems this range-based approach reduces timer interrupts and measurably improves power efficiency on mobile and embedded SoCs.

#include <linux/delay.h>

static void sensor_settle_delay(void)
{
    /* Wait between 800 and 1200 microseconds while the sensor
     * output stabilizes after a power rail change. */
    usleep_range(800, 1200);
}

The wider the gap between the minimum and maximum, the more freedom the kernel timer subsystem has to batch wakeups. A common rule of thumb: set the maximum to roughly 1.5–2x the minimum unless your hardware demands a tighter tolerance.

msleep() and msleep_interruptible() for Millisecond Delays

msleep(ms) is meant for delays of roughly 10 milliseconds and above where an exact microsecond window is unnecessary. It puts the calling task into an uninterruptible sleep state, meaning no pending signal can wake it early. This is the right behavior when a partially completed hardware sequence must not be abandoned midway.

msleep_interruptible(ms) behaves the same way but allows the sleep to be broken by a signal — useful when your driver exposes a blocking operation to user space that the user might want to cancel with Ctrl+C.

#include <linux/delay.h>

static int flash_erase_wait(void)
{
    /* Datasheet specifies a 25 ms erase pulse; a partial erase
     * would corrupt the sector, so we use the uninterruptible form. */
    msleep(25);
    return 0;
}

static int user_cancellable_wait(void)
{
    /* Allow the operator to abort a long operation with a signal. */
    if (msleep_interruptible(3000)) {
        pr_info("wait interrupted by signal\n");
        return -EINTR;
    }
    return 0;
}

ssleep() for Second-Scale Delays

ssleep(s) is a thin convenience wrapper that simply calls msleep(s * 1000). Reach for it whenever a delay is naturally expressed in whole seconds, such as waiting for a device to complete a self-test after power-up.

#include <linux/delay.h>

static void device_selftest_wait(void)
{
    /* Give the device up to 3 seconds to complete power-on self-test. */
    ssleep(3);
}

Interruptible vs Uninterruptible Sleep: Choosing Correctly

This distinction trips up many beginners writing their first Linux kernel driver. An uninterruptible sleep guarantees your delay runs to completion no matter what signals arrive for the calling process, which is essential when interrupting the operation would leave hardware in an undefined state. An interruptible sleep, by contrast, respects the UNIX philosophy of giving user space control — if the operator wants to abort, the kernel obeys.

APITypical DurationInterruptible?Best Used For
usleep_range()10μs – 20msN/A (non-blocking timer wait)Short hardware settling delays
msleep()≥10msNoDelays that must not be aborted
msleep_interruptible()≥10msYesUser-cancellable waits
ssleep()≥1sNoSecond-scale power-on / self-test waits

Hands-On Example: A Kernel Module Demonstrating Safe Sleep

Below is an original demo module you can build and load yourself. It logs a timestamp before and after each sleep call so you can observe the actual elapsed time on your own machine.

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ktime.h>

static int __init sleep_demo_init(void)
{
    ktime_t start, end;

    pr_info("sleep_demo: module loaded\n");

    start = ktime_get();
    usleep_range(1000, 1500);
    end = ktime_get();
    pr_info("sleep_demo: usleep_range took %lld us\n",
            ktime_to_us(ktime_sub(end, start)));

    start = ktime_get();
    msleep(20);
    end = ktime_get();
    pr_info("sleep_demo: msleep took %lld us\n",
            ktime_to_us(ktime_sub(end, start)));

    return 0;
}

static void __exit sleep_demo_exit(void)
{
    pr_info("sleep_demo: module unloaded\n");
}

module_init(sleep_demo_init);
module_exit(sleep_demo_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("EmbeddedPathashala sleep function demo");

Build it with a standard out-of-tree Makefile and load it with insmod, then inspect the output with:

sudo insmod sleep_demo.ko
dmesg | tail -n 5
sudo rmmod sleep_demo

Common Mistakes When Using Kernel Sleep Functions

  • Calling msleep() or usleep_range() inside a spinlock critical section
  • Calling msleep() or usleep_range() inside an interrupt handler
  • Using msleep() for sub-millisecond delays, which wastes accuracy
  • Using msleep_interruptible() for a sequence that cannot tolerate being aborted midway
  • Forgetting to check the return value of msleep_interruptible()

Best Practices for Linux Kernel Sleep Functions

  • Default to usleep_range() for anything under 20 milliseconds
  • Give usleep_range() a generous max value so the timer subsystem can batch wakeups
  • Use msleep_interruptible() for any operation exposed to user space that should be cancellable
  • Never assume schedule_timeout()-based delays are precise to the microsecond — treat them as a lower bound
  • Document why you chose a particular sleep API in a code comment, especially near hardware timing constraints

Performance Considerations

On modern multi-core systems running kernel 6.x, timer coalescing driven by usleep_range()‘s window argument has a real impact on power consumption, particularly on ARM-based embedded boards and laptops using tickless idle. Every extra timer interrupt wakes the CPU out of a deeper idle state, so batching wakeups across drivers measurably extends battery life on mobile and IoT hardware.

Security Considerations

Sleep functions are rarely a direct attack surface, but incorrect use can create denial-of-service style bugs: an uninterruptible sleep held during a critical resource lock can stall unrelated processes, and an interruptible sleep used where it should not be can let unprivileged user space abort a security-relevant hardware sequence (such as a secure erase) partway through, leaving the device in an inconsistent state.

Summary & Key Takeaways

  • Linux kernel sleep functions must only be called from process context where sleeping is safe
  • usleep_range() is preferred for short delays because it allows timer coalescing
  • msleep() is uninterruptible; msleep_interruptible() can be woken by a signal
  • ssleep() is a simple wrapper for second-scale delays
  • Choosing the right API affects both correctness and system power efficiency

Conclusion

Mastering Linux kernel sleep functions is a small but essential skill on the road to writing production-quality device drivers. Once you understand the trade-off between usleep_range(), msleep(), msleep_interruptible(), and ssleep(), you will naturally write drivers that are both correct and power-efficient. This lecture is one part of EmbeddedPathashala’s free Linux kernel development course, and the next lecture continues building on kernel timing concepts.

Frequently Asked Questions

Q1. What is the difference between udelay() and msleep() in the Linux kernel?
udelay() busy-waits the CPU and can be used in atomic/interrupt context for very short delays, while msleep() and other Linux kernel sleep functions actually put the process to sleep and free the CPU, so they can only be used in process context.

Q2. Can I call usleep_range() inside an interrupt handler?
No. usleep_range() can sleep, and interrupt handlers must never sleep. Use udelay() instead for short delays inside interrupt context.

Q3. Why is usleep_range() recommended over a fixed-duration API for short delays?
Giving the kernel a min/max window lets it align your wakeup with other pending timers, reducing the number of times the CPU exits a low-power idle state.

Q4. What happens if a signal arrives during msleep()?
Nothing — msleep() is uninterruptible, so the sleep runs to completion regardless of pending signals. Use msleep_interruptible() if you want signals to break the sleep early.

Q5. Is ssleep() just msleep() in disguise?
Yes, ssleep(s) is implemented as a wrapper around msleep(s * 1000) and exists purely for readability when a delay is naturally expressed in seconds.

Q6. What underlying mechanism actually puts my task to sleep?
Internally these APIs rely on schedule_timeout(), which arms a kernel timer and then calls schedule() to yield the CPU until that timer fires.

Q7. Are these delays guaranteed to be exact?
No. Because you are yielding the CPU to the scheduler, actual wakeup time depends on system load and can be later than requested, though never earlier.

Q8. Which header do I need to include for these APIs?
Include <linux/delay.h> for usleep_range(), msleep(), msleep_interruptible(), and ssleep().

Continue your journey through EmbeddedPathashala’s free Linux kernel development course and free Linux device drivers course.

Previous Lecture Next Lecture

2 Comments

Leave a Reply

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