운전기사가 요청을 즉시 이행할 수 없는 상황에 직면했을 때 어떻게 대응할지 고려해야 합니다. 일반적으로 호출 프로세스는 드라이버의 상태에 관심이 없으므로 드라이버에서 그에 따라 처리해야 합니다. 일반적인 접근 방식은 프로세스에 대한 요청을 차단하는 것입니다.
Blocking I/O는 장치 작업을 수행할 때 필요한 리소스를 얻을 수 없는 경우 작업이 수행되기 전에 작동 가능한 조건이 충족될 때까지 현재 프로세스가 일시 중지된다는 의미입니다. 일시중단된 프로세스는 대기 상태가 되며 대기 조건이 충족될 때까지 스케줄러의 실행 큐에서 제거됩니다. 이에 비해 비차단 I/O는 장치 작업을 수행할 수 없을 때 프로세스를 일시 중지하지 않고 작업을 수행할 수 있을 때까지 폴링을 포기하거나 계속하도록 선택합니다.
“
대기 대기열은 차단 I/O를 처리하는 고전적인 메커니즘입니다.
”
요약하면 블로킹 I/O 처리 흐름은 4가지 부분으로 구성됩니다. 먼저, 차단해야 하는 프로세스를 저장하는 대기 대기열 목록을 초기화합니다. 그런 다음 대기 큐를 초기화하고 현재 차단해야 하는 프로세스를 대기 큐 연결 목록에 추가합니다. 그런 다음 프로세스를 중단 가능하도록 설정하고 프로세스가 휴면 상태가 되지 않도록 차단합니다. 마지막으로 특정 조건이 충족되면, 즉 리소스를 사용할 수 있게 되면 대기 대기열에 있던 프로세스가 깨어납니다.
다음 그림은 차단 I/O 처리 흐름을 설명합니다.
대기 대기열 연결 목록을 초기화하기 전에 먼저 초기화 작업을 위한wait_queue_head_t
的变量。例如在RK3399
的ISP驱动中数据结构struct rkisp1_stream
包含了wait_queue_head_t done;
。通过调用调用init_waitqueue_head(&stream->done);
을 정의해야 합니다.
wait_queue_head_t
变量的原型是__wait_queue_head
, 아래와 같이:
init_waitqueue_head()
真正执行的函数是__init_waitqueue_head()
해당 기능은 다음과 같이 정의됩니다.
void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *key) { spin_lock_init(&q->lock); lockdep_set_class_and_name(&q->lock, key, name); INIT_LIST_HEAD(&q->task_list); }
调用DECLARE_WAITQUEUE(wait, current)
将当前进程初始化为等待队列。注意,这里的等待队列和等待队列链表头可不是一个东东。
#define DECLARE_WAITQUEUE(name, tsk) \ wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)
等待队列的定义如下:
struct __wait_queue { unsigned int flags; void *private; wait_queue_func_t func; struct list_head task_list; };
等待队列和等待队列链表头是通过add_wait_queue()
结合到一起的。
init_waitqueue_head(&delay_wait); add_wait_queue(&delay_wait, &wait);
以上代码是将等待队列进程加入到等待队列链表中:
static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new) { list_add(&new->task_list, &head->task_list); }
阻塞进程处理包括两部分内容,首先设置进程的睡眠状态,包括TASK_INTERRUPTIBLE
和TASK_UNINTERRUPTIBLE
两种。前者用于可中断睡眠,后者用于不可中断睡眠。然后,将当前进程退出调度器让出CPU的使用权。
set_current_state(TASK_INTERRUPTIBLE); schedule();
唤醒处理通常位于中断处理函数或某些动作成功执行之后,特定条件满足时,唤醒通过阻塞队列睡眠的进程。例如:
void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long sectors, int success, int behind) { if (!bitmap) return; if (behind) { if (atomic_dec_and_test(&bitmap->behind_writes)) wake_up(&bitmap->behind_wait); pr_debug("dec write-behind count %d/%lu\n", atomic_read(&bitmap->behind_writes), bitmap->mddev->bitmap_info.max_write_behind); } ... }
위 내용은 Linux 드라이버에서 IO 프로세스를 차단하는 처리 메커니즘의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!