“BUG: sleeping function called from invalid context at ......”(might_sleep 함수 설명)

4732 단어
우리는 Linux kernel 드라이브를 디버깅할 때 다음과 같은 LOG 정보를 자주 볼 수 있습니다.
[   88.055297] BUG: sleeping function called from invalid context at ......
이 오류는might_sleep 함수에 인쇄된 이 함수에 대한 설명은 다음과 같이 귀결되었다.
이 함수는 내가 코드를 볼 때 기본적으로 직접적으로 소홀히 하는 것이다. (왜냐하면 나는 그것이 실제로 무슨 일을 하지 않는다는 것을 알고 있기 때문이다.) 그러나 내부 핵 중의 많은 함수는 처음부터 그것을 사용하기 때문이다. 내부 핵 원본을 배우고 있는 네티즌들을 편리하게 하기 위해 본 글은 이 함수가 도대체 내부 핵에 의해 무엇을 하는지 전문적으로 토론하고자 한다.
간단하게 말하자면, 디버깅 수요가 없다면, 이 매크로(또는 함수, 칭호는 중요하지 않다)는 실질적인 일은 하지 않고, 커널은 단지 그것으로 한 가지 일을 할 뿐이다. 이 함수를 호출하는 함수는 sleep가 될 수 있다는 것을 일깨워 주는 것이다. 이것은 그 이름과 일치한다. The function calling might_sleep() might sleep.이 함수의 정의는 다음과 같습니다.
#ifdef CONFIG_PREEMPT_VOLUNTARY
extern int _cond_resched(void);
# define might_resched() _cond_resched()
#else
# define might_resched() do { } while (0)
#endif

#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
  void __might_sleep(const char *file, int line, int preempt_offset);
/**
 * might_sleep - annotation for functions that can sleep
 *
 * this macro will print a stack trace if it is executed in an atomic
 * context (spinlock, irq-handler, ...).
 *
 * This is a useful debugging help to be able to catch problems early and not
 * be bitten later when the calling function happens to sleep when it is not
 * supposed to.
 */
# define might_sleep() \
	do { __might_sleep(__FILE__, __LINE__, 0); might_resched(); } while (0)
#else
  static inline void __might_sleep(const char *file, int line,
				   int preempt_offset) { }
# define might_sleep() do { might_resched(); } while (0)
#endif

사실 내부 원본 코드에 대해서도 명확한 주석이 있다:might_sleep - annotation for functions that can sleep.그래서 릴리스 버전의kernel image에 대해might_sleep의 역할은 단지 annotation일 뿐, 사용자에게 일깨워주고,might_sleep의 함수는 그 후의 코드 실행에서 sleep가 될 수 있습니다.
그러나 디버깅 수요가 개입된다면 예를 들어 당신의 시스템이 영문도 모른 채 무작위로 충돌을 일으킬 수 있습니다. 어려운 사건 분석 조사를 거친 후에 마지막으로 코어를 열기로 결정한 CONFIG_DEBUG_ATOMIC_SLEEP 옵션, 이제 might_sleep는 사건의 진일보한 추진에 기여할 수 있다.CONFIG_DEBUG_ATOMIC_SLEEP 옵션은 주로 하나의 ATOMIC 조작의 상하문에서 함수가sleep 행위를 하는지 확인하는 데 사용되며, ATOMIC 조작이 무엇인지, 내부 원본 코드는might_sleep 함수 앞에도 다음 설명이 있습니다.
this macro will print a stack trace if it is executed in an atomic context (spinlock, irq-handler, ...)
그래서 하나의 프로세스가 spinlock을 얻은 후에 이른바 atomiccontext, 또는irq-handler, 즉 인터럽트 상하문에 들어간 것이 분명하다.이 두 가지 상하문에서 이론적으로 현재의 execution path를 sleep 상태에 들어가게 해서는 안 된다. (강제 규정은 아니지만, 다시 말하면spinlock을 가진 프로세스가 sleep에 들어가는 것은 시스템이 반드시 deadlock 등을 의미하는 것은 아니지만 내부 프로그래밍에 있어서는 이 지뢰밭을 최대한 피해야 한다.)CONFIG에서_DEBUG_ATOMIC_SLEEP 옵션이 켜진 경우 might_sleep에는 또 어떤 특수한 기능이 있습니까?코어의 소스 코드를 살펴보십시오.
void __might_sleep(const char *file, int line, int preempt_offset)
{
	static unsigned long prev_jiffy;	/* ratelimiting */

	rcu_sleep_check(); /* WARN_ON_ONCE() by default, no rate limit reqd. */
	if ((preempt_count_equals(preempt_offset) && !irqs_disabled()) ||
	    oops_in_progress)
		return;
	if (system_state != SYSTEM_RUNNING &&
	    (!__might_sleep_init_called || system_state != SYSTEM_BOOTING))
		return;
	if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
		return;
	prev_jiffy = jiffies;

	printk(KERN_ERR
		"BUG: sleeping function called from invalid context at %s:%d
", file, line); printk(KERN_ERR "in_atomic(): %d, irqs_disabled(): %d, pid: %d, name: %s
", in_atomic(), irqs_disabled(), current->pid, current->comm); debug_show_held_locks(current); if (irqs_disabled()) print_irqtrace_events(current); dump_stack(); } EXPORT_SYMBOL(__might_sleep);

현재 CONFIG_DEBUG_ATOMIC_SLEEP 옵션을 사용하면 __might_sleep는 여전히 많은 일을 했습니다. 가장 중요한 일은 첫 번째if문장, 특히preempt_count_equals 및 irqs_disabled는 현재 상하문이 하나의atomiccontext인지 판단하는 데 사용됩니다. 프로세스가 spin_를 얻으면lock의 변종 형식의 lock은 단일 프로세서 시스템이든 다중 프로세서 시스템이든preempt_count 변경,irq_disabled는 현재 중단이 켜져 있는지 여부를 판단하는 데 사용됩니다. __might_sleep는 바로 이러한 정보에 근거하여 현재 실행 중인 코드 상하문이atomic인지 아닌지를 판단하는 것입니다. 그렇지 않으면 함수는 모든 것이 정상적이기 때문에 바로 되돌아옵니다.만약 그렇다면 코드는 아래로 내려간다.
그래서 CONFIG_DEBUG_ATOMIC_SLEEP 옵션을 열면 atomic context에서sleep가 발생했는지 확인할 수 있습니다. 만약 코드가 실수로 어딘가에 이런 상황이 발생했다면might_sleep는 다음 printk 및 dump_를 통해stack은 당신이 이런 상황을 발견하는 것을 협조합니다.
__might_sleep 함수의 system_state, 이것은 전역적인enum형 변수로 현재 시스템의 상태를 기록하는 데 주로 사용된다.주의 system_state는 export에 의해 나왔기 때문에 내부 모듈은 이 값을 직접 읽어서 현재 시스템의 운행 상태를 판단할 수 있습니다. 흔히 볼 수 있는 상태는 다음과 같습니다.
    extern enum system_states {
        SYSTEM_BOOTING,
        SYSTEM_RUNNING,
        SYSTEM_HALT,
        SYSTEM_POWER_OFF,
        SYSTEM_RESTART,
        SYSTEM_SUSPEND_DISK,
    } system_state;

가장 흔한 상태는 단연 SYSTEM입니다.RUNNING, 당신의 시스템이 정상이 된 후에 이 상태에 처해 있다.현재의 화제와 직접적인 연관이 없기 때문에, 여기에서 한 번만 언급하면 된다.

좋은 웹페이지 즐겨찾기