Heim  >  Artikel  >  System-Tutorial  >  Der Verarbeitungsmechanismus zum Blockieren von E/A-Prozessen in Linux-Treibern

Der Verarbeitungsmechanismus zum Blockieren von E/A-Prozessen in Linux-Treibern

王林
王林nach vorne
2024-02-11 16:45:03560Durchsuche

Wir müssen darüber nachdenken, wie wir reagieren sollen, wenn wir mit einer Situation konfrontiert werden, in der der Fahrer die Anfrage nicht sofort erfüllen kann. Normalerweise kümmert sich der aufrufende Prozess nicht um den Status des Treibers, daher müssen wir ihn im Treiber entsprechend behandeln. Ein gängiger Ansatz besteht darin, Anfragen an den Prozess zu blockieren.

Das Blockieren von E/A bedeutet, dass der aktuelle Prozess angehalten wird, bis die Betriebsbedingungen erfüllt sind, bevor die Operation ausgeführt wird, wenn die erforderlichen Ressourcen bei der Ausführung von Geräteoperationen nicht abgerufen werden können. Der angehaltene Prozess geht in den Ruhezustand und wird aus der Ausführungswarteschlange des Planers entfernt, bis die Wartebedingungen erfüllt sind. Im Gegensatz dazu unterbricht die nicht blockierende E/A den Prozess nicht, wenn der Gerätevorgang nicht ausgeführt werden kann, sondern gibt die Abfrage auf oder setzt die Abfrage fort, bis der Vorgang ausgeführt werden kann.

Wartewarteschlange ist ein klassischer Mechanismus zur Behandlung blockierender E/A.

1. Blockieren des E/A-Verarbeitungsflusses im Treiber

Zusammenfassend umfasst der blockierende E/A-Verarbeitungsablauf vier Teile. Initialisieren Sie zunächst die Warteschlangenliste, in der die Prozesse gespeichert sind, die blockiert werden müssen. Initialisieren Sie dann eine Warteschlange und fügen Sie den Prozess, der derzeit blockiert werden muss, zur verknüpften Liste der Warteschlange hinzu. Stellen Sie dann den Prozess auf unterbrechbar ein und blockieren Sie den Ruhezustand des Prozesses. Wenn schließlich bestimmte Bedingungen erfüllt sind, also Ressourcen verfügbar sind, werden die Prozesse in der Warteschlange aktiviert.
Die folgende Abbildung beschreibt den blockierenden E/A-Verarbeitungsablauf:

Der Verarbeitungsmechanismus zum Blockieren von E/A-Prozessen in Linux-Treibern

2. Initialisieren Sie die Warteschlangenliste

Bevor wir die verknüpfte Liste der Warteschlange initialisieren, müssen wir zunächst einen wait_queue_head_t的变量。例如在RK3399的ISP驱动中数据结构struct rkisp1_stream包含了wait_queue_head_t done;。通过调用调用init_waitqueue_head(&stream->done);für den Initialisierungsvorgang definieren.

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, wie unten gezeigt:

struct __wait_queue_head {
 spinlock_t  lock;
 struct list_head task_list;
};

init_waitqueue_head()真正执行的函数是__init_waitqueue_head(), seine Funktion ist wie folgt definiert:

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);
}

3. 等待队列处理

调用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);
}

4. 阻塞进程处理

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

set_current_state(TASK_INTERRUPTIBLE);
schedule();

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);
 }
...
}

Das obige ist der detaillierte Inhalt vonDer Verarbeitungsmechanismus zum Blockieren von E/A-Prozessen in Linux-Treibern. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:lxlinux.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen