122 lines
3.4 KiB
ReStructuredText
122 lines
3.4 KiB
ReStructuredText
.. SPDX-License-Identifier: GPL-2.0
|
|
|
|
Delay and 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.
|
|
|
|
The following table gives a rough overview about the existing function
|
|
'families' and their limitations. This overview table does not replace the
|
|
reading of the function description before usage!
|
|
|
|
.. list-table::
|
|
:widths: 20 20 20 20 20
|
|
:header-rows: 2
|
|
|
|
* -
|
|
- `*delay()`
|
|
- `usleep_range*()`
|
|
- `*sleep()`
|
|
- `fsleep()`
|
|
* -
|
|
- busy-wait loop
|
|
- hrtimers based
|
|
- timer list timers based
|
|
- combines the others
|
|
* - Usage in atomic Context
|
|
- yes
|
|
- no
|
|
- no
|
|
- no
|
|
* - precise on "short intervals"
|
|
- yes
|
|
- yes
|
|
- depends
|
|
- yes
|
|
* - precise on "long intervals"
|
|
- Do not use!
|
|
- yes
|
|
- max 12.5% slack
|
|
- yes
|
|
* - interruptible variant
|
|
- no
|
|
- yes
|
|
- yes
|
|
- no
|
|
|
|
A generic advice for non atomic contexts could be:
|
|
|
|
#. Use `fsleep()` whenever unsure (as it combines all the advantages of the
|
|
others)
|
|
#. Use `*sleep()` whenever possible
|
|
#. Use `usleep_range*()` whenever accuracy of `*sleep()` is not sufficient
|
|
#. Use `*delay()` for very, very short delays
|
|
|
|
Find some more detailed information about the function 'families' in the next
|
|
sections.
|
|
|
|
`*delay()` family of functions
|
|
------------------------------
|
|
|
|
These functions use the jiffy estimation of clock speed and will busy wait for
|
|
enough loop cycles to achieve the desired delay. udelay() is the basic
|
|
implementation and ndelay() as well as mdelay() are variants.
|
|
|
|
These functions are mainly used to add a delay in atomic context. Please make
|
|
sure to ask yourself before adding a delay in atomic context: Is this really
|
|
required?
|
|
|
|
.. kernel-doc:: include/asm-generic/delay.h
|
|
:identifiers: udelay ndelay
|
|
|
|
.. kernel-doc:: include/linux/delay.h
|
|
:identifiers: mdelay
|
|
|
|
|
|
`usleep_range*()` and `*sleep()` family of functions
|
|
----------------------------------------------------
|
|
|
|
These functions use hrtimers or timer list timers to provide the requested
|
|
sleeping duration. In order to decide which function is the right one to use,
|
|
take some basic information into account:
|
|
|
|
#. hrtimers are more expensive as they are using an rb-tree (instead of hashing)
|
|
#. hrtimers are more expensive when the requested sleeping duration is the first
|
|
timer which means real hardware has to be programmed
|
|
#. timer list timers always provide some sort of slack as they are jiffy based
|
|
|
|
The generic advice is repeated here:
|
|
|
|
#. Use `fsleep()` whenever unsure (as it combines all the advantages of the
|
|
others)
|
|
#. Use `*sleep()` whenever possible
|
|
#. Use `usleep_range*()` whenever accuracy of `*sleep()` is not sufficient
|
|
|
|
First check fsleep() function description and to learn more about accuracy,
|
|
please check msleep() function description.
|
|
|
|
|
|
`usleep_range*()`
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
.. kernel-doc:: include/linux/delay.h
|
|
:identifiers: usleep_range usleep_range_idle
|
|
|
|
.. kernel-doc:: kernel/time/sleep_timeout.c
|
|
:identifiers: usleep_range_state
|
|
|
|
|
|
`*sleep()`
|
|
~~~~~~~~~~
|
|
|
|
.. kernel-doc:: kernel/time/sleep_timeout.c
|
|
:identifiers: msleep msleep_interruptible
|
|
|
|
.. kernel-doc:: include/linux/delay.h
|
|
:identifiers: ssleep fsleep
|