mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 13:51:44 +00:00
05a5f51ca5
Replace the lkml.org links with lore to better use a single source that's more likely to stay available long-term. Done by bash script: cvt_lkml_to_lore () { tmpfile=$(mktemp ./.cvt_links.XXXXXXX) header=$(echo $1 | sed 's@/lkml/@/lkml/headers/@') wget -qO - $header > $tmpfile if [[ $? == 0 ]] ; then link=$(grep -i '^Message-Id:' $tmpfile | head -1 | \ sed -r -e 's/^\s*Message-Id:\s*<\s*//' -e 's/\s*>\s*$//' -e 's@^@https://lore.kernel.org/r/@') # echo "testlink: $link" if [ -n "$link" ] ; then wget -qO - $link > /dev/null if [[ $? == 0 ]] ; then echo $link fi fi fi rm -f $tmpfile } git grep -P -o "\bhttps?://(?:www.)?lkml.org/lkml[\/\w]+" $@ | while read line ; do echo $line file=$(echo $line | cut -f1 -d':') link=$(echo $line | cut -f2- -d':') newlink=$(cvt_lkml_to_lore $link) if [[ -n "$newlink" ]] ; then sed -i -e "s#\b$link\b#$newlink#" $file fi done Link: https://lore.kernel.org/patchwork/patch/1265849/#1462688 Signed-off-by: Joe Perches <joe@perches.com> Link: https://lore.kernel.org/r/77cdb7f32cfb087955bfc3600b86c40bed5d4104.camel@perches.com Signed-off-by: Jonathan Corbet <corbet@lwn.net>
116 lines
4.0 KiB
ReStructuredText
116 lines
4.0 KiB
ReStructuredText
===================================================================
|
|
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:
|
|
https://lore.kernel.org/r/15327.1186166232@lwn.net
|
|
|
|
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.
|
|
|
|
FLEXIBLE SLEEPING (any delay, uninterruptible)
|
|
* Use fsleep
|