EN JA
SLEEPQUEUE(9)
SLEEPQUEUE(9) FreeBSD Kernel Developer's Manual SLEEPQUEUE(9)

名称

init_sleepqueues, sleepq_abort, sleepq_add, sleepq_alloc, sleepq_broadcast, sleepq_calc_signal_retval, sleepq_catch_signals, sleepq_free, sleepq_lock, sleepq_lookup, sleepq_release, sleepq_remove, sleepq_signal, sleepq_set_timeout, sleepq_set_timeout_sbt, sleepq_sleepcnt, sleepq_timedwait, sleepq_timedwait_sig, sleepq_type, sleepq_wait, sleepq_wait_sigスリープしているスレッドのキューを管理する

書式

#include < sys/param.h>
#include < sys/sleepqueue.h>

void
init_sleepqueues( void);

int
sleepq_abort( struct thread *td);

void
sleepq_add( void *wchan, struct lock_object *lock, const char *wmesg, int flags, int queue);

struct sleepqueue *
sleepq_alloc( void);

int
sleepq_broadcast( void *wchan, int flags, int pri, int queue);

int
sleepq_calc_signal_retval( int sig);

int
sleepq_catch_signals( void *wchan);

void
sleepq_free( struct sleepqueue *sq);

struct sleepqueue *
sleepq_lookup( void *wchan);

void
sleepq_lock( void *wchan);

void
sleepq_release( void *wchan);

void
sleepq_remove( struct thread *td, void *wchan);

int
sleepq_signal( void *wchan, int flags, int pri, int queue);

void
sleepq_set_timeout( void *wchan, int timo);

void
sleepq_set_timeout_sbt( void *wchan, sbintime_t sbt, sbintime_t pr, int flags);

u_int
sleepq_sleepcnt( void *wchan, int queue);

int
sleepq_timedwait( void *wchan);

int
sleepq_timedwait_sig( void *wchan, int signal_caught);

int
sleepq_type( void *wchan);

void
sleepq_wait( void *wchan);

int
sleepq_wait_sig( void *wchan);

解説

スリープキューは、いくつかの条件が満たされるまで、スレッドの実行をサスペンドするメカニズムを提供します。それぞれのキューは、それがアクティブであるときに、特定のウェートチャネルに関連しています、そして、1 つのキューだけが時間内に与えられた任意のポイントでウェートチャネルに関連しています。それぞれのウェート (待ち) チャネルの実装は、スレッドのウェークアップ (wakeup) で、いくつかの最適化を可能とするためにスリープキューを 2 つのサブキューに分割します。アクティブなキューは、関連ウェートチャネルでブロックされたスレッドのリストを保持します。ウェートチャネルでブロックされないスレッドには、関連するアクティブでないスリープキューがあります。スレッドがウェートチャネルでブロックするとき、そのアクティブでないキューをウェートチャネルに提供します。スレッドがレジューム (再開) されるとき、ブロックされているウェートチャネルは後の使用のためにアクティブでないスリープキューをそれに与えます。

sleepq_alloc() 関数は、アクティブでないスリープキューを割り付けて、スレッドの作成の間にスリープキューをスレッドに割り当てるために使用されます。 sleepq_free() 関数は、アクティブでないスリープキューに関連しているリソースを解放して、スレッドの破壊の間にキューを解放するために使用されます。

アクティブなスリープキューは、ウェートチャネルによって指されたアドレスでハッシュされたハッシュテーブルに格納されます。ハッシュテーブルの各バケットはスリープキューチェーンを含みます。スリープキューチェーンは、スピンミューテックスと特有のチェーンへのハッシュされたスリープキューのリストを含みます。アクティブなスリープキューは、それらのチェーンのスピンミューテックスによって保護されます。 init_sleepqueues() 関数は、スリープキューチェーンのハッシュ表を初期化します。

sleepq_lock() 関数は、ウェートチャネル wchan に関連しているスリープキューチェーンをロックします。

sleepq_lookup() は wchan に関連しているそのウェートチャネルのための現在のアクティブなスリープキューへのポインタを返すか、または、引数 wchan に関連しているアクティブなスリープキューがなければ、 NULL を返します。 sleepq_lock() への以前の呼び出しによってロックされている wchan に関連しているスリープキューチェーンを必要とします。

sleepq_release() 関数は、 wchan() に関連しているスリープキューチェーンをアンロックして、ウェート関数の 1 つが呼び出される前に保留中 (pending) のスリープ要求をアボート (中断) するとき、主として役に立ちます。

sleepq_add() 関数は、現在のスレッドをウェートチャネル wchan に関連しているスリープキューに置きます。引数 wchan に関連しているスリープキューチェーンは、この関数が呼び出されるとき、 sleepq_lock() への以前の呼び出しによってロックされていなければなりません。ロックが lock 引数を通して指定され、カーネルが options INVARIANTS でコンパイルされているなら、スリープキューコードは、ロックが wchan でスリープするすべてのスレッドによって使用されることを保証するために特別なチェックを実行します。 wmesg パラメータは wchan の短い記述であるべきです。 flags パラメータは、スリープしているスリープキューのタイプと 0 個以上のオプションのフラグから成るビットマスクです。 queue パラメータは、競合するスレッドが挿入される、サブキューを指定します。

現在、3 つのタイプのスリープキューがあります:

SLEEPQ_CONDVAR
条件変数を実装するために使用されるスリープキュー。
SLEEPQ_SLEEP
sleep(9), wakeup(9)wakeup_one(9) を実装するために使用されるスリープキュー。
SLEEPQ_PAUSE
pause(9) を実装するために使用されるスリープキュー。

現在、2 つのオプションフラグがあります:

SLEEPQ_INTERRUPTIBLE
現在のスレッドは割り込み可能なスリープに入っています。
SLEEPQ_STOP_ON_BDRY
スレッドが割り込み可能なスリープに入るなら、 SIGSTOP のように停止アクションの到着でもそれを停止しません。代わりにそれを起こし (wake up) ます。

スリープでのタイムアウトは、 sleepq_add() の後に sleepq_set_timeout() を呼び出すことによって、指定されます。 wchan パラメータは、 sleepq_add() への以前の呼び出しから同じ値であるべきで、 wchan に関連しているスリープキューチェーンは sleepq_lock() への以前の呼び出しによってロックされていなければなりません。 timo パラメータは、チック単位でタイムアウト値を指定するべきです。

sleepq_set_timeout_sbt() 関数は、 timo の代わりに sbt 引数を取ります。それは、 sbintime_t の形式でより高い解像度がある、相対的か、または絶対的なウェークアップ (wakeup) 時間を指定することができます。パラメータ pr によって、必要とされる絶対的なイベントの正確さを指定することができます。パラメータ flags によって、追加の callout_reset_sbt() フラグを渡すことができます。

現在のスレッドは、ウェートチャネルに設定された wchansleepq_catch_signals() を呼び出すことによって、割り込み可能であるとマークされます。この関数は、現在のスレッドのためのいくつかの保留中のシグナルがあれば、シグナル番号を返し、保留中のシグナルがないなら、0 を返します。引数 wchan に関連しているスリープキューチェーンは、 sleepq_lock() への以前の呼び出しによってロックされるべきです。

いったんスレッドがサスペンドする準備ができたなら、スリープから起こされ、別のスレッドにコンテキストスイッチされるまで、ウェート関数の 1 つは現在のスレッドをスリープするために呼び出されます。 sleepq_wait() 関数は、タイムアウトがない割り込み不可能なスリープに使用されます。 sleepq_timedwait() 関数は、 sleepq_set_timeout() を通して設定されるタイムアウトがある割り込み不可能なスリープに使用されます。 sleepq_wait_sig() 関数は、タイムアウトがない割り込み可能なスリープに使用されます。 sleepq_timedwait_sig() 関数は、設定されるタイムアウトがある割り込み可能なスリープに使用されます。ウェート関数へのすべての wchan 引数は、スリープさせられるウェートチャネルです。引数 wchan に関連しているスリープキューチェーンは、 sleepq_lock() への以前の呼び出しでロックされている必要があります。 sleepq_timedwait_sig() への signal_caught パラメータは、 sleepq_catch_signals() への以前の呼び出しが保留中のシグナルを見つけたなら、指定します。

スレッドがレジューム (再開) されるとき、ウェート関数は、スレッドがシグナルかタイムアウト以外の割り込みのため起こされたなら、0 以外を返します。スリープがタイムアウトしたなら、 EWOULDBLOCK が返されます。スリープがシグナル以外の何かで割り込まれたなら、ある他のリターン値が返されます。割り込み可能なスリープからレジュームした後に 0 が返されるなら、 sleepq_calc_signal_retval() は、スリープがシグナルによって割り込まれたかどうかを決定するために呼び出されるべきです。そうだとしたら、 sleepq_calc_signal_retval() は、割り込みシグナルが再開可能であれば ERESTART を返し、そうでなければ、 EINTR を返します。スリープがシグナルによって割り込まれなかったなら、 sleepq_calc_signal_retval() は 0 を返します。

通常、スリープスレッドは sleepq_broadcast() と sleepq_signal() 関数によってレジュームされます。 sleepq_signal() 関数は sleepq_broadcast() がウェートチャネル上でスリープするすべてのスレッドを起こしている間にウェートチャネル上でスリープしている最高の優先順位のスレッドを起こします。 wchan 引数は起こされるウェートチャネルを指定します。 flags 引数は、ウェートチャネルでスリープしているスレッドによって sleepq_add() に渡された flags 引数に含まれるスリープキュータイプに適合しなければなりません。 pri 引数が-1 と等しくないなら、起こされる各スレッドは、それが低い優先順位であるなら、 pri の優先順位を上げます。引数 wchan に関連しているスリープキューチェーンは、これらの関数のいずれかを呼び出す前に、 sleepq_lock() への以前の呼び出しによってロックされなければなりません。 queue 引数は、そこから起こされる必要があるスレッドをいれる、サブキューを指定します。

割り込み可能なスリープのスレッドは、 sleepq_abort() 関数を通して別のスレッドによって割り込まれることができます。 td 引数は、割り込みのためのスレッドを指定します。また、個々のスレッドは、 sleepq_remove() 関数を通して指定されたウェートチャネル上でスリープから起こされることができます。 td 引数は起こされるスレッドを指定、 wchan 引数はそれに起こされるウェートチャネルを指定します。スレッド td がウェートチャネル wchan でブロックされないなら、この関数はたとえスレッドが異なったウェートチャネルでスリープされても、何もしません。この関数は、上記の他の関すの 1 つが十分でない場合にだけ、使用されるべきです。 1 つの使用可能性は広く共有されたスリープチャネルから指定されたスレッドを起こすことです。

sleepq_sleepcnt() 関数は、 wchan を与えて、指定された queue のためにスリープしているスレッドの番号を検索する簡単な方法を提供します。

sleepq_type() 関数は、スリープキューに関連付けられた wchan のタイプを返します。

sleepq_abort(), sleepq_broadcast() と sleepq_signal() 関数は、すべてブール値を返します。返り値が真であるなら、現在スワップアウトされている少なくとも 1 つのスレッドがレジューム (再開) されます。呼び出し側は、レジュームされたスレッドがスワップバック (swapped back) することができるように、スケジューラのプロセスを目覚めさせることに責任があります。これは、 sleepq_release() への呼び出しを通してスリープキューのチェーンロックを解放した後に、 kick_proc0() 関数を呼び出すことによって行われます。

スリープキューインタフェースは、現在、 sleep(9)condvar(9) インタフェースを実装するために使用されます。カーネルにおける他のほとんどすべてのコードは、直接スリープキューを操作するよりむしろ、それらのインタフェースの 1 つを使用するべきです。

February 19, 2013 FreeBSD