2016-10-28 1 views
2

私はコンテキスト切り替えで面白いです。私は例のコードをファイルにコピーしました。 http://pubs.opengroup.org/onlinepubs/009695399/functions/makecontext.htmlコンテキスト切り替え - makecontextとswapcontextがここで動作していますか(OSX)

と私はOSX用に_XOPEN_SOURCEマクロを定義しました。

#define _XOPEN_SOURCE 
#include <stdio.h> 
#include <ucontext.h> 


static ucontext_t ctx[3]; 


static void 
f1 (void) 
{ 
    puts("start f1"); 
    swapcontext(&ctx[1], &ctx[2]); 
    puts("finish f1"); 
} 


static void 
f2 (void) 
{ 
    puts("start f2"); 
    swapcontext(&ctx[2], &ctx[1]); 
    puts("finish f2"); 
} 


int 
main (void) 
{ 
    char st1[8192]; 
    char st2[8192]; 


    getcontext(&ctx[1]); 
    ctx[1].uc_stack.ss_sp = st1; 
    ctx[1].uc_stack.ss_size = sizeof st1; 
    ctx[1].uc_link = &ctx[0]; 
    makecontext(&ctx[1], f1, 0); 


    getcontext(&ctx[2]); 
    ctx[2].uc_stack.ss_sp = st2; 
    ctx[2].uc_stack.ss_size = sizeof st2; 
    ctx[2].uc_link = &ctx[1]; 
    makecontext(&ctx[2], f2, 0); 


    swapcontext(&ctx[0], &ctx[2]); 
    return 0; 
} 

私は私で

のgcc -oコンテキストcontext.c -g

winges程度にし、取得するには、廃止予定されているスワップコンテキストを構築します。 Meh。

私はそれを実行するだけでハングアップします。それはクラッシュするようではありません。それはちょうどハングアップします。

私はgdbを使ってみましたが、一度swapcontextに入ると、空白になります。それはf1にジャンプしません。私はちょうど入力して打つと、それはコンソール上の新しい行にカーソルを移動しますか?

何が起こっているのでしょうか? Mac/deprecateメソッドで作業することと何か?

おかげ

それはあなたのコードのように見える

答えて

4

はただでコピー/それはイライラそれが働いていないことを確認しなければならないthe ucontext documentation、から貼り付け...私の知る限り

は、あなたのスタックがあまりにもあります小さい。私はあなたのスタックのために32KiB未満で動作するようにはできませんでした。

は、これらの変更を行ってみてください。それを固定

#define STACK_SIZE (1<<15) // 32KiB 

// . . . 

    char st1[STACK_SIZE]; 
    char st2[STACK_SIZE]; 

うん。なぜそれはそれを修正しましたか?

もう少し詳しく調べてみましょう。まず、実際に何が起こっているのかを見てみましょう。

私はそれを実行するとちょうどハングします。それはクラッシュするようではありません。それはちょうどハングアップします。あなたには、いくつかのデバッガ-FUを(ちょうどOS Xで動作しませんlldb-GDBを使用してください)を使用する場合は、アプリが「ハング」したとき、それが実際に回転していますがわかります

あなたのmain機能の奇妙なループ。下のコメントの矢印で示されています。

int 
main (void) 
{ 
    char st1[8192]; 
    char st2[8192]; 


    getcontext(&ctx[1]); 
    ctx[1].uc_stack.ss_sp = st1; 
    ctx[1].uc_stack.ss_size = sizeof st1; 
    ctx[1].uc_link = &ctx[0]; 
    makecontext(&ctx[1], f1, 0); 


    getcontext(&ctx[2]);// <---------------------+ back to here 
    ctx[2].uc_stack.ss_sp = st2;//    | 
    ctx[2].uc_stack.ss_size = sizeof st2;//  | 
    ctx[2].uc_link = &ctx[1];//     | 
    makecontext(&ctx[2], f2, 0); //    | 
    //           | 
    puts("about to swap...");//     | 
    //           | 
    swapcontext(&ctx[0], &ctx[2]);// ------------+ jumps from here 
    return 0; 
} 

ループの途中で余分なputsコールを追加しました。その行を追加してもう一度コンパイル/実行すると、プログラムの代わりに、文字列"about to swap..."を吐き出すことがわかります。

明らかに、一定のスタックサイズに基づいて何かが起こっているので、が参照されているすべての場所を探してみましょう...

(注意:アップルucontext実装はhttps://opensource.apple.com/source/であるが、それは検索やリンクのために立派なので、私が使用しますa GitHub mirrorがありますのための信頼できるソースコードを。)

を我々take a look at makecontext.cは、私たちが何かを見る場合このように:

if (ucp->uc_stack.ss_size < MINSIGSTKSZ) { 
    // fail without an error code since makecontext is a void function 
    return; 
} 

いいですね。 MINSIGSTKSZとは何ですか?さて、a look in signal.hてみましょう:

#define MINSIGSTKSZ 32768 /* (32K)minimum allowable stack */ 
#define SIGSTKSZ 131072 /* (128K)recommended stack size */ 

どうやら、これらの値は、実際にpart of the POSIX standardあります。これらの値を参照するucontextドキュメントには何も表示されませんが、それはucontext preserves the current signal maskから暗黙のうちにあると思います。

とにかく、これは私たちが見ているねじれた動作を説明しています。 の呼び出しはスタックサイズが小さすぎるために失敗しているので、getcontext(&ctx[2])への呼び出しはctx[2]の内容を設定しているため、swapcontext(&ctx[0], &ctx[2])への呼び出しは無限ループを作成し直して終了します。

興味深いことに、MINSIGSTKSZはos xでは32768バイトですが、私のLinuxボックスでは2048バイトしかないので、Linuxでは動作しますが、OS xでは動作しない理由が説明されています。

より安全なオプションがsys/signal.hから推奨スタックサイズを使用しているようにすべてのことに基づいて、それが見えます:

char st1[SIGSTKSZ]; 
char st2[SIGSTKSZ]; 

こと、または非推奨されていない何かに切り替えます。 C++を嫌う人なら、Boost.Contextをご覧ください。

+0

結構です。なぜそれはそれを修正しましたか?何がスタックサイズを増やすと思いましたか? – Prof

+1

@Prof - 私は正常にos xの前にucontextを使ってコードを実行していることを知っていたので、あなたのサンプルコードが私のLinuxボックスでは動作しましたが、os xではなく、スタックサイズが最も有望な原因でした。 – DaoWen

+0

@Prof - もう少し掘り下げましたが、小さなスタックサイズではうまくいかなかった理由の答えを更新しました。楽しい! – DaoWen

関連する問題