名前

makecontext, swapcontext - ユーザーコンテキストを操作する

書式

#include <ucontext.h>
void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);
int swapcontext(ucontext_t *oucp, const ucontext_t *ucp );

説明

In a System V-like environment, one has the type ucontext_t (defined in <ucontext.h> and described in getcontext(3)) and the four functions getcontext(3), setcontext(3), makecontext(), and swapcontext() that allow user-level context switching between multiple threads of control within a process.
makecontext() 関数は、ポインター ucp が指すコンテキストを変更する ( ucp は以前の getcontext(3) 呼び出しで得られたものである)。 makecontext() を起動する前には、呼び出し者は、このコンテキスト用に 新しいスタックを確保し、そのアドレスを ucp->uc_stack に代入し、 さらに後継のコンテキストを定義し、そのアドレスを ucp->uc_link に 代入しなければならない。
このコンテキストが将来 ( setcontext(3) または swapcontext() によって) 有効にされると、関数 func が呼ばれ、 引数として argc 以降の整数 ( int) 引数の列が渡される。 呼び出し者は argc にこれらの引数の個数を指定しなければならない。 この関数が戻ると、後継のコンテキストが有効になる。 後継コンテキストのポインターが NULL の場合、そのスレッドが終了する。
swapcontext() 関数は現在のコンテキストを ポインター oucp が指す構造体に保存し、 ポインター ucp が指すコンテキストを有効にする。

返り値

成功すると、 swapcontext() は返らない (しかし後に oucp が有効になった場合には返ることがある。 このときには swapcontext() は 0 を返すように見える。) 失敗すると、 swapcontext() は -1 を返し、 errno をエラーに応じて設定する。

エラー

ENOMEM
スタックに割り当てる空間が残っていない。

バージョン

makecontext() と swapcontext() は、バージョン 2.1 以降の glibc で提供されている。

属性

この節で使用されている用語の説明については、 attributes(7) を参照。
インターフェース 属性
makecontext() Thread safety MT-Safe race:ucp
swapcontext() Thread safety MT-Safe race:oucp race:ucp

準拠

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(3), 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); }

関連項目

sigaction(2), sigaltstack(2), sigprocmask(2), getcontext(3), sigsetjmp(3)

この文書について

この man ページは Linux man-pages プロジェクトのリリース 5.10 の一部である。プロジェクトの説明とバグ報告に関する情報は https://www.kernel.org/doc/man-pages/ に書かれている。

Recommended readings

Pages related to swapcontext you should read also: