getcontext, setcontext -
ユーザーコンテキストを取得/設定する
#include <ucontext.h>
int getcontext(ucontext_t *ucp);
int setcontext(const ucontext_t *ucp);
System V 的な環境では、
mcontext_t および
ucontext_t
という 2 つの型と、
getcontext(),
setcontext(),
makecontext(3),
swapcontext(3) という 4
つの関数が
<ucontext.h>
で定義されており、あるプロセス内部で制御下にある複数のスレッド間で、
ユーザーレベルのコンテキスト切替えができるようになっている。
mcontext_t
型はマシン依存で、外部からは隠蔽されている。
ucontext_t
型は構造体で、少なくとも以下の
4
つのフィールドを持つ。
typedef struct ucontext_t {
struct ucontext_t *uc_link;
sigset_t uc_sigmask;
stack_t uc_stack;
mcontext_t uc_mcontext;
...
} ucontext_t;
sigset_t と
stack_t は
<signal.h>
で定義されている。
ここで
uc_link は、
現在のコンテキストが終了したとき、
続いて切り替わるコンテキストへのポインターである
(現在のコンテキストが
makecontext(3)
で生成されたものの場合)。
uc_sigmask
はこのコンテキストでブロックされている
シグナル群である (
sigprocmask(2) を見よ)。
uc_stack
はこのコンテキストが用いているスタックである
(
signalstack(2) を見よ)。
uc_mcontext
は保存されているコンテキストの
マシン特有の表現形式であり、
ここには呼び出したスレッドのマシンレジスターが格納される。
getcontext() 関数は、
ポインター
ucp
が指す構造体を、
現在アクティブなコンテキストに初期化する。
The function
setcontext() restores the user context pointed to by
ucp. A successful call does not return. The context should have been
obtained by a call of
getcontext(), or
makecontext(3), or
received as the third argument to a signal handler (see the discussion of the
SA_SIGINFO flag in
sigaction(2)).
コンテキストが
getcontext()
の呼び出しによって得られていたものの場合は、
プログラムはこの呼び出しから返った直後からのように実行を継続する。
コンテキストが
makecontext(3)
の呼び出しによって得られていたものの場合は、
プログラムの実行はその
makecontext(3)
呼び出しの第二引数で指定された関数
func
を呼び出すかたちで継続する。
func から返ると、
makecontext(3)
呼び出しの第一引数で指定されていた
ucp 構造体の
uc_link
メンバで継続する。
このメンバが NULL
だった場合は、そのスレッドは終了する。
コンテキストがシグナルハンドラーの呼び出しによって得られていたものの場合は、
古い標準によれば
「プログラムの実行はシグナルによって割り込まれた命令の次の命令から継続される」。
しかしこの文は SUSv2
で削除されたので、
現在の判断は「結果は定義されていない」である。
成功すると、
getcontext() は 0
を返し、
setcontext()
は返らない。
失敗すると、両者とも
-1 を返し、
errno
をエラーに応じて設定する。
定義されていない。
この節で使用されている用語の説明については、
attributes(7) を参照。
インターフェース |
属性 |
値 |
getcontext(), setcontext() |
Thread safety |
MT-Safe race:ucp |
SUSv2, POSIX.1-2001. POSIX.1-2008
では、移植性の問題から
getcontext()
の仕様が削除された。
代わりに、アプリケーションを
POSIX
スレッドを使って書き直すことが
推奨されている。
このメカニズムの最古の実装は、
setjmp(3)/
longjmp(3)
機構であった。
これらにはシグナルコンテキストの取り扱いが定義されていなかったので、
次の段階では
sigsetjmp(3)/
siglongjmp(3)
のペアが現われた。
現在の機構ではずっと細かな制御ができる。
一方
getcontext()
から返ったとき、
これが最初の呼び出しであったか、
それとも
setcontext()
呼び出しからのものであるかを
区別する容易な方法がなくなってしまった。
ユーザーは「しおり」機構を自分で作らなければならない。
レジスター変数は
(レジスターはリストアされてしまうので)
これをやってくれない。
シグナルが発生すると、
現在のユーザーコンテキストは保存され、
シグナルハンドラー用のコンテキストがカーネルによって生成される。
今後はハンドラーに
longjmp(3)
を使わせないこと:
この関数のコンテキスト下での動作は定義されていない。
代わりに
siglongjmp(3) か
setcontext() を使うこと。
sigaction(2),
sigaltstack(2),
sigprocmask(2),
longjmp(3),
makecontext(3),
sigsetjmp(3),
signal(7)
この man ページは Linux
man-pages
プロジェクトのリリース
5.10
の一部である。プロジェクトの説明とバグ報告に関する情報は
https://www.kernel.org/doc/man-pages/
に書かれている。