Nous devons réfléchir à la manière de réagir face à une situation dans laquelle le conducteur ne peut pas répondre immédiatement à la demande. Normalement, le processus appelant ne se soucie pas du statut du pilote, nous devons donc le gérer en conséquence dans le pilote. Une approche courante consiste à bloquer les requêtes adressées au processus.
Le blocage des E/S signifie que si les ressources requises ne peuvent pas être obtenues lors de l'exécution des opérations sur l'appareil, le processus en cours sera suspendu jusqu'à ce que les conditions opérationnelles soient remplies avant d'effectuer l'opération. Le processus suspendu se met en veille et est supprimé de la file d'attente d'exécution du planificateur jusqu'à ce que les conditions d'attente soient remplies. Au contraire, les E/S non bloquantes ne suspendent pas le processus lorsque l'opération du périphérique ne peut pas être effectuée, mais choisissent d'abandonner ou de continuer l'interrogation jusqu'à ce que l'opération puisse être effectuée.
«
La file d'attente est un mécanisme classique pour gérer le blocage des E/S.
”
En résumé, le flux de traitement des E/S bloquantes comprend 4 parties. Tout d’abord, initialisez la liste d’attente, qui stocke les processus qui doivent être bloqués. Initialisez ensuite une file d'attente et ajoutez le processus qui doit actuellement être bloqué à la liste chaînée de la file d'attente. Ensuite, définissez le processus pour qu'il soit interruption et empêchez le processus de dormir. Enfin, lorsque certaines conditions sont remplies, c'est-à-dire que des ressources sont disponibles, les processus en file d'attente sont réveillés.
La figure suivante décrit le flux de traitement des E/S bloquantes :
Avant d'initialiser la liste chaînée de la file d'attente, nous devons d'abord définir une wait_queue_head_t
的变量。例如在RK3399
的ISP驱动中数据结构struct rkisp1_stream
包含了wait_queue_head_t done;
。通过调用调用init_waitqueue_head(&stream->done);
pour l'opération d'initialisation.
void rkisp1_stream_init(struct rkisp1_device *dev, u32 id) { struct rkisp1_stream *stream = &dev->stream[id]; memset(stream, 0, sizeof(*stream)); stream->id = id; stream->ispdev = dev; INIT_LIST_HEAD(&stream->buf_queue); init_waitqueue_head(&stream->done); spin_lock_init(&stream->vbq_lock); ... }
wait_queue_head_t
变量的原型是__wait_queue_head
, comme indiqué ci-dessous :
struct __wait_queue_head { spinlock_t lock; struct list_head task_list; };
init_waitqueue_head()
真正执行的函数是__init_waitqueue_head()
, sa fonction est définie comme suit :
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); } ... }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!