Windows system >> Windowsの知識 >  >> Linuxシステムチュートリアル >> Linuxチュートリアル >> Linuxカーネルの待ち行列メカニズムの原理分析

Linuxカーネルの待ち行列メカニズムの原理分析

  
1. 1.待ち行列のデータ構造

待ち行列は、要素がプロセス記述子へのポインタを含む二重リンクリストによって実装されています。各待機キューには待機キューヘッドがあります。これは、wait_queque_head_t型のデータ構造です。
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
typedef struct __wait_queue_head wait_queue_head_t;
ここでlockは同時アクセスを防ぐために使用され、task_listフィールドは待機リストの先頭です。リストwait_queue_tを待っ

要素型キュー、我々は、キューエントリを待って呼び出すことができます。
構造体__wait_queue {
unsigned int型のフラグ。
の#define WQ_FLAG_EXCLUSIVE 0x01の
無効* private;
wait_queue_func_t func;
struct list_head task_list;
};
typedef struct __wait_queue wait_queue_t;
各待機キュー項目は、イベントの発生を待機するスリーププロセスを表します。そのディスクリプタアドレスは通常プライベートフィールドに置かれます。 Task_listフィールドには、要素を同じイベントを待機しているプロセスのリストにリンクするポインタが含まれています。
waitキュー要素のfuncフィールドは、スリーププロセスがwaitキュー内でウェイクアップする方法を示すために使用されます(相互に排他的および相互に非排他的)。

全体のキュー構造を以下に示すように:


キューが働く待っ下記参照。 。

2
の待ち行列の前に、スリープキュー中

通常待ちキューの先頭を定義するために使用:静的wait_queue_head_tのWQをした後、関数wait_event_を呼び出します*条件条件を待っている現在のプロセスは、待ち行列wqに挿入されてスリープし、条件条件が満たされるまで待ち、カーネルは、待ち行列wqでスリープしているあるプロセスまたはすべてのプロセスを起動します。
について話をする待ちキューヘッド何の
定義、wait_event_から次の呼び出し*スタート解析:
ここではより一般的なwait_event_interruptible与える:
/** *
wait_event_interruptible - 状態まで睡眠をtrueを取得します。
* @wq:待機する待機キュー
* @condition:待機するイベントのC式
* *プロセスは<(TASK_INTERRUPTIBLE)までスリープ状態になります。 Br> * @conditionはtrueと評価されるかシグナルを受信します。
* @conditionはウェイトキュー@wqが起こされるたびにチェックされます。
*
* wake_up()は変更後に呼ばれなければなりません待機条件の結果を変更する可能性があるすべての変数

*シグナルによって割り込まれた場合、関数は-ERESTARTSYSを返し、@条件がtrueと評価された場合は0を返します。
* /
#define wait_event_interruptible(wq、condition)\\
({\\
int __ret = 0; \\
if(!(condition))\\
__wait_event_interruptible(wq、条件、__ret); \\
__ret; \\
})
これは非常に簡単です、条件を判断してください満たされているかどうかにかかわらず、満たされていない場合は__wait_event_interruptible関数を呼び出します。

の#define __wait_event_interruptible(WQ、条件、RET)\\
行う{\\
DEFINE_WAIT(__待機); \\
\\
用(;;){\\
prepare_to_wait (& wq、& __ wait、TASK_INTERRUPTIBLE); \\
if(条件)\\
break; \\
if(!signal_pending(現在)){\\
schedule(); \\
continue; \\
} \\
ret = -ERESTARTSYS; \\
break; \\
} \\
finish_wait(& wq、& __ wait); \\
} while( 0)
ログイン__wait_event_interruptible wait_queue_t最初のキュー・エントリのタイプを定義__wait:
の#define DEFINE_WAIT(名)\\
wait_queue_t名= {\\
.private =現在、\\ < Br> .func = autoremove_wake_function、\\
.task_list = LIST_HEAD_INIT((name).task_list)、\\
}
__waitのプライベートメンバを見つけることができます(通常はプロセス記述子の格納に使用されます)。これはcurrentに初期化されており、待機キューエントリが現在のプロセスに対応していることを示しています。 funcメンバはウェイトキューエントリに対応するwakeup関数で、プロセスが起こされた後、それを実行し、デフォルトのautoremove_wake_function関数に初期化されます。
ログインprepare_to_wait次いで、(;;)サイクルのために関数呼び出し:fastcall prepare_to_wait(wait_queue_head_t * Q、wait_queue_t *待ち、INT状態)
{
unsigned long型フラグを無効
; < Br>
wait-> flags& =〜WQ_FLAG_EXCLUSIVE;
spin_lock_irqsave(& q-> lock、flags);
if(list_empty(& wait-> task_list))
__ add_wait_queue(q、wait);
/*
*これが非同期待ち行列コールバックを待ち行列に入れようとしている場合は、タスク状態を変更しないでください。
* /
if( Is_sync_wait(wait))
set_current_state(state);
spin_unlock_irqrestore(& q-> lock、flags);
}
prepare_to_waitは2つのことを行い、以前に定義された待機キューエントリになります__waitが待機キューヘッダーwqに挿入され、現在のプロセスがTASK_INTERRUPTIBLE状態に設定されます。 prepare_to_waitが実行された後、条件が満たされているかどうかをチェックしますこの時点で偶然に満たされていれば、スリープする必要はありません。あなたが会っていないならば、あなたは眠る準備ができています。

睡眠は、以前に現在のプロセスTASK_INTERRUPTIBLE状態に設定されているようにので、ここで、次に切り替えの処理を行って、その後、スケジュールを()を実行、スケジュール()関数を呼び出すことによって行われ、それが再びプロセスにディスパッチすることはありませんプロセスが起動されるまで(つまりTASK_RUNNING状態に変わるまで)実行されます。
これは、schedule()切り替えプロセスを実行する前にシグナルがあるかどうかを判断し、ある場合はすぐにERESTARTSYSを返します。そうでなければ、schedule()を実行してスリープします。
ログイン(;;)ループ効果のためには、プロセス条件が成立しているか否かをチェックするために再び目覚めることを可能にすることです。主な理由は、待機中のキューにある複数のプロセスが同時に起きないようにするためですが、他のプロセスが過去にリソースを占有して使用できなくなっている可能性があるため、判断することをお勧めします。 (&#038最後のステップはfinish_wait呼び出すことです後

プロセスがウェイクアップ(もちろん、カーネルにも方法は、関連情報を参照することができます興味を持っている)プロセスのためのウェイクアップのみの1つまたは複数のプロセス(排他待ちを提供); WQ、 & __ wait)関数はクリーンアップを実行します。 Finish_waitはプロセスの状態を再びTASK_RUNNINGに設定し、プロセスを待機キューから削除します。
無効fastcall finish_wait(wait_queue_head_t * Q、wait_queue_t *待機)
{
unsigned long型のフラグ。

__set_current_state(TASK_RUNNING);

場合(list_empty_careful(&#038 !; wait-> task_list)){
spin_lock_irqsave(& q-> lock、flags);
list_del_init(& wait-> task_list);
spin_unlock_irqrestore(& q-> lock) 、フラグ);}

}

再び以前のコールwait_event_interruptible後に返される(WQ、条件)は、ダウン継続する場所にブロックされています。
Copyright © Windowsの知識 All Rights Reserved