/*	
 *	clipidle.h
 *
 *	アイドルスレッド
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2014 Naoyuki Sawa
 *
 *	* Fri Jun 19 01:44:03 JST 2009 Naoyuki Sawa
 *	- 1st リリース。
 *	* Sun Jun 21 21:42:18 JST 2009 Naoyuki Sawa
 *	- clippce.cにapptm_wk変数を追加したことに伴い、残りタイムスライスの算出にapptm_wkを参照するよう変更しました。
 *	* Sun Oct 11 21:57:48 JST 2009 Naoyuki Sawa
 *	- idle_stat()関数を追加しました。
 *	* Mon Oct 12 05:55:33 JST 2009 Naoyuki Sawa
 *	- idle_exit()関数を追加しました。
 *	- idle_exit()関数の追加に伴い、idle_stub()が不要になったため削除しました。
 *	* Thu Sep 11 21:21:57 JST 2014 Naoyuki Sawa
 *	- idle_init()に、スタックサイズを指定する引数を追加しました。
 *	  これまでは、アイドルスレッドのスタックメモリを静的配列で確保していましたが、今後は、動的に確保/開放します。
 *	- スタックメモリを確保するタイミングは、idle_init()が呼ばれた時です。
 *	- スタックメモリを開放するタイミングは、古いアイドルスレッドが終了する前にidle_init()が呼ばれた時と、アイドルスレッドが終了した時です。
 *	  アイドルスレッドが終了する契機は複数有りますが、全てidle_exitを経由するので、idle_exitにてスタックメモリを開放しています。
 *	* Fri Sep 12 22:07:53 JST 2014 Naoyuki Sawa
 *	- idle_init()の引数fnにNULLを指定してアイドル処理を開放することはできなくなりました。今後は代りにidle_free()を使用してください。
 */
#ifndef __CLIP_IDLE_H__
#define __CLIP_IDLE_H__

/*****************************************************************************
 *	グローバル関数
 *****************************************************************************/

/* アイドル関数を登録します。
 * [in]
 *    //{{2014/09/12変更:idle_init()の引数fnにNULLを指定してアイドル処理を開放することはできなくなりました。今後は代りにidle_free()を使用してください。
 *    //fn		アイドル関数。NULLを指定すると、アイドル処理を実行しません。
 *    //↓2014/09/12変更:idle_init()の引数fnにNULLを指定してアイドル処理を開放することはできなくなりました。今後は代りにidle_free()を使用してください。
 *	fn		アイドル関数。NULL指定は不可です。
 *    //}}2014/09/12変更:idle_init()の引数fnにNULLを指定してアイドル処理を開放することはできなくなりました。今後は代りにidle_free()を使用してください。
 *	param		アイドル関数への、任意のパラメータ。
 *    //{{2014/09/11追加:idle_init()に、スタックサイズを指定する引数を追加しました。
 *	stack_size	スタックサイズ。(バイト数)
 *			0を指定すると、既定のスタックサイズを使用します。
 *    //}}2014/09/11追加:idle_init()に、スタックサイズを指定する引数を追加しました。
 * [note]
 *	- メインスレッドからのみ呼び出せます。
 *	- 本関数は、アイドル関数を登録するだけで、まだ、アイドル関数を起動しません。
 *	  実際に起動するのは、次回にidle_yield()、または、idle_wait()を呼んだときです。
 *	- 既にアイドル関数が起動していて、処理途中である場合に、本関数を呼び出すと、
 *	  処理途中のアイドル関数は、強制終了します。
 *	  アイドル関数が、アトミックでない処理を処理している途中にプリエンプトされ、
 *	  メインスレッドに戻った後、本関数で強制終了すると、不安定な状態になったり、
 *	  リソースリークが発生する可能性があるので、注意してください。
 * [使用例]
 *	- ユーザーにロード時間を意識させないよう、タイトル画面の裏でロード処理や圧縮展開処理を行う例です。
 *
 *		void schedule() {
 *			...
 *			idle_yield(); // 通常のyield()の代わりに、idle_yield()を使う
 *			...
 *		}
 *
 *		int load_data(void* param) {
 *			... // 時間がかかる、ロード処理や、圧縮展開処理など。プリエンプトされるので要注意!
 *			return exit_code;
 *		}
 *
 *		void app_main() {
 *    //{{2014/09/11変更:idle_init()に、スタックサイズを指定する引数を追加しました。
 *    //		idle_init(load_data, (void*)data_number); // タイトル画面の裏で、ロード処理を行うよう登録
 *    //↓2014/09/11変更:idle_init()に、スタックサイズを指定する引数を追加しました。
 *			idle_init(load_data, (void*)data_number, 0); // タイトル画面の裏で、ロード処理を行うよう登録
 *    //}}2014/09/11変更:idle_init()に、スタックサイズを指定する引数を追加しました。
 *			for(;;) {
 *				schedule();
 *				... // タイトル画面処理
 *			}
 *			exit_code = idle_wait(); // ロードしたデータを使う前に、確実にロード処理を完了する
 *			for(;;) {
 *				schedule();
 *				... // ゲーム画面処理
 *			}
 *		}
 */
//{{2014/09/11変更:idle_init()に、スタックサイズを指定する引数を追加しました。
//void idle_init(int (*fn)(void* param), void* param);
//↓2014/09/11変更:idle_init()に、スタックサイズを指定する引数を追加しました。
void idle_init(int (*fn)(void* param), void* param, int stack_size);
//}}2014/09/11変更:idle_init()に、スタックサイズを指定する引数を追加しました。

//{{2014/09/12追加:idle_init()の引数fnにNULLを指定してアイドル処理を開放することはできなくなりました。今後は代りにidle_free()を使用してください。
/* アイドル処理を開放します。
 * [note]
 *	- メインスレッドからのみ呼び出せます。
 *	- アイドル処理が実行中だった場合、アイドル処理を中断して、スタックメモリを開放します。
 *	  スタックメモリ以外のリソースは回収されないことに注意してください。
 *	  アイドル処理が独自にリソースを確保していた場合、リソースは開放されずにリークします。
 *	- アイドル処理が完了していた場合、アイドル処理の終了時に、自動的にスタックメモリが開放されているので、当関数は何も行いません。
 *	  アイドル処理が完了することが前提ならば、メインスレッドが明示的に当関数を呼び出してスタックメモリを開放する必要はありません。
 *	- アイドル処理が開始されていなかった場合も、当関数は何も行いません。
 *	⇒以上をまとめますと、『アプリケーションが明示的にidle_free()を呼び出す必要のあるケースは、ほとんど無い』と思います。
 */
void idle_free();
//}}2014/09/12追加:idle_init()の引数fnにNULLを指定してアイドル処理を開放することはできなくなりました。今後は代りにidle_free()を使用してください。

/* 残りタイムスライスでアイドル処理を実行した後、システム処理を実行します。
 * [note]
 *	- メインスレッドからのみ呼び出せます。
 *	- アイドル関数が登録されていない場合や、既に終了していた場合は、
 *	  アイドル処理を実行せずにシステム処理を実行し、残り時間をhaltします。
 *	- タイムスライスが残っていない場合は、アイドル処理を実行しません。
 *	  ユーザー処理が、常にフレーム時間を超過しているようなプログラムでは、
 *	  アイドル処理が全く実行されない場合が有り得るので、注意してください。
 */
void idle_yield();

/* アイドル処理をすべて実行し、終了コードを返します。
 * [out]
 *	戻り値		アイドル関数の戻り値。
 * [note]
 *	- メインスレッドからのみ呼び出せます。
 *	- アイドル関数が既に終了している場合は、すぐに終了コードを返します。
 *	  アイドル関数が登録されていない場合も、すぐに処理を返しますが、戻り値は未定義です。
 *	- アイドル関数が処理を終了しない、無限ループである場合は、本関数も処理を返しません。
 *	  アプリケーションは、ハングアップしてしまうので、注意してください。
 */
int idle_wait();

/* アイドル処理の実行状態を取得します。
 * [out]
 *	戻り値		アイドル処理の実行状態。
 *			アイドル関数がまだ終了していない場合は、0以外の値を返します。
 *			アイドル関数が登録されていない場合や、既に終了していた場合は、0を返します。
 * [note]
 *	- メインスレッドからのみ呼び出せます。
 *	- アプリケーションから、以下の例のように利用することを想定して、この関数を用意しました。
 *	  アプリケーションのメインループで、アイドル処理が終了するまで、別の処理を行う利用法です。
 *
 *		void app_main() {
 *			int exit_code;
 *    //{{2014/09/11変更:idle_init()に、スタックサイズを指定する引数を追加しました。
 *    //		idle_init(load_data, (void*)data_number); // 時間のかかるロード処理を、アイドル処理で実行する
 *    //↓2014/09/11変更:idle_init()に、スタックサイズを指定する引数を追加しました。
 *			idle_init(load_data, (void*)data_number, 0); // 時間のかかるロード処理を、アイドル処理で実行する
 *    //}}2014/09/11変更:idle_init()に、スタックサイズを指定する引数を追加しました。
 *			while(idle_stat()) { // アイドル処理が終了するまで…
 *				schedule() ; // この中で、アイドル処理を実行
 *				// ここで、Now Loading...アニメーション等を表示する //
 *			}
 *			//exit_code = idle_wait(); // 終了コードが必要なければ、idle_wait()を呼ばなくても構いません
 *			for(;;) {
 *				schedule();
 *				// ロードしたデータを使って、メインループを実行する //
 *			}
 *		}
 */
int idle_stat();

/* アイドル処理を終了します。
 * [in]
 *	exit_code	終了コード。
 * [note]
 *	- アイドルスレッドからのみ呼び出せます。
 *	- アイドル関数からreturnするのと同じ効果を持ちます。
 *	  アイドル関数から呼び出された関数の中から、直接、アイドル処理を終了させるために用意しました。
 *	- 本関数は、アイドルスレッドのコンテキストからのみ、呼び出し可能です。
 *	  通常のコンテキストから呼び出すと、異常動作となります。
 * [使用例]
 *	int idle_proc(void* param) { // アイドル関数
 *		idle_proc_sub1();
 *	}
 *	void idle_proc_sub1() {
 *		idle_proc_sub2();
 *	}
 *	void idle_proc_sub2() {
 *		idle_exit(123); // exit_code = 123
 *	}
 */
void idle_exit(int exit_code) __attribute__((noreturn));

#endif /*__CLIP_IDLE_H__*/

