123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- delays - Information on the various kernel delay / sleep mechanisms
- -------------------------------------------------------------------
- This document seeks to answer the common question: "What is the
- RightWay (TM) to insert a delay?"
- This question is most often faced by driver writers who have to
- deal with hardware delays and who may not be the most intimately
- familiar with the inner workings of the Linux Kernel.
- Inserting Delays
- ----------------
- The first, and most important, question you need to ask is "Is my
- code in an atomic context?" This should be followed closely by "Does
- it really need to delay in atomic context?" If so...
- ATOMIC CONTEXT:
- You must use the *delay family of functions. These
- functions use the jiffie estimation of clock speed
- and will busy wait for enough loop cycles to achieve
- the desired delay:
- ndelay(unsigned long nsecs)
- udelay(unsigned long usecs)
- mdelay(unsigned long msecs)
- udelay is the generally preferred API; ndelay-level
- precision may not actually exist on many non-PC devices.
- mdelay is macro wrapper around udelay, to account for
- possible overflow when passing large arguments to udelay.
- In general, use of mdelay is discouraged and code should
- be refactored to allow for the use of msleep.
- NON-ATOMIC CONTEXT:
- You should use the *sleep[_range] family of functions.
- There are a few more options here, while any of them may
- work correctly, using the "right" sleep function will
- help the scheduler, power management, and just make your
- driver better :)
- -- Backed by busy-wait loop:
- udelay(unsigned long usecs)
- -- Backed by hrtimers:
- usleep_range(unsigned long min, unsigned long max)
- -- Backed by jiffies / legacy_timers
- msleep(unsigned long msecs)
- msleep_interruptible(unsigned long msecs)
- Unlike the *delay family, the underlying mechanism
- driving each of these calls varies, thus there are
- quirks you should be aware of.
- SLEEPING FOR "A FEW" USECS ( < ~10us? ):
- * Use udelay
- - Why not usleep?
- On slower systems, (embedded, OR perhaps a speed-
- stepped PC!) the overhead of setting up the hrtimers
- for usleep *may* not be worth it. Such an evaluation
- will obviously depend on your specific situation, but
- it is something to be aware of.
- SLEEPING FOR ~USECS OR SMALL MSECS ( 10us - 20ms):
- * Use usleep_range
- - Why not msleep for (1ms - 20ms)?
- Explained originally here:
- http://lkml.org/lkml/2007/8/3/250
- msleep(1~20) may not do what the caller intends, and
- will often sleep longer (~20 ms actual sleep for any
- value given in the 1~20ms range). In many cases this
- is not the desired behavior.
- - Why is there no "usleep" / What is a good range?
- Since usleep_range is built on top of hrtimers, the
- wakeup will be very precise (ish), thus a simple
- usleep function would likely introduce a large number
- of undesired interrupts.
- With the introduction of a range, the scheduler is
- free to coalesce your wakeup with any other wakeup
- that may have happened for other reasons, or at the
- worst case, fire an interrupt for your upper bound.
- The larger a range you supply, the greater a chance
- that you will not trigger an interrupt; this should
- be balanced with what is an acceptable upper bound on
- delay / performance for your specific code path. Exact
- tolerances here are very situation specific, thus it
- is left to the caller to determine a reasonable range.
- SLEEPING FOR LARGER MSECS ( 10ms+ )
- * Use msleep or possibly msleep_interruptible
- - What's the difference?
- msleep sets the current task to TASK_UNINTERRUPTIBLE
- whereas msleep_interruptible sets the current task to
- TASK_INTERRUPTIBLE before scheduling the sleep. In
- short, the difference is whether the sleep can be ended
- early by a signal. In general, just use msleep unless
- you know you have a need for the interruptible variant.
|