Maison > Tutoriel système > Linux > le corps du texte

Le mécanisme de traitement pour bloquer les processus d'E/S dans les pilotes Linux

王林
Libérer: 2024-02-11 16:45:03
avant
494 Les gens l'ont consulté

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.

1. Blocage du flux de traitement des E/S dans le pilote

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 :

Le mécanisme de traitement pour bloquer les processus dE/S dans les pilotes Linux

2. Initialisez la liste d'attente

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);
 ...
}
Copier après la connexion

wait_queue_head_t变量的原型是__wait_queue_head, comme indiqué ci-dessous :

struct __wait_queue_head {
 spinlock_t  lock;
 struct list_head task_list;
};
Copier après la connexion

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);
}
Copier après la connexion

3. 等待队列处理

调用DECLARE_WAITQUEUE(wait, current)将当前进程初始化为等待队列。注意,这里的等待队列和等待队列链表头可不是一个东东。

#define DECLARE_WAITQUEUE(name, tsk)     \
 wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)
Copier après la connexion

等待队列的定义如下:

struct __wait_queue {
 unsigned int  flags;
 void   *private;
 wait_queue_func_t func;
 struct list_head task_list;
};
Copier après la connexion

等待队列和等待队列链表头是通过add_wait_queue()结合到一起的。

init_waitqueue_head(&delay_wait);
add_wait_queue(&delay_wait, &wait);
Copier après la connexion

以上代码是将等待队列进程加入到等待队列链表中:

static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
{
 list_add(&new->task_list, &head->task_list);
}
Copier après la connexion

4. 阻塞进程处理

阻塞进程处理包括两部分内容,首先设置进程的睡眠状态,包括TASK_INTERRUPTIBLETASK_UNINTERRUPTIBLE两种。前者用于可中断睡眠,后者用于不可中断睡眠。然后,将当前进程退出调度器让出CPU的使用权。

set_current_state(TASK_INTERRUPTIBLE);
schedule();
Copier après la connexion

5. 唤醒处理

唤醒处理通常位于中断处理函数或某些动作成功执行之后,特定条件满足时,唤醒通过阻塞队列睡眠的进程。例如:

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);
 }
...
}
Copier après la connexion

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!

source:lxlinux.net
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!