mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
timers: Update function descriptions of sleep/delay related functions
A lot of commonly used functions for inserting a sleep or delay lack a proper function description. Add function descriptions to all of them to have important information in a central place close to the code. No functional change. Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Frederic Weisbecker <frederic@kernel.org> Link: https://lore.kernel.org/all/20241014-devel-anna-maria-b4-timers-flseep-v3-5-dc8b907cb62f@linutronix.de
This commit is contained in:
parent
102f085d84
commit
f36eb17141
3 changed files with 120 additions and 22 deletions
|
@ -12,11 +12,39 @@ extern void __const_udelay(unsigned long xloops);
|
||||||
extern void __delay(unsigned long loops);
|
extern void __delay(unsigned long loops);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The weird n/20000 thing suppresses a "comparison is always false due to
|
* Implementation details:
|
||||||
* limited range of data type" warning with non-const 8-bit arguments.
|
*
|
||||||
|
* * The weird n/20000 thing suppresses a "comparison is always false due to
|
||||||
|
* limited range of data type" warning with non-const 8-bit arguments.
|
||||||
|
* * 0x10c7 is 2**32 / 1000000 (rounded up) -> udelay
|
||||||
|
* * 0x5 is 2**32 / 1000000000 (rounded up) -> ndelay
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 0x10c7 is 2**32 / 1000000 (rounded up) */
|
/**
|
||||||
|
* udelay - Inserting a delay based on microseconds with busy waiting
|
||||||
|
* @usec: requested delay in microseconds
|
||||||
|
*
|
||||||
|
* When delaying in an atomic context ndelay(), udelay() and mdelay() are the
|
||||||
|
* only valid variants of delaying/sleeping to go with.
|
||||||
|
*
|
||||||
|
* When inserting delays in non atomic context which are shorter than the time
|
||||||
|
* which is required to queue e.g. an hrtimer and to enter then the scheduler,
|
||||||
|
* it is also valuable to use udelay(). But it is not simple to specify a
|
||||||
|
* generic threshold for this which will fit for all systems. An approximation
|
||||||
|
* is a threshold for all delays up to 10 microseconds.
|
||||||
|
*
|
||||||
|
* When having a delay which is larger than the architecture specific
|
||||||
|
* %MAX_UDELAY_MS value, please make sure mdelay() is used. Otherwise a overflow
|
||||||
|
* risk is given.
|
||||||
|
*
|
||||||
|
* Please note that ndelay(), udelay() and mdelay() may return early for several
|
||||||
|
* reasons (https://lists.openwall.net/linux-kernel/2011/01/09/56):
|
||||||
|
*
|
||||||
|
* #. computed loops_per_jiffy too low (due to the time taken to execute the
|
||||||
|
* timer interrupt.)
|
||||||
|
* #. cache behaviour affecting the time it takes to execute the loop function.
|
||||||
|
* #. CPU clock rate changes.
|
||||||
|
*/
|
||||||
#define udelay(n) \
|
#define udelay(n) \
|
||||||
({ \
|
({ \
|
||||||
if (__builtin_constant_p(n)) { \
|
if (__builtin_constant_p(n)) { \
|
||||||
|
@ -29,7 +57,12 @@ extern void __delay(unsigned long loops);
|
||||||
} \
|
} \
|
||||||
})
|
})
|
||||||
|
|
||||||
/* 0x5 is 2**32 / 1000000000 (rounded up) */
|
/**
|
||||||
|
* ndelay - Inserting a delay based on nanoseconds with busy waiting
|
||||||
|
* @nsec: requested delay in nanoseconds
|
||||||
|
*
|
||||||
|
* See udelay() for basic information about ndelay() and it's variants.
|
||||||
|
*/
|
||||||
#define ndelay(n) \
|
#define ndelay(n) \
|
||||||
({ \
|
({ \
|
||||||
if (__builtin_constant_p(n)) { \
|
if (__builtin_constant_p(n)) { \
|
||||||
|
|
|
@ -6,17 +6,7 @@
|
||||||
* Copyright (C) 1993 Linus Torvalds
|
* Copyright (C) 1993 Linus Torvalds
|
||||||
*
|
*
|
||||||
* Delay routines, using a pre-computed "loops_per_jiffy" value.
|
* Delay routines, using a pre-computed "loops_per_jiffy" value.
|
||||||
*
|
* Sleep routines using timer list timers or hrtimers.
|
||||||
* Please note that ndelay(), udelay() and mdelay() may return early for
|
|
||||||
* several reasons:
|
|
||||||
* 1. computed loops_per_jiffy too low (due to the time taken to
|
|
||||||
* execute the timer interrupt.)
|
|
||||||
* 2. cache behaviour affecting the time it takes to execute the
|
|
||||||
* loop function.
|
|
||||||
* 3. CPU clock rate changes.
|
|
||||||
*
|
|
||||||
* Please see this thread:
|
|
||||||
* https://lists.openwall.net/linux-kernel/2011/01/09/56
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/math.h>
|
#include <linux/math.h>
|
||||||
|
@ -35,12 +25,21 @@ extern unsigned long loops_per_jiffy;
|
||||||
* The 2nd mdelay() definition ensures GCC will optimize away the
|
* The 2nd mdelay() definition ensures GCC will optimize away the
|
||||||
* while loop for the common cases where n <= MAX_UDELAY_MS -- Paul G.
|
* while loop for the common cases where n <= MAX_UDELAY_MS -- Paul G.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MAX_UDELAY_MS
|
#ifndef MAX_UDELAY_MS
|
||||||
#define MAX_UDELAY_MS 5
|
#define MAX_UDELAY_MS 5
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef mdelay
|
#ifndef mdelay
|
||||||
|
/**
|
||||||
|
* mdelay - Inserting a delay based on milliseconds with busy waiting
|
||||||
|
* @n: requested delay in milliseconds
|
||||||
|
*
|
||||||
|
* See udelay() for basic information about mdelay() and it's variants.
|
||||||
|
*
|
||||||
|
* Please double check, whether mdelay() is the right way to go or whether a
|
||||||
|
* refactoring of the code is the better variant to be able to use msleep()
|
||||||
|
* instead.
|
||||||
|
*/
|
||||||
#define mdelay(n) (\
|
#define mdelay(n) (\
|
||||||
(__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \
|
(__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \
|
||||||
({unsigned long __ms=(n); while (__ms--) udelay(1000);}))
|
({unsigned long __ms=(n); while (__ms--) udelay(1000);}))
|
||||||
|
@ -63,16 +62,41 @@ unsigned long msleep_interruptible(unsigned int msecs);
|
||||||
void usleep_range_state(unsigned long min, unsigned long max,
|
void usleep_range_state(unsigned long min, unsigned long max,
|
||||||
unsigned int state);
|
unsigned int state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* usleep_range - Sleep for an approximate time
|
||||||
|
* @min: Minimum time in microseconds to sleep
|
||||||
|
* @max: Maximum time in microseconds to sleep
|
||||||
|
*
|
||||||
|
* For basic information please refere to usleep_range_state().
|
||||||
|
*
|
||||||
|
* The task will be in the state TASK_UNINTERRUPTIBLE during the sleep.
|
||||||
|
*/
|
||||||
static inline void usleep_range(unsigned long min, unsigned long max)
|
static inline void usleep_range(unsigned long min, unsigned long max)
|
||||||
{
|
{
|
||||||
usleep_range_state(min, max, TASK_UNINTERRUPTIBLE);
|
usleep_range_state(min, max, TASK_UNINTERRUPTIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* usleep_range_idle - Sleep for an approximate time with idle time accounting
|
||||||
|
* @min: Minimum time in microseconds to sleep
|
||||||
|
* @max: Maximum time in microseconds to sleep
|
||||||
|
*
|
||||||
|
* For basic information please refere to usleep_range_state().
|
||||||
|
*
|
||||||
|
* The sleeping task has the state TASK_IDLE during the sleep to prevent
|
||||||
|
* contribution to the load avarage.
|
||||||
|
*/
|
||||||
static inline void usleep_range_idle(unsigned long min, unsigned long max)
|
static inline void usleep_range_idle(unsigned long min, unsigned long max)
|
||||||
{
|
{
|
||||||
usleep_range_state(min, max, TASK_IDLE);
|
usleep_range_state(min, max, TASK_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ssleep - wrapper for seconds around msleep
|
||||||
|
* @seconds: Requested sleep duration in seconds
|
||||||
|
*
|
||||||
|
* Please refere to msleep() for detailed information.
|
||||||
|
*/
|
||||||
static inline void ssleep(unsigned int seconds)
|
static inline void ssleep(unsigned int seconds)
|
||||||
{
|
{
|
||||||
msleep(seconds * 1000);
|
msleep(seconds * 1000);
|
||||||
|
|
|
@ -281,7 +281,34 @@ EXPORT_SYMBOL_GPL(schedule_hrtimeout);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* msleep - sleep safely even with waitqueue interruptions
|
* msleep - sleep safely even with waitqueue interruptions
|
||||||
* @msecs: Time in milliseconds to sleep for
|
* @msecs: Requested sleep duration in milliseconds
|
||||||
|
*
|
||||||
|
* msleep() uses jiffy based timeouts for the sleep duration. Because of the
|
||||||
|
* design of the timer wheel, the maximum additional percentage delay (slack) is
|
||||||
|
* 12.5%. This is only valid for timers which will end up in level 1 or a higher
|
||||||
|
* level of the timer wheel. For explanation of those 12.5% please check the
|
||||||
|
* detailed description about the basics of the timer wheel.
|
||||||
|
*
|
||||||
|
* The slack of timers which will end up in level 0 depends on sleep duration
|
||||||
|
* (msecs) and HZ configuration and can be calculated in the following way (with
|
||||||
|
* the timer wheel design restriction that the slack is not less than 12.5%):
|
||||||
|
*
|
||||||
|
* ``slack = MSECS_PER_TICK / msecs``
|
||||||
|
*
|
||||||
|
* When the allowed slack of the callsite is known, the calculation could be
|
||||||
|
* turned around to find the minimal allowed sleep duration to meet the
|
||||||
|
* constraints. For example:
|
||||||
|
*
|
||||||
|
* * ``HZ=1000`` with ``slack=25%``: ``MSECS_PER_TICK / slack = 1 / (1/4) = 4``:
|
||||||
|
* all sleep durations greater or equal 4ms will meet the constraints.
|
||||||
|
* * ``HZ=1000`` with ``slack=12.5%``: ``MSECS_PER_TICK / slack = 1 / (1/8) = 8``:
|
||||||
|
* all sleep durations greater or equal 8ms will meet the constraints.
|
||||||
|
* * ``HZ=250`` with ``slack=25%``: ``MSECS_PER_TICK / slack = 4 / (1/4) = 16``:
|
||||||
|
* all sleep durations greater or equal 16ms will meet the constraints.
|
||||||
|
* * ``HZ=250`` with ``slack=12.5%``: ``MSECS_PER_TICK / slack = 4 / (1/8) = 32``:
|
||||||
|
* all sleep durations greater or equal 32ms will meet the constraints.
|
||||||
|
*
|
||||||
|
* See also the signal aware variant msleep_interruptible().
|
||||||
*/
|
*/
|
||||||
void msleep(unsigned int msecs)
|
void msleep(unsigned int msecs)
|
||||||
{
|
{
|
||||||
|
@ -294,7 +321,15 @@ EXPORT_SYMBOL(msleep);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* msleep_interruptible - sleep waiting for signals
|
* msleep_interruptible - sleep waiting for signals
|
||||||
* @msecs: Time in milliseconds to sleep for
|
* @msecs: Requested sleep duration in milliseconds
|
||||||
|
*
|
||||||
|
* See msleep() for some basic information.
|
||||||
|
*
|
||||||
|
* The difference between msleep() and msleep_interruptible() is that the sleep
|
||||||
|
* could be interrupted by a signal delivery and then returns early.
|
||||||
|
*
|
||||||
|
* Returns: The remaining time of the sleep duration transformed to msecs (see
|
||||||
|
* schedule_timeout() for details).
|
||||||
*/
|
*/
|
||||||
unsigned long msleep_interruptible(unsigned int msecs)
|
unsigned long msleep_interruptible(unsigned int msecs)
|
||||||
{
|
{
|
||||||
|
@ -312,11 +347,17 @@ EXPORT_SYMBOL(msleep_interruptible);
|
||||||
* @max: Maximum time in usecs to sleep
|
* @max: Maximum time in usecs to sleep
|
||||||
* @state: State of the current task that will be while sleeping
|
* @state: State of the current task that will be while sleeping
|
||||||
*
|
*
|
||||||
|
* usleep_range_state() sleeps at least for the minimum specified time but not
|
||||||
|
* longer than the maximum specified amount of time. The range might reduce
|
||||||
|
* power usage by allowing hrtimers to coalesce an already scheduled interrupt
|
||||||
|
* with this hrtimer. In the worst case, an interrupt is scheduled for the upper
|
||||||
|
* bound.
|
||||||
|
*
|
||||||
|
* The sleeping task is set to the specified state before starting the sleep.
|
||||||
|
*
|
||||||
* In non-atomic context where the exact wakeup time is flexible, use
|
* In non-atomic context where the exact wakeup time is flexible, use
|
||||||
* usleep_range_state() instead of udelay(). The sleep improves responsiveness
|
* usleep_range() or its variants instead of udelay(). The sleep improves
|
||||||
* by avoiding the CPU-hogging busy-wait of udelay(), and the range reduces
|
* responsiveness by avoiding the CPU-hogging busy-wait of udelay().
|
||||||
* power usage by allowing hrtimers to take advantage of an already-
|
|
||||||
* scheduled interrupt instead of scheduling a new one just for this sleep.
|
|
||||||
*/
|
*/
|
||||||
void __sched usleep_range_state(unsigned long min, unsigned long max, unsigned int state)
|
void __sched usleep_range_state(unsigned long min, unsigned long max, unsigned int state)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue