문맥:다음 작업 집합 {A, B, C, D, E}를 고려하세요.
- (A): 내 장치 드라이버 기능에서
read()
드라이버 버퍼가 비어 있으면 호출 스레드를 대기 대기열에 추가합니다.wq
buf
보다 구체적으로 호출 스레드는 다음을 통해 대기열에 추가됩니다.
wait_event_interruptible(wq, strlen(buf) > 0)
- (B): 마찬가지로 드라이버 기능에서 전달된 명령이 이고 드라이버의 플래그가 인 경우
ioctl()
호출 스레드를 동일한 대기열에 추가합니다.wq
ioctl
MY_IOCTL_X
is_free == 0
마찬가지로 호출 스레드는 다음을 통해 대기 대기열에 추가됩니다.
wait_event_interruptible(wq, is_free != 0)
(C): 드라이버 함수에서 "휴면" 상태에 있는 스레드를 깨우기 위해
write()
사용자 공간 콘텐츠를 에 전달buff
하고 을 호출합니다 .wake_up_interruptible(&wq)
read()
(D): 드라이버
ioctl()
기능 에서ioctl
명령이 이면 "sleep" 상태에 있던 스레드를 깨우도록MY_IOCTL_Y
설정is_free = 1
하고 호출합니다 .wake_up_interruptible(&wq)
ioctl(MY_IOCTL_X)
print_wait_queue()
(E): 대기 대기열에 있는 스레드의 PID를 인쇄하는 함수를 만들었습니다 . 예전에 그렇게 불렀었는데~ 후에wake_up_interruptible()
작업 C와 D를 호출합니다 .
인쇄 기능은 다음과 같이 구현됩니다.
void print_wait_queue(struct wait_queue_head* wq)
{
struct list_head *i, *tmp;
pr_info("waiting queue: [");
list_for_each_safe(i, tmp, &(wq->head))
{
struct wait_queue_entry* wq_item = list_entry(i, struct wait_queue_entry, entry);
struct task_struct* task = (struct task_struct*) wq_item->private;
pr_info("%d,", task->pid);
}
pr_info("]\n");
}
질문:실제 대기열 추가 및 대기열 제거는 예상대로 작동하는 것으로 보이며 여기서는 문제가 없습니다.
그러나 대기열에서 인쇄 대기는 발생하지 않습니다.
위의 작업을 A -> B -> C -> D 순서로 수행한다고 가정합니다.
다음은 콘솔에서 얻은 결과입니다(간단한 출력).
- "대기 대기열: [pid_1, pid_2]" //
wake_up_interruptible()
호출 전write()
- "대기 대기열: []" //
wake_up_interruptible()
호출write()
(나는 [pid_2]를 기대하고 있습니다) - "대기 대기열: [pid_2]" // 호출
wake_up_interruptible()
전ioctl(MY_IOCTL_Y)
- "대기 대기열: []" // 호출
wake_up_interruptible()
후ioctl(MY_IOCTL_Y)
위에 표시된 대로 인쇄 #2에서는 나머지 스레드(pid_2)의 PID가 PID 목록에 표시되지 않습니다. 대신 빈 목록이 표시됩니다.
wake_up_interruptible()
그러나 예상대로 pid_2는 ioctl(MY_IOCTL_Y)
인쇄 #3이 호출되기 전에 목록에 나타나며 이는 pid_2
실제로 인쇄 #2와 #3 사이의 대기 대기열에 남아 있음을 나타냅니다.
질문:위의 인쇄 #2에서는 [pid_2]를 얻지 못하지만 #3에서는 얻는 이유는 무엇입니까?
잠금으로 대기 대기열 주기를 보호하려고 했지만 print_wait_queue()
인쇄 문제가 해결되지 않았습니다.
또한 내가 전달한 포인터의 주소는 print_wait_queue()
항상 같은 주소를 가리키는 것을 확인했습니다.
답변1
내 관찰은 예상된 동작입니다.
상술 한 바와 같이여기, 섹션 6.2.2에서:
wake_up()
깨우다주어진 큐에서 대기 중인 모든 프로세스(...). 다른 형태(wake_up_interruptible()
)는 중단 가능한 절전 모드를 실행하는 프로세스로 제한됩니다.
따라서 위의 인쇄 #2에서 wake_up_interruptible()
호출 직후 두 작업의 상태는 runnable
이므로 두 작업 모두 대기 대기열에서 제거됩니다. 하지만 ioctl()
아직 조건이 검증되지 않아 임무는 다시 휴면 상태가 될 예정이다.
gdb
각 작업 전후의 pid_2 작업 상태를 확인하여 이를 확인 했습니다 wake_up_interruptible()
.