/*
 *	pcl.c
 *
 *	Portable Coroutine Library (PCL)
 *
 *	* Wed Nov 30 21:38:22 JST 2016 Naoyuki Sawa
 *	- 1st リリース。
 *	- 「Portable Coroutine Library (PCL)」(http://xmailserver.org/libpcl.html)を参考にさせて頂きました。
 *	  関数仕様はオリジナル版と同じですが、実装は独自で、P/ECE環境とWindows環境でucontextを利用する事に特化して作成しました。
 *	  今回参考にさせて頂いた、オリジナル版のPCLを、/clip/keep/pcl-1.12.tar.7z に保存しておきました。
 *	- 今回、PCLを実装した目的は、昨日(2016/11/29)ucontext.cモジュールに実装した、Windows用のucontextをテストするためでした。
 *	  しかし、実際に使ってみた所、Windows環境では、コルーチンは使いづらいと思いました。(根本的には、ucontext自体の問題です。)
 *	  なぜなら、スレッドを切り替えずにスタックを切り替えると、プログラムがabort()で停止した時に、VC++6.0のデバッガが、abort()箇所を正しく表示出来ないようだからです。
 *	- Windows環境では、やはり、スレッドを使う(例えばcliprrs.cモジュールの、Windows版の実装のように)方が、良いかも知れません。
 *	  又は、別の方法として、abort()で停止せずに、'__asm int 3'を使うと、何故か、VC++6.0のデバッガが、abort()箇所を正しく表示出来る(?)みたいです。
 *	  しかし、abort()と'__asm int 3'で、なぜそのような違いが生じるのかが、まだ良く分かっていません。
 *	- あと、コルーチンは、Boehm GCとも相性が悪いです。
 *	  同一スレッドの中で、スタックが分断してしまう事になるので、Boehm GCがスタックの範囲を正しく判断出来ず、異常な動作になります。
 *	  この問題は、PCLやucontextだけではなく、Win32のファイバーAPI(SwitchToFiber()等)を使った場合も同様です。
 *	  解決策としては、メインのコンテキストでコルーチンを切り替える前にGC_disable()し、メインのコンテキストに戻って来たらGC_enable();GC_collect_a_little()する等です。	⇒{{2016/12/01コメント追記:Windows環境でBoehm GCを使用した場合、メインコンテキスト以外ではガーベージコレクションを停止する処理を、co_call()に追加しました。}}
 *	* Thu Dec 01 22:25:12 JST 2016 Naoyuki Sawa
 *	- コルーチンが最初にco_exit_to()で起動された場合や、レジューム後にco_exit()やco_exit_to()を経由して再アクティブ化した場合に、レジューム先が自己削除ヘルパーコルーチンになってしまう問題を修正しました。
 *	  詳細は、以下の通りです。
 *	- これまでの処理では、以下のようなアプリケーションで、問題が生じていました。
 *	  □サンプルプログラム
 *	  │coroutine_t co1, co2;
 *	  │void func1(void* data) {
 *	  │    puts("func1 called");
 *	  │    co_exit_to(co2);
 *	  │}
 *	  │void func2(void* data) {
 *	  │    puts("func2 called");
 *	  │  //co_exit();//書いても書かなくても同じ。
 *	  │}
 *	  │int app_main(int argc, char* argv[]) {
 *	  │    co_thread_init();
 *	  │    co1 = co_create(func1, NULL, NULL, 0);
 *	  │    co2 = co_create(func2, NULL, NULL, 0);
 *	  │    puts("start");
 *	  │    co_call(co1);
 *	  │    puts("end");
 *	  │    co_thread_cleanup();
 *	  │    return 0;
 *	  │}
 *	  □結果(修正前)
 *	  │start
 *	  │func1 called
 *	  │func2 called
 *	  │(ここで異常動作)
 *	  原因は、以下の通りです。
 *	  ・概念上の説明
 *	  　func1()にて、co_exit_to(co2)が実行されるまで、co2は起動していません。
 *	  　従って、co_exit_to(co2)が実行された時に、co2が初めて起動し、co2のレジューム先はco1になり、co2がco_exit()やco_resume()を使うと、co1へ戻る事になります。
 *	  　しかし、既にco1は無いので、異常動作となります。
 *	  ・実際の動作の説明
 *	  　実際には、もっと根本的な問題が生じていました。
 *	  　co_exit_to()を経由して他のコルーチンを起動すると、そのコルーチンが初めて起動する場合だけでなく、レジュームから再アクティブ化する場合も、自己削除ヘルパーコルーチンをレジューム先のコルーチンとして格納してしまっていました。
 *	  　自己削除ヘルパーコルーチンを、レジューム先のコルーチンとして格納する事自体が、根本的な問題です。
 *	  　また、自己削除ヘルパーコルーチンを、レジューム先のコルーチンとして格納しないようにするには、その代わりにどのコルーチンをレジューム先として格納するかを取り決める必要が有ります。
 *	  今回の修正では、上記の問題の解決策を検討して、上手く解決出来たと思います。
 *	  自己削除ヘルパーコルーチンを経由して、コルーチンが呼び出された場合、自己削除ヘルパーコルーチンを呼び出したコルーチン(削除されたコルーチン)の、レジューム先のコルーチンから呼び出されたと見なすのが自然です。
 *	  概念的には、呼び出された側から逆方向に見て、自己削除ヘルパーコルーチンを除いて、まだ生きているコルーチンをレジューム先とする感じです。
 *	  もっとも、上記の仕組みの関知しないところでコルーチンが削除されてしまっている可能性は有り、その場合はやはり問題が生じます。(restargetフィールドは、コルーチンがまだ生きているかどうかを、追跡していないから。)
 *	  しかし、そこまではライブラリの範疇を超えるので、アプリケーションに任せて良いと思います。
 *	  今回の修正だけで、充分、自然な動作になったと思います。
 *	  修正後は、上記のサンプルプログラムの実行結果は、以下のようになります。
 *	  □結果(修正後)
 *	  │start
 *	  │func1 called
 *	  │func2 called	←ここで、co2のリジューム先は、co1のレジューム先であった、メインコンテキストになっているので…
 *	  │end			←上手くメインコンテキストに帰ります。
 *	- 今回の修正は、オリジナル版のPCLとは異なりますが、元々オリジナル版のPCLの仕様では異常動作になっていた(と思われる)ケースに対するケアですので、変更しても問題無いと思います。
 *	* Thu Dec 01 23:02:48 JST 2016 Naoyuki Sawa
 *	- Windows環境でBoehm GCを使用した場合、メインコンテキスト以外ではガーベージコレクションを停止する処理を、co_call()に追加しました。
 *	  'Wed Nov 30 21:38:22 JST 2016'のコメントに書いた通り、一般的にコルーチンとBoehm GCは相性が悪いのですが、少なくとも当モジュールのコルーチン機能に関しては、Windows+Boehm GCの環境でも問題無く併用出来るようになったと思います。
 *	  詳細は、co_call()内のコメントを参照して下さい。
 *	- 今後、他のモジュールにおいても、(メインコンテキストを識別出来るモジュールならば)、同じ方法で対策が可能だと思います。
 *	  例えば、cliprrs.cでも同様の対策を取れば、マルチスレッド環境においても、Pthreadsを使わずにFiberやucontextでの実装が可能となり、性能改善が出来る可能性が有ります。(※要検討)
 *	* Sat Dec 03 21:41:01 JST 2016 Naoyuki Sawa
 *	- co_thread_init()が複数回呼び出されたら、2回目以降は無視する事にしました。(独自仕様)
 *	  オリジナル版のPCLでは未定義なので、独自仕様で解釈しても問題無いと思います。
 *	- 初期化する前にco_thread_cleanup()が呼び出されたら、無視する事にしました。(独自仕様)
 *	  オリジナル版のPCLでは未定義なので、独自仕様で解釈しても問題無いと思います。
 *	* Sun Dec 04 20:50:05 JST 2016 Naoyuki Sawa
 *	- コルーチンの関数の引数dataには、co_create()の引数dataに指定された値を、確実に引き渡すようにしました。
 *	  具体的には、以下の通りです。
 *	- これまで、コルーチンの関数の引数dataには、最初にこのコルーチンが起動された時点での、このコルーチンのデータとして格納されている値を引き渡していました。
 *	  そのため、コルーチンを作成した後、コルーチンを起動する前にデータを変更した場合、co_create()の引数dataに指定された値ではなく、変更後のデータが、コルーチンの関数の引数dataに引き渡されていました。
 *	  □例
 *	  │static void func(void* data) {
 *	  │    printf("%s,%s\n", data, co_get_data(co_current()));
 *	  │}
 *	  │int app_main(int argc, char* argv[]) {
 *	  │    coroutine_t co = co_create(func, "One", NULL, 0);
 *	  │    co_set_data(co, "Two");
 *	  │    co_call(co);
 *	  │    return 0;
 *	  │}
 *	  □結果(修正前)
 *	  │Two,Two
 *	  オリジナル版のPCLでも同じ挙動ではあるのですが、この挙動は明らかに不自然であり、仕様ではなくバグだと思います。
 *	  なぜならば、もし、このコルーチンのデータとして格納されている値を参照するだけならば、コルーチンの関数の先頭でco_get_data()を呼び出せば良く、コルーチンの関数の引数dataが不要であるはずだからです。
 *	- 従って、コルーチンを作成した後、コルーチンを起動する前にデータを変更した場合でも、変更後のデータではなく、コルーチンの関数の引数dataに引き渡すのが適切だと思い、そのように修正する事にしました。
 *	  □結果(修正後)
 *	  │One,Two
 *	  今回の修正より、この点において、オリジナル版のPCLとは違う挙動になってしまったのですが、問題は無いと思います。
 *	  前述の通り、オリジナル版のPCLの挙動の方が不自然(バグ?)だと思いますし、修正前の挙動に依存しているような既存のプログラムはまず無いだろうと思うからです。
 *	* Sun Dec 04 21:29:41 JST 2016 Naoyuki Sawa
 *	- 独自拡張としてco_create_joinable_np(),co_call_joinable_np(),co_detach_np(),co_join_np()を追加しました。
 *	  これらの関数は、オリジナル版のPCLには無い、独自拡張です。
 *	  関数名サフィックス'np'は、'not portable'の略です。
 *	  Pthreadsが、移植性の無い関数にサフィックス'np'を付与している流儀に倣いました。
 *	  これらの関数を追加した理由は、以下の通りです。
 *	- オリジナル版のPCLの関数だけでは、'合流'の動作が実現出来ません。
 *	  '合流'の動作を実現するためには、グローバル変数で特定のコルーチンの終了状態を管理する等、アプリケーションプログラムの処理が複雑になる問題が有りました。
 *	  そこで、'合流'の動作を簡単に実現できるようにするための、独自拡張の関数を追加する事にしました。
 *	- 今回追加した関数の動作は、概ね、pthread_create(),pthread_detach(),pthread_join()に倣いました。
 *	  Pthreadsの上記の関数と同じ感覚で、使用出来ると思います。
 *	  尚、PCL標準の関数の動作は変更していませんので、今回追加した関数を使用しなければ、PCLを利用している既存のアプリケーションの動作には影響は無いはずです。
 *	- □今回追加した関数の使用例
 *	  │void func1(void* data) {
 *	  │    printf("1"); co_resume();
 *	  │    printf("2"); co_resume();
 *	  │    co_set_data(co_current(), "3");
 *	  │}
 *	  │void func2(void* data) {
 *	  │    co_set_data(co_current(), "4"); co_resume();
 *	  │    co_set_data(co_current(), "5"); co_resume();
 *	  │    co_set_data(co_current(), "6");
 *	  │}
 *	  │void func3(void* data) {
 *	  │    printf("7"); co_resume();
 *	  │    printf("8"); co_resume();
 *	  │    printf("9");
 *	  │}
 *	  │int app_main(int argc, char* argv[]) {
 *	  │    //以下のループを繰り返して、メモリリークが発生しない事を確認した。
 *	  │    for(;;) {
 *	  │        coroutine_t co;
 *	  │        //--- func1 ---
 *	  │        co = co_create_joinable_np(func1, NULL, NULL, 0);
 *	  │        printf(co_join_np(co)); //coはco_join_np()によって解放される。    //⇒123
 *	  │        //--- func2 ---
 *	  │        co = co_create_joinable_np(func2, NULL, NULL, 0);
 *	  │        while(co_call_joinable_np(co) != -1) { printf(co_get_data(co)); } //⇒456
 *	  │        co_delete(co); //co_delete()を呼び出してcoを明示的に解放する。
 *	  │        //--- func3 ---
 *	  │        co = co_create_joinable_np(func3, NULL, NULL, 0);
 *	  │        co_detach_np(co);
 *	  │        co_call(co); co_call(co); co_call(co); //coは終了時に解放される。 //⇒789
 *	  │    }
 *	  │    return 0;
 *	  │}
 *	* Tue Dec 06 21:24:37 JST 2016 Naoyuki Sawa
 *	- 独自拡張としてco_cleanup_push_np(),co_cleanup_pop_np()を追加しました。
 *	  これらの関数は、オリジナル版のPCLには無い、独自拡張です。
 *	  関数名サフィックス'np'は、'not portable'の略です。
 *	  Pthreadsが、移植性の無い関数にサフィックス'np'を付与している流儀に倣いました。
 *	  これらの関数を追加した理由は、以下の通りです。
 *	- コルーチンの関数がco_resume()を呼び出した場合、そのco_resume()が処理を返さず、確保していたリソースがリークする可能性が有る。
 *	  また、コルーチンの処理の途中で、co_exit()を呼び出した場合、その時点で確保していたリソースの解放処理を通らない可能性が有る。
 *	  前者は、コルーチン側で対処する事は出来ない。
 *	  後者は、コルーチン側で対処する事は可能だが、見落としが発生し易い。
 *	  そこで、どちらの場合に対しても共通の仕組みで、リソースの解放を行うための、クリーンアップハンドラを登録出来るようにした。
 *	  仕組みは、Pthreadsのpthread_cleanup_push/pthread_cleanup_popを参考にした。
 *	  今回追加したco_cleanup_push_np/co_cleanup_pop_npの使い方は、ほぼ、pthread_cleanup_push/pthread_cleanup_popと似ています。
 *	  ただし、pthread_cleanup_push/pthread_cleanup_popは、スレッドを作成する側がスレッドの関数外で使用するのに対して、
 *	  co_cleanup_push_np/co_cleanup_pop_npは、コルーチンの関数内で使用するという違いがありますが、感覚的には同じだと思います。
 *	- □今回追加したマクロの使用例
 *	  │void cleanup1(void* arg) {
 *	  │    printf("cleanup1: %s\n", arg);
 *	  │    free(arg);
 *	  │}
 *	  │void func1(void* data) {
 *	  │    int i = 0;
 *	  │    char* a = strdup_printf("%d", i++);
 *	  │    co_cleanup_push_np(cleanup1, a);
 *	  │    {
 *	  │        puts(a);
 *	  │        for(;;) {
 *	  │            char* b = strdup_printf("%d", i++);
 *	  │            co_cleanup_push_np(cleanup1, b);
 *	  │            {
 *	  │                puts(b);
 *	  │                co_resume();
 *	  │            }
 *	  │          #if 0
 *	  │            free(b);
 *	  │            co_cleanup_pop_np(0);
 *	  │          #else//↑どちらでもok↓
 *	  │            co_cleanup_pop_np(1);
 *	  │          #endif
 *	  │        }
 *	  │    }
 *	  │  #if 0
 *	  │    free(a);
 *	  │    co_cleanup_pop_np(0);
 *	  │  #else//↑どちらでもok↓
 *	  │    co_cleanup_pop_np(1);
 *	  │  #endif
 *	  │}
 *	  │int app_main(int argc, char* argv[]) {
 *	  │    coroutine_t co = co_create_joinable_np(func1, NULL, NULL, 0);
 *	  │    int i;
 *	  │    //以下のループを繰り返して、メモリリークが発生しない事を確認した。
 *	  │    for(i = 0; i < 1000; i++) {
 *	  │        co_call(co);
 *	  │    }
 *	  │    co_delete(co);
 *	  │    return 0;
 *	  │}
 *	* Sat Dec 10 21:29:37 JST 2016 Naoyuki Sawa
 *	- co_create_joinable_np()のfunc引数にNULLも指定出来るようにしました。
 *	  詳細は、以下の通りです。
 *	- 当関数のfunc引数にNULLが指定された場合、合流可能,かつ,終了済みの、何もしないコルーチンを作成します。
 *	  当関数のfunc引数に何もしない関数を指定するのと動作上は同じですが、スタックメモリを確保しない分メモリが節約出来ます。
 *	- 上記の方法で作成した何もしないコルーチンを、co_call_joinable_np()に渡す事は出来ますが、co_call()に渡す事は出来ない事に注意して下さい。
 *	  これは、上記の方法で作成した何もしないコルーチン特有の制限という訳ではなく、終了したコルーチンをco_call()に渡す事は出来ないからです。
 *	- func引数がNULL可になったのはco_create_joinable_np()だけであり、co_create()のfunc引数はこれまで通りNULL不可である事に注意して下さい。
 *	  もしco_create()のfunc引数もNULL可にすると、終了済みでメモリ解放されたコルーチンを作成する事になってしまい、戻り値のポインタが定義出来なくなるからです。
 *	* Sun Dec 11 11:24:38 JST 2016 Naoyuki Sawa
 *	- 独自拡張としてco_cleanup_np()を追加しました。
 *	  これまではco_delete()の中に直接書いていた処理を、グローバル関数co_cleanup_np()に分離して、co_delete()からもco_cleanup_np()を呼び出すようにしました。
 *	  アプリケーションが明示的にco_cleanup_np()を呼び出さない限り、今回の変更はアプリケーションに対する影響は有りません。
 *	  詳細は、以下の通りです。
 *	- 通常は、直接に呼び出したco_delete()や、co_exit()から呼び出されたco_delete()の中で、当関数が自動的に呼び出されるので、アプリケーションが当関数を明示的に呼び出す必要は有りません。
 *	  当関数をグローバル関数にした目的は、コルーチンを削除する処理において、クリーンアップハンドラの実行とコンテキスト削除(co_exit()呼び出し)の間に、何か処理を行いたい場合のためです。
 *	  使用例は、clipact.c内のActObj_Free()の、2016/12/11の変更を参照して下さい。
 *	- アプリケーションが、「co_cleanup_np(co_current())」を実行した後に、co_current()に対して行える処理は、「co_exit()」「co_exit_to(移行先のコルーチン)」だけです。
 *	  アプリケーションが、「co_cleanup_np(削除するコルーチン)」を実行した後に、(削除するコルーチン)に対して行える処理は、「co_delete(削除するコルーチン)」だけです。
 *	  もし上記以外の処理を行うと、クリーンアップハンドラのプッシュとポップの対称性が崩れて、_co_cleanup_pop_np()内でエラー停止する可能性が有ります。
 *	* Sun Dec 11 13:55:50 JST 2016 Naoyuki Sawa
 *	- co_call_joinable_np()の戻り値の仕様を変更しました。
 *	  【変更前】
 *	  │コルーチンが既に終了していたら、コルーチンを実行せずに、-1(エラー)を返す。
 *	  │コルーチンがまだ終了していなければ、コルーチンを実行して、0(継続),又は,1(終了)を返す。
 *	  【変更後】
 *	  │コルーチンが既に終了していたら、コルーチンを実行せずに、-1(エラー)を返す。
 *	  │コルーチンがまだ終了していなければ、コルーチンを実行して、0(実行)を返す。今回の実行によってコルーチンが終了したかはチェックしない。
 *	- 変更した理由は、コルーチンの関数が、自分自身でco_detach_np()とco_exit()を呼び出して、リソースを解放する事も出来るようにするためです。
 *	  使用例は、clipact.c内のActObj_Free()の、2016/12/11の変更を参照して下さい。
 *	- 今回の変更によって、co_join_np()の終了タイミングが1ループ分遅れますが、実用上は問題無いと思います。
 *	  同様に、アプリケーション自身でco_call_joinable_np()の戻り値を見て終了を判断する処理の、検出タイミングが1ループ分遅れますが、これも実用上は問題無いと思います。
 *	* Wed Dec 14 21:49:23 JST 2016 Naoyuki Sawa
 *	- 独自拡張としてco_get_stack_use_np()を追加しました。
 *	  コルーチンの、スタック使用量を推定する関数です。
 *	  アプリケーションの開発中に、個々のコルーチンのスタック使用量を取得して、必要十分な容量のスタックサイズを設定するために、この関数を追加しました。
 *	  関数名は、Boehm GCの'GC_get_memory_use()'に倣いました。
 *	- ただし、co_get_stack_use_np()を実装するためには、co_create()の処理負荷が少し高くなりました。
 *	  変更前は、スタックトップにマジックナンバーを埋め込むだけで良かったのですが、変更後は、スタックの全てのワードにそのワード自身のアドレスを埋め込む必要が生じたからです。
 *	  普通は、co_create()の処理速度は重要ではないので、この程度負荷が高くなってもほとんど影響は無いと思います。
 *	  とは言え、実行自体には不要な処理である事には違いないので、もしこの程度の負荷増大も許容出来ない場合のために、co_get_stack_use_np()を無効化出来るようにしておきました。
 *	  pcl.h内で、PCL_GET_STACK_USEシンボルを定義してライブラリをビルドすると、co_get_stack_use_np()が有効になり、定義しなければ、co_get_stack_use_np()は有効になります。
 *	  2016/12/14現在は、co_get_stack_use_np()を有効にしています。
 *	  もし、上記のco_create()の負荷増大が許容出来なくなった場合は、PCL_GET_STACK_USEシンボルを定義している行をコメントアウトして、co_get_stack_use_np()を無効にして下さい。
 *	- co_get_stack_use_np()は、メインコンテキストに対しては、常に0を返します。
 *	  メインコンテキストのスタックはOSが割り当てたものであり、当モジュールでは初期化していないので、スタック使用量を推定するためのアドレスが埋め込まれていないからです。
 *	- co_get_stack_use_np()は、co_create_joinable_np()に引数func=NULLを指定して作成した何もしないコルーチンに対しても、常に0を返します。
 *	  何もしないコルーチンは、(co_create_joinable_np()に引数stacksize>0を指定したとしても)、常にスタックサイズ0で作成され、実行状態になる事も無いからです。
 */
#include "clip.h"
/****************************************************************************
 *	定数・構造体
 ****************************************************************************/
//{{2016/12/04追加:独自拡張としてco_create_joinable_np(),co_call_joinable_np(),co_detach_np(),co_join_np()を追加しました。
//s_coroutine.flags
#define PCL_FLAG_JOINABLE		(1<<0)			//合流可能	co_create_joinable_np()で作成され、co_detach_np()が呼び出されていない事を示す。
#define PCL_FLAG_JOINING		(1<<1)			//合流対象	co_join_np()の対象となっている事を示す。
#define PCL_FLAG_EXITED			(1<<2)			//終了済み	コルーチンの関数が処理を返したか、co_exit(),又は,co_exit_to()が呼び出された事を示す。
//}}2016/12/04追加:独自拡張としてco_create_joinable_np(),co_call_joinable_np(),co_detach_np(),co_join_np()を追加しました。
/*--------------------------------------------------------------------------*/
//{{2016/12/06追加:独自拡張としてco_cleanup_push_np(),co_cleanup_pop_np()を追加しました。
//クリーンアップ
struct s_coroutine_cleanup {
	void				(*routine)(void* arg);	//クリーンアップ関数
	void*				arg;			//任意の引数
	struct s_coroutine_cleanup*	next;			//クリーンアップチェインの一つ前回にプッシュしたノード	NULL=終端
};
//}}2016/12/06追加:独自拡張としてco_cleanup_push_np(),co_cleanup_pop_np()を追加しました。
/*--------------------------------------------------------------------------*/
//コルーチン
struct s_coroutine {
	ucontext_t			ucx;			//ユーザーコンテキスト
	void*				data;			//任意のデータ
	coroutine_t			caller;			//このコルーチンを呼び出したコルーチン
	coroutine_t			restarget;		//最初にこのコルーチンを起動したコルーチン,又は,前回このコルーチンがco_resume()を行った後に再アクティブ化したコルーチン
//{{2016/12/06追加:独自拡張としてco_cleanup_push_np(),co_cleanup_pop_np()を追加しました。
	struct s_coroutine_cleanup*	cleanup;		//クリーンアップチェインの一番最近にプッシュしたノード	NULL=終端
//}}2016/12/06追加:独自拡張としてco_cleanup_push_np(),co_cleanup_pop_np()を追加しました。
//{{2016/12/04追加:独自拡張としてco_create_joinable_np(),co_call_joinable_np(),co_detach_np(),co_join_np()を追加しました。
	int				flags;			//(PCL_FLAG_*)の0個以上の組み合わせ
//}}2016/12/04追加:独自拡張としてco_create_joinable_np(),co_call_joinable_np(),co_detach_np(),co_join_np()を追加しました。
};
/****************************************************************************
 *	ローカル変数
 ****************************************************************************/
static coroutine_t	co_curr;	//現在のコルーチン
static coroutine_t	co_dhelper;	//自己削除ヘルパーコルーチン
/****************************************************************************
 *	ローカル関数
 ****************************************************************************/
//スタック溢れ検査
static coroutine_t co_stack_check(coroutine_t co) {
	//スタックトップのマジックナンバーが破壊されていない事を確認する。
	if(*(void**)co->ucx.uc_stack.ss_sp != co->ucx.uc_stack.ss_sp) { DIE(); }	//スタック溢れ
	//呼び出し元の利便性のために、引数coをそのまま返す。
	return co;
}
/*--------------------------------------------------------------------------*/
//コルーチンのエントリポイント
//{{2016/12/04変更:コルーチンの関数の引数dataには、co_create()の引数dataに指定された値を、確実に引き渡すようにしました。
//static void co_runner(void (*func)(void* data)) {
//↓2016/12/04変更:コルーチンの関数の引数dataには、co_create()の引数dataに指定された値を、確実に引き渡すようにしました。
static void co_runner(void (*func)(void* data), void* data) {
//}}2016/12/04変更:コルーチンの関数の引数dataには、co_create()の引数dataに指定された値を、確実に引き渡すようにしました。
	//最初にこのコルーチンを起動したコルーチンを、次回のco_resume()の切り替え先として記憶する。
	co_curr->restarget = co_stack_check(co_stack_check(co_curr)->caller);
	//コルーチンの関数を呼び出す。
//{{2016/12/04変更:コルーチンの関数の引数dataには、co_create()の引数dataに指定された値を、確実に引き渡すようにしました。
//	(*func)(co_get_data(co_stack_check(co_curr)));
//↓2016/12/04変更:コルーチンの関数の引数dataには、co_create()の引数dataに指定された値を、確実に引き渡すようにしました。
	(*func)(data);
//}}2016/12/04変更:コルーチンの関数の引数dataには、co_create()の引数dataに指定された値を、確実に引き渡すようにしました。
	//このコルーチンを削除して、関数実行中に最後に記憶したco_resume()の切り替え先へ切り替える。
	co_exit();
}
/*--------------------------------------------------------------------------*/
//自己削除ヘルパーコルーチンの関数
static void co_del_helper(void* data) {
	for(;;) {
//{{2016/12/01変更:コルーチンが最初にco_exit_to()で起動された場合や、レジューム後にco_exit()やco_exit_to()を経由して再アクティブ化した場合に、レジューム先が自己削除ヘルパーコルーチンになってしまう問題を修正しました。
//		//co_exit_to()を呼び出したコルーチンを削除する。
//		co_delete(co_stack_check(co_curr)->caller);
//		//co_exit_to()の引数に指定されたコルーチンへ切り替える。
//		co_call(co_stack_check(co_get_data(co_stack_check(co_curr))));
//↓2016/12/01変更:コルーチンが最初にco_exit_to()で起動された場合や、レジューム後にco_exit()やco_exit_to()を経由して再アクティブ化した場合に、レジューム先が自己削除ヘルパーコルーチンになってしまう問題を修正しました。
		//co_exit_to()を呼び出したコルーチンを、削除するコルーチンとする。
		coroutine_t co_del = co_stack_check(co_stack_check(co_curr)->caller);
		//削除するコルーチンのレジューム先のコルーチンを、切り替え先のコルーチンを呼び出したコルーチンと見なすコルーチンとする。
		coroutine_t co_res = co_stack_check(co_stack_check(co_del)->restarget);
	//{{2016/12/04変更:独自拡張としてco_create_joinable_np(),co_call_joinable_np(),co_detach_np(),co_join_np()を追加しました。
	//	//削除するコルーチンを、削除する。
	//	co_delete(co_stack_check(co_del));
	//↓2016/12/04変更:独自拡張としてco_create_joinable_np(),co_call_joinable_np(),co_detach_np(),co_join_np()を追加しました。
		//削除するコルーチンが、終了済みとなった事をマークする。
		co_stack_check(co_del)->flags |= PCL_FLAG_EXITED;
		//削除するコルーチンが、合流可能でなければ…
		if(!(co_stack_check(co_del)->flags & PCL_FLAG_JOINABLE)) {
			//削除するコルーチンを、削除する。
			co_delete(co_stack_check(co_del));
		}
	//}}2016/12/04変更:独自拡張としてco_create_joinable_np(),co_call_joinable_np(),co_detach_np(),co_join_np()を追加しました。
		//切り替え先のコルーチンを呼び出したコルーチンと見なすコルーチンを、自己削除ヘルパーコルーチンのデータに格納する。(co_call()が参照する)
		//入れ替わって、自己削除ヘルパーコルーチンのデータに格納されていた、co_exit_to()の引数に指定されたコルーチンを取得して、切り替える。
		co_call(co_stack_check(co_set_data(co_stack_check(co_curr), co_stack_check(co_res))));
//}}2016/12/01変更:コルーチンが最初にco_exit_to()で起動された場合や、レジューム後にco_exit()やco_exit_to()を経由して再アクティブ化した場合に、レジューム先が自己削除ヘルパーコルーチンになってしまう問題を修正しました。
	}
}
/****************************************************************************
 *	グローバル関数
 ****************************************************************************/
//If the PCL library is built in multi-thread mode, and if multi threads are actually used, this function should be called before calling any PCL function.
//If the PCL library is built in multi-thread mode, but it is used only from one thread (the main one, likely), then it is possible to avoid to call co_thread_init().
//Returns 0 in case of success, or an negative error code in case of error.
int co_thread_init() {
	if(!co_curr) {	//{{2016/12/03追加:co_thread_init()が複数回呼び出されたら、2回目以降は無視する事にしました。(独自仕様)}}
		//メインコンテキストを作成する。(ConvertThreadToFiber()に相当する処理です。)
		co_curr = calloc(1, sizeof(struct s_coroutine));
		if(!co_curr) { DIE(); }
		co_curr->caller    = co_curr;	//co_curr->callerの初期値は何でも良いが、分かり易いようにco_curr->restargetと同じ値にしておく事にした。実際には、co_call()によってco_curr->callerが変更される前に、co_curr->callerを参照する事は無いはずである。
		co_curr->restarget = co_curr;	//"co_thread_init();co_resume();"とされても安全なように、co_curr->restargetの初期値をこのコルーチン自身としておく事にした。
		//スタック溢れ検査のために、ss_spフィールド自身を疑似的なスタックトップと見なして、マジックナンバーを埋め込む。
		co_curr->ucx.uc_stack.ss_sp = &co_curr->ucx.uc_stack.ss_sp;
		//自己削除ヘルパーコルーチンを作成する。
		co_dhelper = co_stack_check(co_create(co_del_helper, NULL, NULL, 0));
	}
	return 0;
}
/*--------------------------------------------------------------------------*/
//If the PCL library is built in multi-thread mode, and if multi threads are actually used, this function should be called before the thread exits, or whenever the thread decides it won't call the PCL functions anymore.
//A failure in calling co_thread_cleanup() will result in resource leakage by the calling application.
void co_thread_cleanup() {
	if(co_curr) {	//{{2016/12/03追加:初期化する前にco_thread_cleanup()が呼び出されたら、無視する事にしました。(独自仕様)}}
		//自己削除ヘルパーコルーチンを削除する。
		co_delete(co_stack_check(co_dhelper));
		co_dhelper = NULL;
		//メインコンテキストを削除する。(ConvertThreadToFiber()の逆に相当する処理です。)
		// - co_thread_init()を呼び出したコンテキストが、co_thread_cleanup()も呼び出す事を前提とする。
		//   言い換えると、co_thread_cleanup()が呼ばれた時のco_currは、co_thread_init()によって作成されたco_currである事を前提とする。
		//   もし、途中で作成したコルーチンがco_thread_cleanup()を呼び出した場合、動作は予測出来ない。
		free(co_stack_check(co_curr));
		co_curr = NULL;
	}
}
/*--------------------------------------------------------------------------*/
//This function creates a new coroutine.
//func is the entry point of the coroutine.
//It will be called with one arg, a void *, which holds the data passed through the data parameter.
//If func terminates, the associated coroutine is deleted.
//stack is the base of the stack this coroutine will use and stacksize its size in bytes.
//You may pass a NULL pointer for stack in which case the memory will be allocated by co_create itself.
//Both, stack and stacksize are aligned to system requirements.
//A stacksize of less then 4096 bytes will be rejected.				←当実装では、4096バイト未満のスタックサイズも許容する事にしました。P/ECE環境では、4096バイト未満のスタックサイズで充分な場合も有るからです。Windows環境でも、当関数が4096バイト未満のスタックサイズをrejectする動作に依存するようなアプリケーションは作らないと思うので、rejectしなくても問題無いと思います。
//You have to make sure, that the stack is large enough for your coroutine and possible signal handlers (see below).
//The stack will not grow! (Exception: the main coroutine uses the standard system stack which may still grow) On success, a handle (coroutine_t) for a new coroutine is returned, otherwise NULL.
coroutine_t co_create(void (*func)(void* data), void* data, void* stack/*NULL可*/, int stacksize/*0可*/) {	//((stack!=NULL)&&(stacksize==0))は不可。それ以外の組み合わせは全て可。
	struct s_coroutine* co;
#ifdef  _DEBUG
	if(!co_curr) { DIE(); }	//co_thread_init()の呼び出し忘れを早く見つけるために、ここで検査する事にしました。全ての関数で検査しなくても、ここで検査するだけで充分だと思います。一般的なアプリケーションにおいて、当モジュールの関数のうち最初に呼び出される関数は、co_create(),又は,co_create_joinable_np()だからです。co_create_joinable_np()はco_create()を呼び出すので、co_create_joinable_np()での検査も不要です。
#endif//_DEBUG
	//スタックメモリが指定されていたら…
	if(stack) {
		if(!stacksize) { DIE(); }	//スタックメモリを指定した場合は、スタックサイズは省略不可。
		//構造体のメモリを確保する。
		co = calloc(1, sizeof(struct s_coroutine));
		if(!co) { DIE(); }
	} else {
		//スタックサイズが省略されていたら、既定値とする。
		if(!stacksize) {		//スタックメモリを省略した場合は、スタックサイズも省略可能。
#ifdef  WIN32		//Win32
			stacksize = 1048576/*調整可*/;	//Windows環境では、スタックサイズの既定値を1MBとする事にした。Win32のスタックの既定値が1MBなので、多分大丈夫だと思います。4KBでは小さ過ぎて、何かAPIを呼び出すとすぐにスタック溢れが生じました。
#else //WIN32		//P/ECE,Generic
			stacksize = 4096/*調整可*/;	//P/ECE,及び,その他の環境では、スタックサイズの既定値を4KBとする事にした。P/ECEでは充分なサイズ,又は,大き過ぎだと思うので、stacksize引数でもっと小さなサイズを明示的に指定するのが望ましいです。
#endif//WIN32
		}
		//構造体とスタックのメモリを確保する。
		co = calloc(1, sizeof(struct s_coroutine) + stacksize);
		if(!co) { DIE(); }
		stack = co + 1;
	}
//{{2016/12/14追加:独自拡張としてco_get_stack_use_np()を追加しました。
#ifndef PCL_GET_STACK_USE
//}}2016/12/14追加:独自拡張としてco_get_stack_use_np()を追加しました。
	//スタック溢れ検査のために、スタックトップにマジックナンバーを埋め込む。
	*(void**)stack = stack;
//{{2016/12/14追加:独自拡張としてco_get_stack_use_np()を追加しました。
#else //PCL_GET_STACK_USE
	//スタック溢れ検査のために、スタックトップにマジックナンバーを埋め込む。
	//同時に、スタックの全てのワードに、そのワード自身のアドレスを埋め込む。
	{
		void** p = stack;
		int    n = stacksize;
		while(n >= sizeof(void*)) {
			*p = p;
			p++;	//'*p = p++'としないよう注意!!
			n -= sizeof(void*);
		}
	}
#endif//PCL_GET_STACK_USE
//}}2016/12/14追加:独自拡張としてco_get_stack_use_np()を追加しました。
	//↑マジックナンバーやアドレスを埋め込む処理と、ユーザーコンテキストを初期化する処理の順序を、逆にしないように注意せよ。
	//↓もし逆にしてしまうと、makecontext() がスタックに積んだ値を、マジックナンバーやアドレスで上書きしてしまう恐れが有る。
	//ユーザーコンテキストを初期化する。
	if(getcontext(&co->ucx)) { DIE(); }
//不要	co->ucx.uc_link          = NULL;	//calloc()でクリアされているので不要。
	co->ucx.uc_stack.ss_sp   = stack;
	co->ucx.uc_stack.ss_size = stacksize;
//{{2016/12/04変更:コルーチンの関数の引数dataには、co_create()の引数dataに指定された値を、確実に引き渡すようにしました。
//	makecontext(&co->ucx, co_runner, 1, func);
//↓2016/12/04変更:コルーチンの関数の引数dataには、co_create()の引数dataに指定された値を、確実に引き渡すようにしました。
	makecontext(&co->ucx, co_runner, 2, func, data);
//}}2016/12/04変更:コルーチンの関数の引数dataには、co_create()の引数dataに指定された値を、確実に引き渡すようにしました。
	//↑ここまでは、co_stack_check(co)が使用出来ない。
	//↓これ以降は、co_stack_check(co)が使用可能です。
	//データの初期値を格納する。
	co_stack_check(co)->data = data;
	return co_stack_check(co);
}
/*--------------------------------------------------------------------------*/
//This function deletes the given coroutine co.
//If the stack for this coroutine was allocated by co_create it will be freed.
//After a coroutine handle was passed to co_delete it is invalid and may not be used any more.
//It is invalid for a coroutine to delete itself with this function.
void co_delete(coroutine_t co) {
	if(co_stack_check(co) == co_stack_check(co_curr)) { DIE(); }	//実行状態のコルーチンを削除する事は出来ない。(別スレッドからであっても不可)
//{{2016/12/11変更:独自拡張としてco_cleanup_np()を追加しました。
////{{2016/12/06追加:独自拡張としてco_cleanup_push_np(),co_cleanup_pop_np()を追加しました。
//	//ポップされずに残っているクリーンアップハンドラが有れば…
//	while(co_stack_check(co)->cleanup) {
//		//クリーンアップチェインの先頭のノードを取り外す。
//		// - ポップされていないと言う事は、このノードを含むスタックフレームはまだ生きているはずなので、cleanupが指すメモリは有効なはずである。
//		//   このノードを含むスタックフレームが解放されるのは、当関数の最後の、free(co)を実行するタイミングである。
//		struct s_coroutine_cleanup* cleanup = co_stack_check(co)->cleanup;
//		                                      co_stack_check(co)->cleanup = cleanup->next;
//		//クリーンアップハンドラを呼び出す。
//		// - ポップされずに残っていたクリーンアップハンドラは、co_delete()を呼び出したコルーチン(co_curr)のコンテキストで、実行される事に注意せよ。
//		//   削除したコルーチン(co)のコンテキストで、実行されるのではない。
//		(*cleanup->routine)(cleanup->arg);
//	}
////}}2016/12/06追加:独自拡張としてco_cleanup_push_np(),co_cleanup_pop_np()を追加しました。
//↓2016/12/11変更:独自拡張としてco_cleanup_np()を追加しました。
	//ポップされずに残っているクリーンアップハンドラを実行する。
	// - もし、アプリケーションがco_delete()やco_exit()を呼び出す前に明示的にco_cleanup_np()を呼び出していた場合は、クリーンアップチェインは既に空になっており、以下のco_cleanup_np()呼び出しはダミー処理となる。
	co_cleanup_np(co);
//}}2016/12/11変更:独自拡張としてco_cleanup_np()を追加しました。
	//解放したコルーチンが誤って参照されるバグを検出するために、スタックトップのマジックナンバーをクリアしておく。
	*(void**)co->ucx.uc_stack.ss_sp = NULL;
	//構造体のメモリを解放する。
	// - co_create()にて構造体とスタックのメモリを確保していた場合は、以下の処理でスタックのメモリもまとめて解放される。
	free(co);	//上でマジックナンバーをクリアしているので、'free(co_stack_check(co))'としてはいけない事に注意せよ。
}
/*--------------------------------------------------------------------------*/
//This function passes execution to the given coroutine co.
//The first time the coroutine is executed, its entry point func is called, and the data parameter used during the call to co_create is passed to func.
//The current coroutine is suspended until another one restarts it with a co_call or co_resume call.
//Calling oneself returns immediately.
void co_call(coroutine_t co) {
//{{2016/12/01追加:Windows環境でBoehm GCを使用した場合、メインコンテキスト以外ではガーベージコレクションを停止する処理を、co_call()に追加しました。
#if     (defined(WIN32) && defined(GC_H))
	//切り替え前のコルーチンが、メインコンテキストならば…
	// - もし、切り替え先のコルーチンもメインコンテキストであっても、同じ処理で構いません。
	//   コンテキストが切り替わらずに、この関数の最後ですぐに'GC_enable();'されるからです。
	if(co_stack_check(co_curr)->ucx.uc_stack.ss_sp == &co_stack_check(co_curr)->ucx.uc_stack.ss_sp) {	//{{2016/12/10コメント追記:厳密に言うと、左記の判定方法では、co_thread_init()で作成したメインコンテキストだけでなく、co_create_joinable_np(NULL,～)で作成した何もしないコンテキストも、間違ってメインコンテキストと判断してしまいます。しかし、動作上は問題有りません。co_create_joinable_np(NULL,～)で作成した何もしないコンテキストは、作成時点で終了済みであり、何もしないコンテキストが現在のコンテキスト(=co_curr)になる事は、起こり得ないからです。}}
		//'GC_dont_gc'をインクリメントする。(この意味については、/clip/tool/gc.h内の'GC_dont_gc'のコメントを参照せよ)
		GC_disable();
	}
#endif//(defined(WIN32) && defined(GC_H))
//}}2016/12/01追加:Windows環境でBoehm GCを使用した場合、メインコンテキスト以外ではガーベージコレクションを停止する処理を、co_call()に追加しました。
//{{2016/12/01変更:コルーチンが最初にco_exit_to()で起動された場合や、レジューム後にco_exit()やco_exit_to()を経由して再アクティブ化した場合に、レジューム先が自己削除ヘルパーコルーチンになってしまう問題を修正しました。
//	//切り替え先のコルーチンを呼び出したコルーチンとして、切り替え元のコルーチンを格納する。										//┐
//	co_stack_check(co)->caller = co_stack_check(co_curr);							//(co_curr==co)の場合も、co->callerを書き換える必要が有る。	//│
//	//現在のコルーチンとして、切り替え先のコルーチンを格納する。														//├(co_curr==co)でも安全に動作します。
//	co_curr = co_stack_check(co);										//(co_curr==co)の場合は、ダミー処理となる。			//│
//	//ユーザーコンテキストを、切り替え元のコルーチンから切り替え先のコルーチンへ切り替える。										//│
//	if(swapcontext(&co_stack_check(co_stack_check(co)->caller)->ucx, &co_stack_check(co)->ucx)) { DIE(); }	//(co_curr==co)の場合は、ダミー処理となる。			//┘
//↓2016/12/01変更:コルーチンが最初にco_exit_to()で起動された場合や、レジューム後にco_exit()やco_exit_to()を経由して再アクティブ化した場合に、レジューム先が自己削除ヘルパーコルーチンになってしまう問題を修正しました。
	//切り替え元のコルーチンが、自己削除ヘルパーコルーチンならば…														//┐
	if(co_stack_check(co_curr) == co_stack_check(co_dhelper)) {														//│
		//切り替え先のコルーチンを呼び出したコルーチンと見なすコルーチンを、自己削除ヘルパーコルーチンのデータから取得する。						//│
		co_stack_check(co)->caller = co_stack_check(co_get_data(co_stack_check(co_curr)));		//(co_curr==co)の場合に、ここへ来る事は無いはず。		//│
	//切り替え元のコルーチンが、自己削除ヘルパーコルーチン以外ならば…													//│
	} else {																				//│
		//切り替え先のコルーチンを呼び出したコルーチンとして、切り替え元のコルーチンを格納する。									//│
		co_stack_check(co)->caller = co_stack_check(co_curr);						//(co_curr==co)の場合も、co->callerを書き換える必要が有る。	//│
	}																					//├(co_curr==co)でも安全に動作します。
	{																					//│
		//現在のコルーチンを、切り替え元のコルーチンとして取得する。													//│
		coroutine_t oco = co_stack_check(co_curr);															//│
		//現在のコルーチンとして、切り替え先のコルーチンを格納する。													//│
		co_curr = co_stack_check(co);									//(co_curr==co)の場合は、ダミー処理となる。			//│
		//ユーザーコンテキストを、切り替え元のコルーチンから切り替え先のコルーチンへ切り替える。									//│
		if(swapcontext(&co_stack_check(oco)->ucx, &co_stack_check(co)->ucx)) { DIE(); }			//(co_curr==co)の場合は、ダミー処理となる。			//│
	}																					//┘
//}}2016/12/01変更:コルーチンが最初にco_exit_to()で起動された場合や、レジューム後にco_exit()やco_exit_to()を経由して再アクティブ化した場合に、レジューム先が自己削除ヘルパーコルーチンになってしまう問題を修正しました。
	//ここで、'co_curr->restarget = co_curr->caller;'を行ってはいけません。
	//co_call()を使って他のコルーチンを呼び出した後、処理が戻って来た場合、次にco_resume()する切り替え先(=co_curr->restarget)は変化しないという仕様です。
//{{2016/12/01追加:Windows環境でBoehm GCを使用した場合、メインコンテキスト以外ではガーベージコレクションを停止する処理を、co_call()に追加しました。
#if     (defined(WIN32) && defined(GC_H))
	//切り戻し後のコルーチンが、メインコンテキストならば…
	// - '切り替え前のコルーチンが、メインコンテキストだったならば…'という条件と同義です。
	//   当関数の観点からは、当関数の開始時点のco_currと、ここでのco_currは同じだからです。
	if(co_stack_check(co_curr)->ucx.uc_stack.ss_sp == &co_stack_check(co_curr)->ucx.uc_stack.ss_sp) {	//{{2016/12/10コメント追記:厳密に言うと、左記の判定方法では、co_thread_init()で作成したメインコンテキストだけでなく、co_create_joinable_np(NULL,～)で作成した何もしないコンテキストも、間違ってメインコンテキストと判断してしまいます。しかし、動作上は問題有りません。co_create_joinable_np(NULL,～)で作成した何もしないコンテキストは、作成時点で終了済みであり、何もしないコンテキストが現在のコンテキスト(=co_curr)になる事は、起こり得ないからです。}}
		//'GC_dont_gc'をデクリメントする。(この意味については、/clip/tool/gc.h内の'GC_dont_gc'のコメントを参照せよ)
		GC_enable();
		//最小限のガーベージコレクションを行う。
		// - ここで最小限ガーベージコレクションを行う理由は、(GC_dont_gc!=0)となっている間に、別のコンテキストでリークしたメモリを回収する機会を与えるためです。
		//   一般的には、いずれメインコンテキストでmalloc()を行ってメモリ不足が検出されれば、自動的にガーベージコレクションが起動されるので、ここで最小限ガーベージコレクションを行わなくても問題有りません。
		//   しかし万一、メインコンテキストで一切malloc()を行わず、別のコンテキストだけでmalloc()を行ってメモリリークが発生しているような場合は、自動的にガーベージコレクションが起動される機会が失われます。
		//   そこで保険として、ここで最小限のガーベージコレクションを行う事にしました。
		// - ちなみに、GC_collect_a_little()の代わりに、普通のGC_gcollect()を使用しても、動作結果としては問題無いのですが、ここで毎回フルガーベージコレクションを行う事は、速度の問題が大き過ぎると思います。
		//   前述の通り、ここでは単に、ガーベージコレクションを起動する機会を与えれば十分なので、最小限ガーベージコレクションを行う、GC_collect_a_little()を使用する事にしました。
		// - 尚、GC_disable()～GC_enable()はネスト可能なので、もし呼び出し側でGC_disable()を行っていた場合は、ここでもまだ(GC_dont_gc!=0)である可能性も有ります。
		//   その場合は、GC_collect_a_little()が単に無視されるだけなので、ここでの処理は同じで問題有りません。
		//   ただし、呼び出し側にて、ガーベージコレクションが起動される機会を保障して下さい。(malloc()を使用するか、明示的にGC_gcollect()やGC_collect_a_little()を呼び出す等です。)
		GC_collect_a_little();
	}
#endif//(defined(WIN32) && defined(GC_H))
//}}2016/12/01追加:Windows環境でBoehm GCを使用した場合、メインコンテキスト以外ではガーベージコレクションを停止する処理を、co_call()に追加しました。
}
/*--------------------------------------------------------------------------*/
//This function passes execution back to the coroutine which either initially started this one or restarted it after a prior co_resume.
void co_resume() {
	//最初にこのコルーチンを起動したコルーチン,又は,前回このコルーチンがco_resume()を行った後に再アクティブ化したコルーチンへ切り替える。
	co_call(co_stack_check(co_stack_check(co_curr)->restarget));
	//今回このコルーチンがco_resume()を行った後に再アクティブ化したコルーチンを、次回のco_resume()の切り替え先として記憶する。
	co_stack_check(co_curr)->restarget = co_stack_check(co_stack_check(co_curr)->caller);
}
/*--------------------------------------------------------------------------*/
//This function does the same a co_delete(co_current()) followed by a co_call would do.
//That is, it deletes itself and then passes execution to another coroutine co.
void co_exit_to(coroutine_t co) {
	//現在のコルーチンを削除し、指定されたコルーチンへ切り替える。
	// - 現在のコルーチンを、直接削除する事は出来ない。(スタックから離れる前にスタックが解放されてしまうから)
	//   そのため、自己削除ヘルパーコルーチンを介して、現在のコルーチンの削除と、コルーチンの切り替えを行う。
	co_set_data(co_stack_check(co_dhelper), co_stack_check(co));
	co_call(co_stack_check(co_dhelper));
	DIE();	//ここへ到達する事は無いはず。
}
/*--------------------------------------------------------------------------*/
//This function does the same a co_delete(co_current()) followed by a co_resume would do.
//That is, it deletes itself and then passes execution back to the coroutine which either initially started this one or restarted it after a prior co_resume.
void co_exit() {
	//現在のコルーチンを削除し、最初にこのコルーチンを起動したコルーチン,又は,前回このコルーチンがco_resume()を行った後に再アクティブ化したコルーチンへ切り替える。
	co_exit_to(co_stack_check(co_stack_check(co_curr)->restarget));
}
/*--------------------------------------------------------------------------*/
//This function returns the currently running coroutine.
coroutine_t co_current() {
	//現在のコルーチンを返す。
	return co_stack_check(co_curr);
}
/*--------------------------------------------------------------------------*/
//This function returns the data associated with the co coroutine.
//The data associated with a coroutine is the data parameter passed to co_create().
void* co_get_data(coroutine_t co) {
	//指定されたコルーチンのデータを取得する。
	return co_stack_check(co)->data;
}
/*--------------------------------------------------------------------------*/
//Sets the data associated with the co coroutine, and returns the previously associated data.
void* co_set_data(coroutine_t co, void* data) {
	//指定されたコルーチンの、変更前のデータを取得する。
	void* odata = co_stack_check(co)->data;
	//指定されたコルーチンの、変更後のデータを格納する。
	co_stack_check(co)->data = data;
	//指定されたコルーチンの、変更前のデータを返す。
	return odata;
}
/*****************************************************************************
 *	独自拡張
 *****************************************************************************/
//{{2016/12/04追加:独自拡張としてco_create_joinable_np(),co_call_joinable_np(),co_detach_np(),co_join_np()を追加しました。
//合流可能なコルーチンを作成する。
// - PCL標準のco_create()は、合流可能でないコルーチンを作成する。
//{{2016/12/10変更:co_create_joinable_np()のfunc引数にNULLも指定出来るようにしました。
//coroutine_t co_create_joinable_np(void (*func)(void* data), void* data, void* stack/*NULL可*/, int stacksize/*0可*/) {	//((stack!=NULL)&&(stacksize==0))は不可。それ以外の組み合わせは全て可。
//	coroutine_t co = co_stack_check(co_create(func, data, stack, stacksize));			//コルーチンを作成する。この時点ではコルーチンは合流可能ではない。
//	co_stack_check(co)->flags |= PCL_FLAG_JOINABLE;							//このコルーチンを合流可能に変更する。
//	return co_stack_check(co);									//このコルーチンを返す。
//}
//↓2016/12/10変更:co_create_joinable_np()のfunc引数にNULLも指定出来るようにしました。
// - 当関数のfunc引数にNULLが指定された場合、合流可能,かつ,終了済みの、何もしないコルーチンを作成します。
//   当関数のfunc引数に何もしない関数を指定するのと動作上は同じですが、スタックメモリを確保しない分メモリが節約出来ます。
// - 上記の方法で作成した何もしないコルーチンを、co_call_joinable_np()に渡す事は出来ますが、co_call()に渡す事は出来ない事に注意して下さい。
//   これは、上記の方法で作成した何もしないコルーチン特有の制限という訳ではなく、終了したコルーチンをco_call()に渡す事は出来ないからです。
// - func引数がNULL可になったのはco_create_joinable_np()だけであり、co_create()のfunc引数はこれまで通りNULL不可である事に注意して下さい。
//   もしco_create()のfunc引数もNULL可にすると、終了済みでメモリ解放されたコルーチンを作成する事になってしまい、戻り値のポインタが定義出来なくなるからです。
coroutine_t co_create_joinable_np(void (*func/*NULL可*/)(void* data), void* data, void* stack/*NULL可*/, int stacksize/*0可*/) {	//((stack!=NULL)&&(stacksize==0))は不可。それ以外の組み合わせは全て可。	{{2016/12/10追記:func引数にNULLが指定された場合は、stack,及び,stacksize引数は参照しません。}}
	coroutine_t co;
	if(func) {											//コルーチンの関数が指定されていたら…
		co = co_stack_check(co_create(func, data, stack, stacksize));				//コルーチンを作成する。この時点ではコルーチンは合流可能ではない。
		co_stack_check(co)->flags |= PCL_FLAG_JOINABLE;						//このコルーチンを合流可能に変更する。
	} else {											//コルーチンの関数が指定されていなければ…
		co = calloc(1, sizeof(struct s_coroutine));						//構造体のメモリを確保する。
		if(!co) { DIE(); }
		co->data = data;									//データの初期値を格納する。
		co->flags |= (PCL_FLAG_JOINABLE|PCL_FLAG_EXITED);					//このコルーチンを合流可能,かつ,終了済みに変更する。
		co->ucx.uc_stack.ss_sp = &co->ucx.uc_stack.ss_sp;					//スタック溢れ検査のために、ss_spフィールド自身を疑似的なスタックトップと見なして、マジックナンバーを埋め込む。
	}
	return co_stack_check(co);									//このコルーチンを返す。
}
//}}2016/12/10変更:co_create_joinable_np()のfunc引数にNULLも指定出来るようにしました。
/*--------------------------------------------------------------------------*/
//合流可能なコルーチンの実行を試みる。
//{{2016/12/11変更:co_call_joinable_np()の戻り値の仕様を変更しました。
////コルーチンが既に終了していたら、コルーチンを実行せずに、-1(エラー)を返す。
////コルーチンがまだ終了していなければ、コルーチンを実行して、0(継続),又は,1(終了)を返す。
//↓2016/12/11変更:co_call_joinable_np()の戻り値の仕様を変更しました。
//コルーチンが既に終了していたら、コルーチンを実行せずに、-1(エラー)を返す。
//コルーチンがまだ終了していなければ、コルーチンを実行して、0(実行)を返す。今回の実行によってコルーチンが終了したかはチェックしない。
//}}2016/12/11変更:co_call_joinable_np()の戻り値の仕様を変更しました。
// - PCL標準のco_call()は、既に終了しているコルーチンに対して呼び出す事は出来ない。
int co_call_joinable_np(coroutine_t co) {
//{{2016/12/11変更:co_call_joinable_np()の戻り値の仕様を変更しました。
//	if(!(co_stack_check(co)->flags & PCL_FLAG_JOINABLE)) { DIE(); }					//合流可能でないコルーチンに対して、co_call_joinable_np()を呼び出してはいけない。
//	if(  co_stack_check(co)->flags & PCL_FLAG_EXITED   ) { return -1; }				//このコルーチンが既に終了していたら-1を返す。	←┐
//	co_call(co_stack_check(co));									//このコルーチンを実行する。			　│アプリケーションの観点では、コルーチンが終了しているかどうかを区別するだけならば、co_call_joinable_np()の戻り値が0か0以外かだけを見れば充分です。
//	if(  co_stack_check(co)->flags & PCL_FLAG_EXITED   ) { return  1; }				//このコルーチンが今まさに終了したら 1を返す。	←┤
//	                                                     { return  0; }				//このコルーチンが終了していなければ 0を返す。	←┘
//↓2016/12/11変更:co_call_joinable_np()の戻り値の仕様を変更しました。
	if(!(co_stack_check(co)->flags & PCL_FLAG_JOINABLE)) { DIE(); }					//合流可能でないコルーチンに対して、co_call_joinable_np()を呼び出してはいけない。
	if(  co_stack_check(co)->flags & PCL_FLAG_EXITED   ) { return -1; }				//このコルーチンが既に終了していたら-1を返す。
	co_call(co_stack_check(co));									//このコルーチンを実行する。
	                                                     { return  0; }				//このコルーチンを実行したならば     0を返す。今回の実行によってコルーチンが終了したかはチェックしない。
//}}2016/12/11変更:co_call_joinable_np()の戻り値の仕様を変更しました。
}
/*--------------------------------------------------------------------------*/
//合流可能なコルーチンを、合流不可能に変更する。
void co_detach_np(coroutine_t co) {
	if(!(co_stack_check(co)->flags &   PCL_FLAG_JOINABLE)) { DIE(); }				//合流可能でないコルーチンに対して、co_detach_np()を呼び出してはいけない。
	if(  co_stack_check(co)->flags &   PCL_FLAG_JOINING  ) { DIE(); }				//合流対象となっているコルーチンに対して、co_detach_np()を呼び出してはいけない。
	     co_stack_check(co)->flags &= ~PCL_FLAG_JOINABLE;						//このコルーチンを合流不可能に変更する。
	if(  co_stack_check(co)->flags &   PCL_FLAG_EXITED   ) { co_delete(co_stack_check(co)); }	//このコルーチンが既に終了していたら、このコルーチンを削除する。
}
/*--------------------------------------------------------------------------*/
//合流対象のコルーチンが終了するまで繰り返し実行し、コルーチンを削除し、最終データを返す。(=合流)
// - co_create_joinable_np()で作成した合流可能なコルーチンは、以下のいずれかの方法で削除する必要が有る。
//   │①co_detach_np()を呼び出して合流不可能に変更する。(その後、コルーチンの終了時に自動的に削除される。)
//   │②co_join_np()を呼び出してコルーチンに合流する。(co_join_np()の処理の中で、コルーチンが削除される。)
//   │③co_delete()を呼び出して明示的にコルーチンを削除する。(co_delete()は、コルーチンが合流可能かどうかに関係無く、強制的に即削除する。)
//   ただし③は、合流対象,かつ,終了済みでないコルーチンも削除してしまう可能性が有り危険である。(co_join_np()を呼び出しているコルーチンもco_delete()で削除するならば、一応動作可能ではあるが…)
//   なるべく、①,又は,②の方法で削除するのが安全です。
void* co_join_np(coroutine_t co) {
	void* data;
	if(  co_stack_check(co) == co_stack_check(co_curr)  ) { DIE(); }				//自分自身に合流する事は出来ない。
	if(!(co_stack_check(co)->flags &  PCL_FLAG_JOINABLE)) { DIE(); }				//合流可能でないコルーチンに対して、co_join_np()を呼び出してはいけません。
	if(  co_stack_check(co)->flags &  PCL_FLAG_JOINING  ) { DIE(); }				//既に合流対象となっているコルーチンに対して、co_join_np()を呼び出してはいけない。
	     co_stack_check(co)->flags |= PCL_FLAG_JOINING;						//このコルーチンが合流対象となった事をマークする。
	while(!co_call_joinable_np(co)) { /** no job **/ }						//このコルーチンが終了するまで繰り返し実行する。既に終了していた場合も同じ処理で良い。
	data = co_get_data(co_stack_check(co));								//このコルーチンの最終データを取得する。
	co_delete(co_stack_check(co));									//このコルーチンを削除する。
	return data;											//削除したコルーチンの最終データを返す。
}
//}}2016/12/04追加:独自拡張としてco_create_joinable_np(),co_call_joinable_np(),co_detach_np(),co_join_np()を追加しました。
/*--------------------------------------------------------------------------*/
//{{2016/12/06追加:独自拡張としてco_cleanup_push_np(),co_cleanup_pop_np()を追加しました。
//クリーンアップハンドラをプッシュする。
// - co_cleanup_push_np()マクロが内部で使用します。アプリケーションはこの関数を直接使用しないで下さい。
void _co_cleanup_push_np(void* _cleanup[3], void (*routine)(void* arg), void* arg) {
	static_assert(sizeof(struct s_coroutine_cleanup) == sizeof(void*[3]), "s_coroutine_cleanup構造体のサイズが不正です。");
	struct s_coroutine_cleanup* cleanup = (struct s_coroutine_cleanup*)_cleanup;
	cleanup->routine = routine;					//┬クリーンアップチェインのノードを作成する。
	cleanup->arg     = arg;						//┘
	cleanup->next    = co_stack_check(co_curr)->cleanup;		//┬クリーンアップチェインの先頭にノードを追加する。
	                   co_stack_check(co_curr)->cleanup = cleanup;	//┘
}
/*--------------------------------------------------------------------------*/
//クリーンアップハンドラをポップする。
// - co_cleanup_pop_np()マクロが内部で使用します。アプリケーションはこの関数を直接使用しないで下さい。
void _co_cleanup_pop_np(void* _cleanup[3], int execute) {
	static_assert(sizeof(struct s_coroutine_cleanup) == sizeof(void*[3]), "s_coroutine_cleanup構造体のサイズが不正です。");
	struct s_coroutine_cleanup* cleanup = (struct s_coroutine_cleanup*)_cleanup;
	if(co_stack_check(co_curr)->cleanup != cleanup) { DIE(); }	//プッシュとポップが対称である事を確認する。	当関数の引数_cleanupは、このチェックだけのために有ります。動作だけならば、チェック無しにco_stack_check(co_curr)->nextがポップするクリーンアップハンドラであると見なしても構わないのですが、非対称な(=不正な)プッシュとポップに起因するバグは発見し辛いので、確実に発見出来るように、呼び出し側がポップするクリーンアップハンドラを引数_cleanupで指定して、co_stack_check(co_curr)->nextと比較する事にしました。
	   co_stack_check(co_curr)->cleanup  = cleanup->next;		//クリーンアップチェインの先頭のノードを取り外す。
	if(execute) { (*cleanup->routine)(cleanup->arg); }		//ポップしたクリーンアップハンドラを実行するならば、クリーンアップハンドラを呼び出す。
}
//}}2016/12/06追加:独自拡張としてco_cleanup_push_np(),co_cleanup_pop_np()を追加しました。
/*--------------------------------------------------------------------------*/
//{{2016/12/11追加:独自拡張としてco_cleanup_np()を追加しました。
//ポップされずに残っているクリーンアップハンドラを、全て実行する。
// - 通常は、直接に呼び出したco_delete()や、co_exit()から呼び出されたco_delete()の中で、当関数が自動的に呼び出されるので、アプリケーションが当関数を明示的に呼び出す必要は有りません。
//   当関数をグローバル関数にした目的は、コルーチンを削除する処理において、クリーンアップハンドラの実行とコンテキスト削除(co_exit()呼び出し)の間に、何か処理を行いたい場合のためです。
//   使用例は、clipact.c内のActObj_Free()の、2016/12/11の変更を参照して下さい。
// - アプリケーションが、「co_cleanup_np(co_current())」を実行した後に、co_current()に対して行える処理は、「co_exit()」「co_exit_to(移行先のコルーチン)」だけです。
//   アプリケーションが、「co_cleanup_np(削除するコルーチン)」を実行した後に、(削除するコルーチン)に対して行える処理は、「co_delete(削除するコルーチン)」だけです。
//   もし上記以外の処理を行うと、クリーンアップハンドラのプッシュとポップの対称性が崩れて、_co_cleanup_pop_np()内でエラー停止する可能性が有ります。
void co_cleanup_np(coroutine_t co) {
	//ポップされずに残っているクリーンアップハンドラが有れば…
	while(co_stack_check(co)->cleanup) {
		//クリーンアップチェインの先頭のノードを取り外す。
		// - ポップされていないと言う事は、このノードを含むスタックフレームはまだ生きているはずなので、cleanupが指すメモリは有効なはずである。
		//   このノードを含むスタックフレームが解放されるのは、当関数の最後の、free(co)を実行するタイミングである。
		struct s_coroutine_cleanup* cleanup = co_stack_check(co)->cleanup;
		                                      co_stack_check(co)->cleanup = cleanup->next;
		//クリーンアップハンドラを呼び出す。
		// - ポップされずに残っていたクリーンアップハンドラは、当関数を呼び出したコルーチン(co_curr)のコンテキストで、実行される事に注意せよ。
		//   削除したコルーチン(co)のコンテキストで、実行されるのではない。
		(*cleanup->routine)(cleanup->arg);
	}
}
//}}2016/12/11追加:独自拡張としてco_cleanup_np()を追加しました。
/*--------------------------------------------------------------------------*/
//{{2016/12/14追加:独自拡張としてco_get_stack_use_np()を追加しました。
#ifdef  PCL_GET_STACK_USE
//コルーチンの、スタック使用量を推定する。
// - co_get_stack_use_np()は、メインコンテキストに対しては、常に0を返します。
//   co_get_stack_use_np()は、co_create_joinable_np()に引数func=NULLを指定して作成した何もしないコルーチンに対しても、常に0を返します。
int co_get_stack_use_np(coroutine_t co) {
	void** p = co_stack_check(co)->ucx.uc_stack.ss_sp;
	int    n = co_stack_check(co)->ucx.uc_stack.ss_size;
	while(n >= sizeof(void*)) {
		if(*p != p) { break; }
		p++;	//'if(*p != p++)'としないよう注意!!
		n -= sizeof(void*);
	}
	return n;
}
#endif//PCL_GET_STACK_USE
//}}2016/12/14追加:独自拡張としてco_get_stack_use_np()を追加しました。
