/*
 *	pcl.h
 *
 *	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で作成され、実行状態になる事も無いからです。
 */
#ifndef __PCL_H__
#define __PCL_H__
#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus
/****************************************************************************
 *	
 ****************************************************************************/
typedef struct s_coroutine* coroutine_t;	//opaque datatype
/****************************************************************************
 *	
 ****************************************************************************/
int co_thread_init();
void co_thread_cleanup();
coroutine_t co_create(void (*func)(void* data), void* data, void* stack/*NULL可*/, int stacksize/*0可*/);	//((stack!=NULL)&&(stacksize==0))は不可。それ以外の組み合わせは全て可。
void co_delete(coroutine_t co);
void co_call(coroutine_t co);
void co_resume();
void co_exit_to(coroutine_t co);
void co_exit();
coroutine_t co_current();
void* co_get_data(coroutine_t co);
void* co_set_data(coroutine_t co, void* data);
/*****************************************************************************
 *	独自拡張
 *****************************************************************************/
//{{2016/12/04追加:独自拡張としてco_create_joinable_np(),co_call_joinable_np(),co_detach_np(),co_join_np()を追加しました。
//{{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))は不可。それ以外の組み合わせは全て可。
//↓2016/12/10変更:co_create_joinable_np()の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引数は参照しません。}}
//}}2016/12/10変更:co_create_joinable_np()のfunc引数にNULLも指定出来るようにしました。
int co_call_joinable_np(coroutine_t co);
void co_detach_np(coroutine_t co);
void* co_join_np(coroutine_t co);
//}}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()を追加しました。
#define co_cleanup_push_np(routine, arg)	do { void* __co_cleanup__[3]; _co_cleanup_push_np(__co_cleanup__, (routine), (arg))
#define co_cleanup_pop_np(execute)		_co_cleanup_pop_np(__co_cleanup__, (execute)); } while(0)
void _co_cleanup_push_np(void* _cleanup[3], void (*routine)(void* arg), void* arg);	//co_cleanup_push_np()マクロが内部で使用します。アプリケーションはこの関数を直接使用しないで下さい。
void _co_cleanup_pop_np(void* _cleanup[3], int execute);				//co_cleanup_pop_np()マクロが内部で使用します。アプリケーションはこの関数を直接使用しないで下さい。
//}}2016/12/06追加:独自拡張としてco_cleanup_push_np(),co_cleanup_pop_np()を追加しました。
//{{2016/12/11追加:独自拡張としてco_cleanup_np()を追加しました。
void co_cleanup_np(coroutine_t co);
//}}2016/12/11追加:独自拡張としてco_cleanup_np()を追加しました。
//{{2016/12/14追加:独自拡張としてco_get_stack_use_np()を追加しました。
#define PCL_GET_STACK_USE	//このシンボルを定義すると、co_get_stack_use_np()が有効になります。co_get_stack_use_np()が不要ならば、この行をコメントアウトして下さい。
#ifdef  PCL_GET_STACK_USE
int co_get_stack_use_np(coroutine_t co);
#endif//PCL_GET_STACK_USE
//}}2016/12/14追加:独自拡張としてco_get_stack_use_np()を追加しました。
#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus
#endif//__GNODE_H__
