UNIXTimer.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /*****************************************************************************/
  2. /* ここから */
  3. /*****************************************************************************/
  4. #include <unistd.h>
  5. #include <signal.h>
  6. #include "UNIXTimerP.h"
  7. #include "WonX.h"
  8. /*****************************************************************************/
  9. /* メンバ関数の定義 */
  10. /*****************************************************************************/
  11. /*---------------------------------------------------------------------------*/
  12. /* コールバック関数 */
  13. /*---------------------------------------------------------------------------*/
  14. /* pointed_unix_timer の値はいつ変化するかわからないので,最適化を禁止する */
  15. volatile static UNIXTimer pointed_unix_timer = NULL;
  16. static void UNIXTimer_CallBackFunction(int argument)
  17. {
  18. int ret;
  19. int old;
  20. /*
  21. * static なフラグを立てて,コールバック関数からコールバック関数が
  22. * 呼ばれたのを検出するのが必要かも.
  23. */
  24. if (pointed_unix_timer == NULL) return;
  25. if (!pointed_unix_timer->timer_on) return;
  26. if (pointed_unix_timer->pause) {
  27. pointed_unix_timer->interrupt_in_pause++;
  28. if (pointed_unix_timer->interrupt_in_pause > 1000) {
  29. WonX_Error("UNIXTimer_CallBackFunction", "interrupt count is too much.");
  30. }
  31. } else {
  32. if (pointed_unix_timer->interrupt_in_pause == 0)
  33. pointed_unix_timer->interrupt_in_pause = 1;
  34. while (pointed_unix_timer->interrupt_in_pause > 0) {
  35. pointed_unix_timer->interrupt_in_pause--;
  36. if (pointed_unix_timer->callback != NULL) {
  37. /*
  38. * コールバック関数の中から UNIXTimer_Unpause() などが呼ばれて,
  39. * そこからさらにコールバック関数が呼ばれたりしたときのために,
  40. * ポーズする.またこのとき,interrupt_in_pause がインクリメント
  41. * されると無限ループに陥ってしまう可能性がある(?)ので,
  42. * interrupt_in_pause を保存してコールバック関数の実行後に元に戻す.
  43. */
  44. pointed_unix_timer->pause++;
  45. old = pointed_unix_timer->interrupt_in_pause;
  46. ret = (*pointed_unix_timer->callback)(pointed_unix_timer->parameter);
  47. pointed_unix_timer->pause--;
  48. pointed_unix_timer->interrupt_in_pause = old;
  49. /*
  50. * コールバック関数の中で UNIXTimer_* 関連の関数が呼び出されると,
  51. * ここで UNIXTimer オブジェクトの状態が変わってしまう可能性がある.
  52. */
  53. /*
  54. * 以下の処理は同じことを関数の先頭でやっているので,
  55. * 最適化されて削除されないように注意すること.
  56. */
  57. if (pointed_unix_timer == NULL) return;
  58. if (!pointed_unix_timer->timer_on) return;
  59. if (ret) {
  60. pointed_unix_timer->interrupt_in_pause = 0;
  61. UNIXTimer_OFF(pointed_unix_timer);
  62. return;
  63. }
  64. /*
  65. * コールバック関数中で,ポーズの状態が切り替わってしまった
  66. * ときのため.
  67. * 以下の処理は同じようなことをちょっと前にやっているので,
  68. * 最適化されて削除されないように注意すること.
  69. */
  70. if (pointed_unix_timer->pause) break;
  71. }
  72. }
  73. }
  74. if (pointed_unix_timer->auto_preset)
  75. UNIXTimer_ON(pointed_unix_timer);
  76. else
  77. UNIXTimer_OFF(pointed_unix_timer);
  78. return;
  79. }
  80. /*---------------------------------------------------------------------------*/
  81. /* タイマの ON, OFF */
  82. /*---------------------------------------------------------------------------*/
  83. /*
  84. * このあたりの処理は,処理中にタイマ割り込みが発生しないかどうかを
  85. * 常に注意すること.でないと不可解なバグの原因になる.
  86. */
  87. int UNIXTimer_ON(UNIXTimer unix_timer)
  88. {
  89. int t;
  90. unix_timer->timer_on = 1;
  91. pointed_unix_timer = unix_timer;
  92. /*
  93. * SIGALRM を使用するので,sleep() 中にアラームが起きた場合には,
  94. * コールバック関数からの復帰後に sleep() の残り時間は継続されない.
  95. */
  96. signal(SIGALRM, UNIXTimer_CallBackFunction);
  97. #if 0 /* use ualarm() */
  98. /* ualarm(); の引数に0を用いてはダメなので */
  99. t = unix_timer->interval * 1000;
  100. if (t < 1) t = 1;
  101. ualarm(t, 0);
  102. #else /* use alarm() */
  103. /* alarm(); の引数に0を用いてはダメなので */
  104. t = unix_timer->interval / 1000;
  105. if (t < 1) t = 1;
  106. alarm(t);
  107. #endif
  108. return (0);
  109. }
  110. int UNIXTimer_OFF(UNIXTimer unix_timer)
  111. {
  112. alarm(0); /* タイマを無効にする */
  113. unix_timer->timer_on = 0;
  114. pointed_unix_timer = NULL;
  115. return (0);
  116. }
  117. int UNIXTimer_IsON(UNIXTimer unix_timer)
  118. { return (unix_timer->timer_on != 0); }
  119. int UNIXTimer_IsOFF(UNIXTimer unix_timer)
  120. { return (unix_timer->timer_on == 0); }
  121. /*---------------------------------------------------------------------------*/
  122. /* 一時停止 */
  123. /*---------------------------------------------------------------------------*/
  124. /*
  125. * 関数の先頭と末尾を Pause, Unpause でくくるばあいなどは,
  126. * 関数から関数を呼び出したときに,2重 Pause, Unpause が起きるので
  127. * 注意すること.(ただし,ポーズはネストできる)
  128. */
  129. /*
  130. * ポーズはネストされるので,UNIXTimer_Unpause() を安易に繰り返し呼んだり
  131. * しないように注意すること.
  132. */
  133. /*
  134. * このあたりの処理は,処理中にタイマ割り込みが発生しないかどうかを
  135. * 常に注意すること.でないと不可解なバグの原因になる.
  136. */
  137. int UNIXTimer_Pause(UNIXTimer unix_timer)
  138. {
  139. unix_timer->pause++; /* ポーズはネストできる */
  140. return (0);
  141. }
  142. int UNIXTimer_Unpause(UNIXTimer unix_timer)
  143. {
  144. if (unix_timer->pause == 0)
  145. WonX_Error("UNIXTimer_Unpause", "Duplicated unpause.");
  146. if (unix_timer->pause < 0)
  147. WonX_Error("UNIXTimer_Unpause", "Invalid pause.");
  148. if (unix_timer->pause == 1) {
  149. if (unix_timer->interrupt_in_pause > 0) {
  150. /*
  151. * 万が一,ここでタイマ割り込みが発生しても,
  152. * unix_timer->pause は 1 なので,コールバック関数は呼ばれないので,
  153. * 問題無し.
  154. * オートプリセットならば,べつに問題無し.
  155. * オートプリセットでなければ timer_on フラグが落ちるので,問題無い.
  156. */
  157. /*
  158. * 処理中にタイマ割り込みが発生すると面倒なので,
  159. * タイマをいったん無効にする.
  160. */
  161. alarm(0);
  162. /*
  163. * 状態値を変更する直前・直後で割り込みが入ると面倒なので,
  164. * 割り込みをOFFにしてからデクリメントする.
  165. */
  166. /* コールバック関数を呼ぶ前に,pause フラグを無効にする */
  167. unix_timer->pause--; /* ポーズはネストできる */
  168. /* コールバック関数の呼び出し */
  169. UNIXTimer_CallBackFunction(0);
  170. } else {
  171. if (unix_timer->interrupt_in_pause < 0)
  172. WonX_Error("UNIXTimer_Unpause", "Invalid interrupt_in_pause.");
  173. unix_timer->pause--; /* ポーズはネストできる */
  174. }
  175. } else {
  176. unix_timer->pause--; /* ポーズはネストできる */
  177. }
  178. return (0);
  179. }
  180. int UNIXTimer_IsPause(UNIXTimer unix_timer)
  181. { return (unix_timer->pause != 0); }
  182. /*---------------------------------------------------------------------------*/
  183. /* オートプリセット */
  184. /*---------------------------------------------------------------------------*/
  185. int UNIXTimer_SetAutoPreset(UNIXTimer unix_timer)
  186. { return (unix_timer->auto_preset = 1); }
  187. int UNIXTimer_ResetAutoPreset(UNIXTimer unix_timer)
  188. { return (unix_timer->auto_preset = 0); }
  189. int UNIXTimer_IsAutoPreset(UNIXTimer unix_timer)
  190. { return (unix_timer->auto_preset != 0); }
  191. /*---------------------------------------------------------------------------*/
  192. /* インターバル */
  193. /*---------------------------------------------------------------------------*/
  194. int UNIXTimer_GetInterval(UNIXTimer unix_timer)
  195. { return (unix_timer->interval); }
  196. int UNIXTimer_SetInterval(UNIXTimer unix_timer, int interval)
  197. { return (unix_timer->interval = interval); }
  198. /*---------------------------------------------------------------------------*/
  199. /* コールバック関数の呼び出し時のパラメータ */
  200. /*---------------------------------------------------------------------------*/
  201. void * UNIXTimer_GetParameter(UNIXTimer unix_timer)
  202. { return (unix_timer->parameter); }
  203. void * UNIXTimer_SetParameter(UNIXTimer unix_timer, void * parameter)
  204. { return (unix_timer->parameter = parameter); }
  205. /*---------------------------------------------------------------------------*/
  206. /* コールバック関数の取得・登録 */
  207. /*---------------------------------------------------------------------------*/
  208. UNIXTimerCallBack UNIXTimer_GetCallBack(UNIXTimer unix_timer)
  209. { return (unix_timer->callback); }
  210. UNIXTimerCallBack UNIXTimer_SetCallBack(UNIXTimer unix_timer,
  211. UNIXTimerCallBack callback)
  212. { return (unix_timer->callback = callback); }
  213. /*---------------------------------------------------------------------------*/
  214. /* オブジェクトの作成 */
  215. /*---------------------------------------------------------------------------*/
  216. UNIXTimer UNIXTimer_Create(int auto_preset, int interval, void * parameter,
  217. UNIXTimerCallBack callback)
  218. {
  219. UNIXTimer unix_timer;
  220. unix_timer = (UNIXTimer)malloc(sizeof(_UNIXTimer));
  221. if (unix_timer == NULL)
  222. WonX_Error("UNIXTimer_Create", "Cannot allocate memory.");
  223. unix_timer->timer_on = 0;
  224. unix_timer->pause = 0;
  225. unix_timer->interrupt_in_pause = 0;
  226. unix_timer->auto_preset = 0;
  227. unix_timer->interval = 0;
  228. unix_timer->parameter = NULL;
  229. unix_timer->callback = NULL;
  230. if (auto_preset) UNIXTimer_SetAutoPreset(unix_timer);
  231. else UNIXTimer_ResetAutoPreset(unix_timer);
  232. UNIXTimer_SetInterval(unix_timer, interval);
  233. UNIXTimer_SetParameter(unix_timer, parameter);
  234. UNIXTimer_SetCallBack(unix_timer, callback);
  235. return (unix_timer);
  236. }
  237. /*---------------------------------------------------------------------------*/
  238. /* オブジェクトの削除 */
  239. /*---------------------------------------------------------------------------*/
  240. /*
  241. * このあたりの処理は,処理中にタイマ割り込みが発生しないかどうかを
  242. * 常に注意すること.でないと不可解なバグの原因になる.
  243. */
  244. UNIXTimer UNIXTimer_Destroy(UNIXTimer unix_timer)
  245. {
  246. if (unix_timer == NULL)
  247. WonX_Error("UNIXTimer_Destroy", "Object is not created.");
  248. UNIXTimer_OFF(unix_timer);
  249. free(unix_timer);
  250. return (NULL);
  251. }
  252. /*****************************************************************************/
  253. /* ここまで */
  254. /*****************************************************************************/
  255. /*****************************************************************************/
  256. /* End of File. */
  257. /*****************************************************************************/