カーネル遅延関数
4948 ワード
1)msleep:ミリ秒級の遅延を実現し、この遅延は少なくとも遅延に設定された遅延時間を保証し、早期にタイムアウトして返さず、CPUを譲る
なぜjiffiesに変換するときに+1するのですか?前述したように、この遅延は少なくとも遅延変換のjiffies時間を保証しなければならない.1つのjiffiesは10ミリ秒である.例えば、10個の数を調べて1つのjiffiesを表し、5まで数えたときにmsleepを呼び出すことができる.それでは、このjiffiesから時々戻ることができず、少なくとも遅延設定のjiffiesの原則に違反していることは明らかである.そのため、jiffies+1に変換するのが適切であり、カーネルでもわざわざ説明した.
2)msleep_interruptible:ミリ秒級遅延、この遅延関数は信号によって中断されて早期にタイムアウトし、残りの時間を返し、CPUを譲る可能性がある
3)ssleep:秒級遅延、msleep実現を呼び出すことで、CPUを譲る
4)usleep_range:この遅延関数はマイクロ秒レベルの遅延を実現し、特にタイムアウト範囲を設定することができ、ソースコードを見ると、この関数がタスク状態をASK_に設定していることがわかります.UNINTERUPTIBLE、すなわち、遅延は、少なくとも、中断されずにminマイクロ秒の遅延を保証することができる.CPUを譲ります
5)ndelay:ナノ秒級遅延、CPUを譲らない
6)udelay:マイクロ秒遅延、CPUを譲らない
についてbuiltin_constant_p(x)、正確な定義は、xの値がコンパイル時に決定される場合、関数は値を1に返すべきである.
arm_の場合delay_opsでは、カーネルにはデフォルトのコールバック関数があります.
しかし、ほとんどのメーカーは一般的に自分のtimerを登録して、遅延使用を提供し、具体的にはarch/arm/lib/delayを参照することができる.c実装
7)mdelay:ミリ秒級遅延、ndelayの1000倍、CPUを譲らない
遅延関数がCPUを譲るかどうかについては、使用時に注意が必要で、一般的に遅延に対して特に正確で、CPUを譲らない遅延関数を使用する.遅延要求は特に正確ではなく、CPUを呼び出す遅延関数を使用することができ、遅延システムが睡眠に入らないことを保証するために、通常、CPUを呼び出す遅延を使用する前にwakelockロックを加えて睡眠を阻止する.
void msleep(unsigned int msecs)
{
unsigned long timeout = msecs_to_jiffies(msecs) + 1;
while (timeout)
timeout = schedule_timeout_uninterruptible(timeout);
}
なぜjiffiesに変換するときに+1するのですか?前述したように、この遅延は少なくとも遅延変換のjiffies時間を保証しなければならない.1つのjiffiesは10ミリ秒である.例えば、10個の数を調べて1つのjiffiesを表し、5まで数えたときにmsleepを呼び出すことができる.それでは、このjiffiesから時々戻ることができず、少なくとも遅延設定のjiffiesの原則に違反していることは明らかである.そのため、jiffies+1に変換するのが適切であり、カーネルでもわざわざ説明した.
unsigned long msecs_to_jiffies(const unsigned int m)
{
/*
* Negative value, means infinite timeout:
*/
if ((int)m < 0)
return MAX_JIFFY_OFFSET;
。
。
。
}
/*
* Change timeval to jiffies, trying to avoid the
* most obvious overflows..
*
* And some not so obvious.
*
* Note that we don't want to return LONG_MAX, because
* for various timeout reasons we often end up having
* to wait "jiffies+1" in order to guarantee that we wait
* at _least_ "jiffies" - so "jiffies+1" had better still
* be positive.
*/
#define MAX_JIFFY_OFFSET ((LONG_MAX >> 1)-1)
2)msleep_interruptible:ミリ秒級遅延、この遅延関数は信号によって中断されて早期にタイムアウトし、残りの時間を返し、CPUを譲る可能性がある
unsigned long msleep_interruptible(unsigned int msecs)
{
unsigned long timeout = msecs_to_jiffies(msecs) + 1;
while (timeout && !signal_pending(current))
timeout = schedule_timeout_interruptible(timeout);
return jiffies_to_msecs(timeout);
}
3)ssleep:秒級遅延、msleep実現を呼び出すことで、CPUを譲る
static inline void ssleep(unsigned int seconds)
{
msleep(seconds * 1000);
}
4)usleep_range:この遅延関数はマイクロ秒レベルの遅延を実現し、特にタイムアウト範囲を設定することができ、ソースコードを見ると、この関数がタスク状態をASK_に設定していることがわかります.UNINTERUPTIBLE、すなわち、遅延は、少なくとも、中断されずにminマイクロ秒の遅延を保証することができる.CPUを譲ります
/**
* usleep_range - Drop in replacement for udelay where wakeup is flexible
* @min: Minimum time in usecs to sleep
* @max: Maximum time in usecs to sleep
*/
void usleep_range(unsigned long min, unsigned long max)
{
__set_current_state(TASK_UNINTERRUPTIBLE);
do_usleep_range(min, max);
}
5)ndelay:ナノ秒級遅延、CPUを譲らない
static inline void ndelay(unsigned long x)
{
udelay(DIV_ROUND_UP(x, 1000));
}
6)udelay:マイクロ秒遅延、CPUを譲らない
/*
* division by multiplication: you don't have to worry about
* loss of precision.
*
* Use only for very small delays ( < 2 msec). Should probably use a
* lookup table, really, as the multiplications take much too long with
* short delays. This is a "reasonable" implementation, though (and the
* first constant multiplications gets optimized away if the delay is
* a constant)
*/
#define __udelay(n) arm_delay_ops.udelay(n)
#define __const_udelay(n) arm_delay_ops.const_udelay(n)
#define udelay(n) \
(__builtin_constant_p(n) ? \
((n) > (MAX_UDELAY_MS * 1000) ? __bad_udelay() : \
__const_udelay((n) * UDELAY_MULT)) : \
__udelay(n))
についてbuiltin_constant_p(x)、正確な定義は、xの値がコンパイル時に決定される場合、関数は値を1に返すべきである.
arm_の場合delay_opsでは、カーネルにはデフォルトのコールバック関数があります.
/*
* Default to the loop-based delay implementation.
*/
struct arm_delay_ops arm_delay_ops = {
.delay = __loop_delay,
.const_udelay = __loop_const_udelay,
.udelay = __loop_udelay,
};
しかし、ほとんどのメーカーは一般的に自分のtimerを登録して、遅延使用を提供し、具体的にはarch/arm/lib/delayを参照することができる.c実装
/*
* Default to the loop-based delay implementation.
*/
struct arm_delay_ops arm_delay_ops = {
.delay = __loop_delay,
.const_udelay = __loop_const_udelay,
.udelay = __loop_udelay,
};
#ifdef ARCH_HAS_READ_CURRENT_TIMER
static void __timer_delay(unsigned long cycles)
{
cycles_t start = get_cycles();
while ((get_cycles() - start) < cycles)
cpu_relax();
}
static void __timer_const_udelay(unsigned long xloops)
{
unsigned long long loops = xloops;
loops *= loops_per_jiffy;
__timer_delay(loops >> UDELAY_SHIFT);
}
static void __timer_udelay(unsigned long usecs)
{
__timer_const_udelay(usecs * UDELAY_MULT);
}
void __init init_current_timer_delay(unsigned long freq)
{
pr_info("Switching to timer-based delay loop
");
lpj_fine = freq / HZ;// jiffy
loops_per_jiffy = lpj_fine;
arm_delay_ops.delay = __timer_delay;
arm_delay_ops.const_udelay = __timer_const_udelay;
arm_delay_ops.udelay = __timer_udelay;
}
unsigned long __cpuinit calibrate_delay_is_known(void)
{
return lpj_fine;
}
#endif
7)mdelay:ミリ秒級遅延、ndelayの1000倍、CPUを譲らない
#ifndef mdelay
#define mdelay(n) (\
(__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \
({unsigned long __ms=(n); while (__ms--) udelay(1000);}))
#endif
遅延関数がCPUを譲るかどうかについては、使用時に注意が必要で、一般的に遅延に対して特に正確で、CPUを譲らない遅延関数を使用する.遅延要求は特に正確ではなく、CPUを呼び出す遅延関数を使用することができ、遅延システムが睡眠に入らないことを保証するために、通常、CPUを呼び出す遅延を使用する前にwakelockロックを加えて睡眠を阻止する.