Linux ドライバーで IO プロセスをブロックするための処理メカニズム

王林
リリース: 2024-02-11 16:45:03
転載
496 人が閲覧しました

ドライバーがすぐに要求に応じられない場合の対応を検討する必要があります。通常、呼び出しプロセスはドライバーのステータスを気にしないため、ドライバー内でそれに応じて処理する必要があります。一般的なアプローチは、プロセスへのリクエストをブロックすることです。

I/O のブロックとは、デバイス操作の実行時に必要なリソースを取得できない場合、操作が実行される前に操作可能な条件が満たされるまで現在のプロセスが一時停止されることを意味します。一時停止されたプロセスはスリープ状態になり、待機条件が満たされるまでスケジューラの実行キューから削除されます。逆に、ノンブロッキング I/O では、デバイス操作が実行できない場合でもプロセスは一時停止されませんが、操作を実行できるようになるまでポーリングを中止するか続行することが選択されます。

#「

待機キューは、ブロッキング I/O を処理するための古典的なメカニズムです。

#1. ドライバーでの I/O 処理フローのブロック

要約すると、ブロッキング I/O 処理フローには 4 つの部分が含まれます。まず、ブロックする必要があるプロセスを格納する待機キュー リストを初期化します。次に、待機キューを初期化し、現在ブロックする必要があるプロセスを待機キューのリンク リストに追加します。次に、プロセスを割り込み可能に設定し、プロセスがスリープ状態になるのをブロックします。最後に、特定の条件が満たされると、つまりリソー​​スが利用可能になると、待機キュー内のプロセスが起動されます。

次の図は、ブロッキング I/O 処理フローを示しています。


2. 待機リストの初期化Linux ドライバーで IO プロセスをブロックするための処理メカニズム

待機キューのリンク リストを初期化する前に、まず wait_queue_head_t

変数を定義する必要があります。たとえば、

#RK3399 の ISP ドライバーでは、データ構造 struct rkisp1_streamwait_queue_head_tned; が含まれています。 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);
}
ログイン後にコピー

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);
 }
...
}
ログイン後にコピー

以上がLinux ドライバーで IO プロセスをブロックするための処理メカニズムの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:lxlinux.net
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!