プロセスのBlockとWakeup
Rev.14を表示中。最新版はこちら。
1.プロセスの止め方
プロセスをブロックさせるには、WaitQueueを使ってブロックすれば、まとめてWakeupできる。1.1 WaitQueueを使わない場合
1. currentをどこかに保存2. set_current_state(TASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE)
3. schedule() - プロセス切替え(ブロック)
wake_up_process()で1.で保存しておいたcurrentを指定すれば起床できる。
1.2 WaitQueueを使う場合
WaitQueueのエントリにはwakeup時のコールバックルーチンを指定しておく。本ルーチンを指定すれば、wakeup時に何か追加の処理を行える。通常はデフォルトでいいはず。その1
        1. DECLARE_WAITQUEUE()でWaitQueue用のエントリを作成
        
3. add_wait_queue() - WaitQueueに追加
4. schedule() - プロセス切替え(ブロック)
5. remove_wait_queue() - Wakeupされたら、WaitQueueから削除
      
      
          wakeup時のコールバックルーチンは
.func = default_wake_function が設定される。
        
2. set_current_state(TASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE).func = default_wake_function が設定される。
3. add_wait_queue() - WaitQueueに追加
4. schedule() - プロセス切替え(ブロック)
5. remove_wait_queue() - Wakeupされたら、WaitQueueから削除
        6. set_current_state(TASK_RUNNING) - Running状態にする
      
その2
        1. DEFINE_WAIT()でWaitQueue用のエントリを作成
        
        
      
      
          wakeup時のコールバックルーチンは
.func = autoremove_wake_functionが設定される。
        
2. prepare_to_wait().func = autoremove_wake_functionが設定される。
          指定WaitQueueにエントリを追加
set_current_state()で状態を変更
(通常はTASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE)
        
3. schedule() - プロセス切替え(ブロック)set_current_state()で状態を変更
(通常はTASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE)
        4. finish_wait() - Wakeupされた時の後処理
        
          __set_current_state(TASK_RUNNING)でプロセスをRunning状態にしている。
        
      
        wakeup時のコールバックルーチンでWaitQueueからの削除は行われているのでここでは不要
      
各処理部でその1のような方法で止めたり、その2の方法で止めたりまちまち。その2の方が、Wakup後にWaitQueueからエントリの削除を行なう必要がないので多少楽。
プロセスのRunQueueからの削除はschedule()で行われている。
1.3 wait_on_bit()を使う場合
wait_on_bit()を使用すると指定Bitがクリアされるまでプロセスをブロックさせることができる。
        wait_on_bit(word, bit, action, mode)はwordで指定した領域のbitがクリアされるまでブロックする。ブロック処理はactionで指定される関数で行う。modeはブロック中の割込み可否(TASK_INTERRUPTIBLE/UNINTERRUPTIBLE)を指定する。
      
起床する時はwake_up_bit()で起こす。1.1, 1.2のようにブロック前、起床後の繁雑な処理はいらない。
wait_on_bit()も実装はWaitQueueを使用している。Zone毎に汎用WorkQueueのハッシュがあり(zone->wait_table[ハッシュ値])、bit_waitqueue()でハッシュテーブルからWorkQueueを取得するしている。
2.止めたプロセスの起こし方
WaitQueueを使わずにtask_structのアドレスを保存しておいて止めた場合は、wake_up_process()でtask_structを指定すればよい。WaitQueueを使用した場合は、wake_up()でWaitQueueを指定すればよい。wake_up()には派生ルーチンがあるが、どれもマクロで__wake_up()を使用している(include/linux/wait.h)。
3.Wakeupの流れ
        wake_up_process()処理
      
      
wake_up_process(&task) - 指定ProcessのWakeup
    try_to_wake_up()
        :
        SMP関連の処理
        :
        activate_task() - プロセスをRunQueue rq->active に戻す
        プロセス状態をTASK_RUNNINGに設定
        wake_up()処理
      
      
wake_up(&WaitQueue) - 指定WaitQueueの全プロセスをWakeup
    __wake_up()
        __wake_up_common()
            WaitQueueに連なっている各エントリのwakeup用
            コールバック(xxx->func())を実行してプロセスをwakeup
            DECLARE_WAITQUEUE()で作られたエントリならば
            .func = default_wake_function
                try_to_wake_up() - プロセスをRUNNING状態へ
                <-- WaitQueueからは外されないので
                   プロセス再開後、自前で外す必要がある
            DEFINE_WAIT()で作られたエントリならば
            .func = autoremove_wake_function
                default_wake_function()(デフォルトルーチン)を呼んで
                RUNNING状態にした後、WaitQueueから外す
これらのルーチンはプロセスをRunQueueにつないでRUNNING状態にするだけで、schedule自体は別途行なう。
[関連ページ]
WaitQueue
