커널 지연 함수

1) msleep: 밀리초 단위의 지연 시간을 실현하며, 이 지연 시간은 최소한 설정한 지연 시간을 보장하며, 시간 초과 반환을 앞당기지 않으며, CPU를 양보합니다.
void msleep(unsigned int msecs)
{
	unsigned long timeout = msecs_to_jiffies(msecs) + 1;

	while (timeout)
		timeout = schedule_timeout_uninterruptible(timeout);
}

왜 jiffies로 전환할 때 +1을 해야 하나요?앞에서 우리가 말한 바와 같이 이 지연시간은 최소한 지연전환의 jiffies 시간을 확보해야 한다. 한 jiffies는 10밀리초이다. 예를 들어 우리는 10개의 수를 찾아서 하나의 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 로 설정하는 것을 알 수 있다.UNNTERRUPTIBLE, 즉, 이 지연은 최소한 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로 되돌아온다.
armdelay_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를 참고할 수 있다.실현
/*
 * 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를 양보하는 지연 시간을 사용하기 전에 웨이크록 자물쇠를 달아서 수면을 막아야 한다.

좋은 웹페이지 즐겨찾기