makecontext, swapcontext -
ユーザコンテキストを操作する
#include <ucontext.h>
void makecontext(ucontext_t *ucp, void
(*func)(), int argc, ...);
int swapcontext(ucontext_t *oucp, ucontext_t
*ucp);
System V 的な環境では、
mcontext_t および
ucontext_t
という 2 つの型と、
getcontext(2),
setcontext(2),
makecontext(),
swapcontext() という 4
つの関数が
<ucontext.h>
で定義されており、あるプロセス内部で制御下にある複数のスレッド間で、
ユーザレベルのコンテキスト切替えができるようになっている。
これらの型と、最初の
2
つの関数については、
getcontext(2) を参照のこと。
makecontext()
関数は、ポインタ
ucp
が指すコンテキストを変更する
(
ucp は以前の
getcontext(2)
呼び出しで得られたものである)。
makecontext()
を起動する前には、呼び出し者は、このコンテキスト用に
新しいスタックを確保し、そのアドレスを
ucp->uc_stack に代入し、
さらに後継のコンテキストを定義し、そのアドレスを
ucp->uc_link に
代入しなければならない。
このコンテキストが将来
(
setcontext(2) または
swapcontext()
によって)
有効にされると、関数
func が呼ばれ、
引き数として
argc
以降の整数 (
int)
引き数の列が渡される。
呼び出し者は
argc
にこれらの引き数の個数を指定しなければならない。
この関数が戻ると、後継のコンテキストが有効になる。
後継コンテキストのポインタが
NULL
の場合、そのスレッドが終了する。
swapcontext()
関数は現在のコンテキストを
ポインタ
oucp
が指す構造体に保存し、
ポインタ
ucp
が指すコンテキストを有効にする。
返り値¶
成功すると、
swapcontext()
は返らない
(しかし後に
oucp
が有効になった場合には返ることがある。
このときには
swapcontext() は
0
を返すように見える。)
失敗すると、
swapcontext() は
-1 を返し、
errno
をエラーに応じて設定する。
エラー¶
- ENOMEM
- スタックに割り当てる空間が残っていない。
バージョン¶
makecontext() と
swapcontext()
は、バージョン 2.1
以降の glibc
で提供されている。
SUSv2, POSIX.1-2001. POSIX.1-2008
では、移植性の問題から
makecontext() と
swapcontext()
の仕様が削除されている。
代わりに、アプリケーションを
POSIX
スレッドを使って書き直すことが
推奨されている。
ucp->uc_stack の解釈は
sigaltstack(2)
の場合と同じである。
すなわちこの構造体には、
スタックとして用いられるメモリ領域の開始アドレスと長さが含まれ、
これはスタックが伸びる方向がどちらであるかには関係しない。
したがって、ユーザプログラムはこの件については心配しなくてよい。
int
とポインタ型が同じ大きさであるアーキテクチャでは
(x86-32
はその例であり、両方の型とも
32 ビットである)、
makecontext() の
argc
以降の引き数としてポインタを渡してもうまく動くかもしれない。
しかしながら、このようにすると、移植性は保証されず、
標準に従えば動作は未定義であり、ポインタが
int
よりも大きいアーキテクチャでは正しく動作しないことだろう。
それにも関わらず、バージョン
2.8 以降の glibc では、
makecontext()
に変更が行われ、(x86-64
などの) いくつかの 64
ビットアーキテクチャで
引き数としてポインタを渡すことができるようになっている。
以下のサンプル・プログラムは、
getcontext(2),
makecontext(),
swapcontext()
の使用方法の例を示すものである。
このプログラムを実行すると、以下のような出力が得られる:
$ ./a.out
main: swapcontext(&uctx_main, &uctx_func2)
func2: started
func2: swapcontext(&uctx_func2, &uctx_func1)
func1: started
func1: swapcontext(&uctx_func1, &uctx_func2)
func2: returning
func1: returning
main: exiting
プログラムのソース¶
#include <ucontext.h>
#include <stdio.h>
#include <stdlib.h>
static ucontext_t uctx_main, uctx_func1, uctx_func2;
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
static void
func1(void)
{
printf("func1: started\n");
printf("func1: swapcontext(&uctx_func1, &uctx_func2)\n");
if (swapcontext(&uctx_func1, &uctx_func2) == -1)
handle_error("swapcontext");
printf("func1: returning\n");
}
static void
func2(void)
{
printf("func2: started\n");
printf("func2: swapcontext(&uctx_func2, &uctx_func1)\n");
if (swapcontext(&uctx_func2, &uctx_func1) == -1)
handle_error("swapcontext");
printf("func2: returning\n");
}
int
main(int argc, char *argv[])
{
char func1_stack[16384];
char func2_stack[16384];
if (getcontext(&uctx_func1) == -1)
handle_error("getcontext");
uctx_func1.uc_stack.ss_sp = func1_stack;
uctx_func1.uc_stack.ss_size = sizeof(func1_stack);
uctx_func1.uc_link = &uctx_main;
makecontext(&uctx_func1, func1, 0);
if (getcontext(&uctx_func2) == -1)
handle_error("getcontext");
uctx_func2.uc_stack.ss_sp = func2_stack;
uctx_func2.uc_stack.ss_size = sizeof(func2_stack);
/* Successor context is f1(), unless argc > 1 */
uctx_func2.uc_link = (argc > 1) ? NULL : &uctx_func1;
makecontext(&uctx_func2, func2, 0);
printf("main: swapcontext(&uctx_main, &uctx_func2)\n");
if (swapcontext(&uctx_main, &uctx_func2) == -1)
handle_error("swapcontext");
printf("main: exiting\n");
exit(EXIT_SUCCESS);
}
関連項目¶
getcontext(2),
sigaction(2),
sigaltstack(2),
sigprocmask(2),
sigsetjmp(3)
この文書について¶
この man ページは Linux
man-pages
プロジェクトのリリース
3.41 の一部
である。プロジェクトの説明とバグ報告に関する情報は
http://www.kernel.org/doc/man-pages/
に書かれている。