名 前
makecontext, swapcontext − ユ ー ザ ー コ ン テ キ ス ト を 操 作 す る
書 式
#include <ucontext.h>
void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);
int swapcontext(ucontext_t *oucp, const ucontext_t *ucp);
説 明
System V 的 な 環 境 で は 、 mcontext_t お よ び ucontext_t と い う 2 つ の 型 と 、 getcontext(3), setcontext(3), makecontext(), swapcontext() と い う 4 つ の 関 数 が <ucontext.h> で 定 義 さ れ て お り 、 あ る プ ロ セ ス 内 部 で 制 御 下 に あ る 複 数 の ス レ ッ ド 間 で 、 ユ ー ザ ー レ ベ ル の コ ン テ キ ス ト 切 替 え が で き る よ う に な っ て い る 。 こ れ ら の 型 と 、 最 初 の 2 つ の 関 数 に つ い て は 、 getcontext(3) を 参 照 の こ と 。
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 で 提 供 さ れ て い る 。
属 性
マ ル チ ス レ ッ デ ィ ン グ (pthreads(7) 参 照 ) 関 数 makecontext() と swapcontext() は ス レ ッ ド セ ー フ で あ る 。
準 拠
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 プ ロ ジ ェ ク ト の リ リ ー ス 3.79 の 一 部 で あ る 。 プ ロ ジ ェ ク ト の 説 明 と バ グ 報 告 に 関 す る 情 報 は http://www.kernel.org/doc/man−pages/ に 書 か れ て い る 。