source: asp_wo_cfg/trunk/target/macosx_gcc/target_timer.c@ 49

Last change on this file since 49 was 49, checked in by ertl-hiro, 12 years ago

asp_wo_kernelをコミット。

  • Property svn:keywords set to Id
File size: 11.8 KB
Line 
1/*
2 * TOPPERS/ASP Kernel
3 * Toyohashi Open Platform for Embedded Real-Time Systems/
4 * Advanced Standard Profile Kernel
5 *
6 * Copyright (C) 2005-2012 by Embedded and Real-Time Systems Laboratory
7 * Graduate School of Information Science, Nagoya Univ., JAPAN
8 *
9 * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
10 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
11 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
12 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
13 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
14 * スコード中に含まれていること.
15 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
16 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
17 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
18 * の無保証規定を掲載すること.
19 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
20 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
21 * と.
22 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
23 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
24 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
25 * 報告すること.
26 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
27 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
28 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
29 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
30 * 免責すること.
31 *
32 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
33 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
34 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
35 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
36 * の責任を負わない.
37 *
38 * @(#) $Id: target_timer.c 49 2012-09-06 04:41:53Z ertl-hiro $
39 */
40
41/*
42 * タイマドライバ(Mac OS X用)
43 */
44
45#include "kernel_impl.h"
46#include "time_event.h"
47#include <sys/time.h>
48#include "target_timer.h"
49
50/*
51 * タイマ割込みの登録処理
52 */
53Inline void
54target_timer_register_int(void)
55{
56 T_CINT cint;
57 T_DINH dinh;
58 ER ercd;
59
60 /*
61 * タイマドライバの初期化処理(target_timer.cfg相当の処理)
62 *
63 * CFG_INT(INTNO_TIMER, { TA_ENAINT | INTATR_TIMER, INTPRI_TIMER });
64 * DEF_INH(INHNO_TIMER, { TA_NULL, target_timer_handler });
65 */
66 cint.intatr = TA_ENAINT | INTATR_TIMER;
67 cint.intpri = INTPRI_TIMER;
68 ercd = cfg_int(INTNO_TIMER, &cint);
69 assert(ercd == E_OK);
70
71 dinh.inhatr = TA_NULL;
72 dinh.inthdr = target_timer_handler;
73 ercd = def_inh(INHNO_TIMER, &dinh);
74 assert(ercd == E_OK);
75}
76
77#ifndef TOPPERS_SUPPORT_OVRHDR
78
79/*
80 * オーバランハンドラ機能をサポートしない場合
81 */
82
83#if 0
84/*
85 * インターバルタイマを周期タイマとして使用する方法
86 *
87 * インターバルタイマを周期タイマとして使用するのが素直であるが,現在
88 * のMac OS Xでは,SIGALRMの配送が遅延することがあるためか,タイマが次
89 * の周期に進んだにもかかわらず,SIGALRMの配送がsigpendingで検出できな
90 * い場合がある.これにより,性能評価用システム時刻の参照が正しく動作
91 * しないため,このコードは使用していない.
92 */
93
94/*
95 * タイマの起動処理
96 */
97void
98target_timer_initialize(intptr_t exinf)
99{
100 CLOCK cyc = TO_CLOCK(TIC_NUME, TIC_DENO);
101 struct itimerval val;
102
103 /*
104 * タイマ割込みの登録処理
105 */
106 target_timer_register_int();
107
108 /*
109 * タイマ周期を設定し,タイマの動作を開始する.
110 */
111 assert(cyc <= MAX_CLOCK);
112 val.it_interval.tv_sec = 0;
113 val.it_interval.tv_usec = cyc;
114 val.it_value = val.it_interval;
115 setitimer(ITIMER_REAL, &val, NULL);
116}
117
118/*
119 * タイマの停止処理
120 */
121void
122target_timer_terminate(intptr_t exinf)
123{
124 struct itimerval val;
125
126 /*
127 * タイマの動作を停止する.
128 */
129 val.it_interval.tv_sec = 0;
130 val.it_interval.tv_usec = 0;
131 val.it_value = val.it_interval;
132 setitimer(ITIMER_REAL, &val, NULL);
133}
134
135/*
136 * タイマの現在値の読出し
137 */
138CLOCK
139target_timer_get_current(void)
140{
141 struct itimerval val;
142
143 getitimer(ITIMER_REAL, &val);
144 return(TO_CLOCK(TIC_NUME, TIC_DENO) - val.it_value.tv_usec);
145}
146
147/*
148 * タイマ割込み要求のチェック
149 */
150bool_t
151target_timer_probe_int(void)
152{
153 return(x_probe_int(INTNO_TIMER));
154}
155
156/*
157 * タイマ割込みハンドラ
158 */
159void
160target_timer_handler(void)
161{
162 i_begin_int(INTNO_TIMER);
163 signal_time(); /* タイムティックの供給 */
164 i_end_int(INTNO_TIMER);
165}
166
167#else /* 0 */
168/*
169 * インターバルタイマをワンショットタイマとして使用する方法
170 */
171
172/*
173 * タイマの動作開始
174 */
175Inline void
176itimer_start(void)
177{
178 CLOCK cyc = TO_CLOCK(TIC_NUME, TIC_DENO);
179 struct itimerval val;
180
181 /*
182 * タイマ周期を設定し,タイマの動作を開始する.
183 */
184 assert(cyc <= MAX_CLOCK);
185 val.it_interval.tv_sec = 0;
186 val.it_interval.tv_usec = 0;
187 val.it_value.tv_sec = 0;
188 val.it_value.tv_usec = cyc;
189 setitimer(ITIMER_REAL, &val, NULL);
190}
191
192/*
193 * タイマの起動処理
194 */
195void
196target_timer_initialize(intptr_t exinf)
197{
198 target_timer_register_int();
199 itimer_start();
200}
201
202/*
203 * タイマの停止処理
204 */
205void
206target_timer_terminate(intptr_t exinf)
207{
208 struct itimerval val;
209
210 /*
211 * タイマの動作を停止する.
212 */
213 val.it_interval.tv_sec = 0;
214 val.it_interval.tv_usec = 0;
215 val.it_value = val.it_interval;
216 setitimer(ITIMER_REAL, &val, NULL);
217}
218
219/*
220 * タイマの現在値の読出し
221 */
222CLOCK
223target_timer_get_current(void)
224{
225 struct itimerval val;
226
227 getitimer(ITIMER_REAL, &val);
228 return(TO_CLOCK(TIC_NUME, TIC_DENO) - val.it_value.tv_usec);
229}
230
231/*
232 * タイマ割込み要求のチェック
233 */
234bool_t
235target_timer_probe_int(void)
236{
237 return(false);
238}
239
240/*
241 * タイマ割込みハンドラ
242 */
243void
244target_timer_handler(void)
245{
246 i_begin_int(INTNO_TIMER);
247 i_lock_cpu();
248 itimer_start();
249 i_unlock_cpu();
250 signal_time(); /* タイムティックの供給 */
251 i_end_int(INTNO_TIMER);
252}
253
254#endif /* 0 */
255#else /* TOPPERS_SUPPORT_OVRHDR */
256
257/*
258 * オーバランハンドラ機能をサポートする場合
259 *
260 * タイムティック供給のためのタイマ(ティックタイマ)とオーバランハン
261 * ドラ機能のためのタイマ(オーバランタイマ)を,1つのインターバルタイ
262 * マを多重化して実現している.この方法は,ティックの周期がずれるため
263 * に推奨できないが,マイクロ秒精度のタイマが1つしかなく,シミュレーショ
264 * ン環境でティック周期のずれは大きい問題ではないため,この方法を採用
265 * している.
266 */
267#include "task.h"
268#include "overrun.h"
269
270static CLOCK ticktimer_cyc; /* ティックタイマの周期 */
271
272static bool_t itimer_ticktimer; /* インターバルタイマに
273 ティックタイマが設定されている */
274static CLOCK ticktimer_left; /* ティックタイマの残り時間 */
275static bool_t ovrtimer_active; /* オーバランタイマが有効 */
276static OVRTIM ovrtimer_left; /* オーバランタイマの残り時間 */
277
278#define CLOCK_TO_OVRTIM(clock) ((OVRTIM) clock)
279#define OVRTIM_TO_CLOCK(ovrtim) ((CLOCK) ovrtim)
280
281static const struct itimerval itimerval_stop = {{ 0, 0 }, { 0, 0 }};
282
283/*
284 * タイマの動作開始
285 */
286Inline void
287itimer_start(void)
288{
289 struct itimerval val;
290
291 /*
292 * タイマを設定し,タイマの動作を開始する.
293 */
294 if (!ovrtimer_active || CLOCK_TO_OVRTIM(ticktimer_left) <= ovrtimer_left) {
295 val.it_value.tv_sec = 0;
296 val.it_value.tv_usec = ticktimer_left;
297 itimer_ticktimer = true;
298 }
299 else {
300 val.it_value.tv_sec = 0;
301 val.it_value.tv_usec = OVRTIM_TO_CLOCK(ovrtimer_left);
302 itimer_ticktimer = false;
303 }
304 val.it_interval.tv_sec = 0;
305 val.it_interval.tv_usec = 0;
306 setitimer(ITIMER_REAL, &val, NULL);
307}
308
309/*
310 * タイマの動作停止
311 */
312Inline void
313itimer_stop(void)
314{
315 struct itimerval val;
316 CLOCK left;
317
318 /*
319 * タイマの動作を停止し,その時点の残り時間をleftに取り出す.残り
320 * 時間が0になっていれば1に読み換える.この時に,スプリアス割込み
321 * を発生させる可能性がある.
322 */
323 setitimer(ITIMER_REAL, &itimerval_stop, &val);
324 left = val.it_value.tv_usec;
325 if (left == 0) {
326 left = 1;
327 }
328
329 /*
330 * タイマの残り時間から,ティックタイマとオーバランタイマの残り時
331 * 間を設定し直す.
332 */
333 if (itimer_ticktimer) {
334 if (ovrtimer_active) {
335 ovrtimer_left -= CLOCK_TO_OVRTIM(ticktimer_left - left);
336 }
337 ticktimer_left = left;
338 }
339 else {
340 ticktimer_left -= (OVRTIM_TO_CLOCK(ovrtimer_left) - left);
341 ovrtimer_left = CLOCK_TO_OVRTIM(left);
342 }
343}
344
345/*
346 * タイマの起動処理
347 */
348void
349target_timer_initialize(intptr_t exinf)
350{
351 target_timer_register_int();
352
353 ticktimer_cyc = TO_CLOCK(TIC_NUME, TIC_DENO);
354 assert(ticktimer_cyc <= MAX_CLOCK);
355
356 ticktimer_left = ticktimer_cyc;
357 ovrtimer_active = false;
358 itimer_start();
359}
360
361/*
362 * タイマの停止処理
363 */
364void
365target_timer_terminate(intptr_t exinf)
366{
367 /*
368 * タイマの動作を停止する.
369 */
370 setitimer(ITIMER_REAL, &itimerval_stop, NULL);
371}
372
373/*
374 * タイマの現在値の読出し
375 */
376CLOCK
377target_timer_get_current(void)
378{
379 struct itimerval val;
380
381 if (itimer_ticktimer) {
382 getitimer(ITIMER_REAL, &val);
383 if (val.it_value.tv_usec == 0) {
384 return(0);
385 }
386 else {
387 return(TO_CLOCK(TIC_NUME, TIC_DENO) - val.it_value.tv_usec);
388 }
389 }
390 else {
391 getitimer(ITIMER_REAL, &val);
392 return(ticktimer_left - (OVRTIM_TO_CLOCK(ovrtimer_left)
393 - val.it_value.tv_usec));
394 }
395}
396
397/*
398 * タイマ割込み要求のチェック
399 */
400bool_t
401target_timer_probe_int(void)
402{
403 struct itimerval val;
404
405 if (itimer_ticktimer) {
406 getitimer(ITIMER_REAL, &val);
407 return(val.it_value.tv_usec == 0);
408 }
409 else {
410 return(false);
411 }
412}
413
414/*
415 * オーバランタイマの初期化処理
416 *
417 * 必要な処理をすべてtarget_timer_initializeで行っているので,こちらで
418 * は何もしない.
419 */
420void
421target_ovrtimer_initialize(intptr_t exinf)
422{
423}
424
425/*
426 * オーバランタイマの停止処理
427 *
428 * 必要な処理をすべてtarget_timer_terminateで行っているので,こちらで
429 * は何もしない.
430 */
431void
432target_ovrtimer_terminate(intptr_t exinf)
433{
434}
435
436/*
437 * オーバランタイマの動作開始
438 */
439void
440target_ovrtimer_start(OVRTIM ovrtim)
441{
442 assert(!ovrtimer_active);
443 itimer_stop();
444 ovrtimer_active = true;
445 ovrtimer_left = ovrtim;
446 itimer_start();
447}
448
449/*
450 * オーバランタイマの停止
451 */
452OVRTIM
453target_ovrtimer_stop(void)
454{
455 struct itimerval val;
456
457 assert(ovrtimer_active);
458 if (itimer_ticktimer) {
459 getitimer(ITIMER_REAL, &val);
460 ovrtimer_left -= CLOCK_TO_OVRTIM(ticktimer_left
461 - val.it_value.tv_usec);
462 if (ovrtimer_left == 0) {
463 ovrtimer_left = 1;
464 }
465 ovrtimer_active = false;
466 }
467 else {
468 itimer_stop();
469 ovrtimer_active = false;
470 itimer_start();
471 }
472 return(ovrtimer_left);
473}
474
475/*
476 * オーバランタイマの現在値の読出し
477 */
478OVRTIM
479target_ovrtimer_get_current(void)
480{
481 struct itimerval val;
482 OVRTIM ovrtimer_current;
483
484 assert(ovrtimer_active);
485 if (itimer_ticktimer) {
486 getitimer(ITIMER_REAL, &val);
487 ovrtimer_current = ovrtimer_left
488 - CLOCK_TO_OVRTIM(ticktimer_left - val.it_value.tv_usec);
489 }
490 else {
491 getitimer(ITIMER_REAL, &val);
492 ovrtimer_current = CLOCK_TO_OVRTIM(val.it_value.tv_usec);
493 }
494 return(ovrtimer_current);
495}
496
497/*
498 * タイマ割込みハンドラ
499 *
500 * タイマ割込みハンドラの入口処理で,ovrtimer_stopが呼び出される.オー
501 * バランタイマが動作していた場合には,そこからtarget_ovrtimer_stopが
502 * 呼び出される.インターバルタイマにオーバランタイマが設定されていた
503 * 場合には,そこからitimer_stopとitimer_startが呼び出されて,インター
504 * バルタイマにティックタイマが設定され,インターバルタイマが動作開始
505 * される.逆に,インターバルタイマにティックタイマが設定されていた場
506 * 合には,インターバルタイマは停止したままとなっている.
507 */
508void
509target_timer_handler(void)
510{
511 struct itimerval val;
512
513 i_begin_int(INTNO_TIMER);
514 i_lock_cpu();
515 getitimer(ITIMER_REAL, &val);
516 if (val.it_value.tv_usec == 0) {
517 /*
518 * インターバルタイマが停止しているのは,インターバルタイマに
519 * ティックタイマが設定されていた場合である.
520 */
521 ticktimer_left = ticktimer_cyc;
522
523 val.it_value.tv_sec = 0;
524 val.it_value.tv_usec = ticktimer_left;
525 val.it_interval.tv_sec = 0;
526 val.it_interval.tv_usec = 0;
527 setitimer(ITIMER_REAL, &val, NULL);
528
529 i_unlock_cpu();
530 signal_time(); /* タイムティックの供給 */
531 }
532 else {
533 /*
534 * インターバルタイマが動作しているのは,インターバルタイマに
535 * オーバランタイマが設定されていた場合である.
536 */
537 if (p_runtsk->leftotm == 1) {
538 /*
539 * スプリアス割込みでない場合に,オーバランタイマを起動す
540 * る.
541 */
542 i_unlock_cpu();
543 call_ovrhdr(); /* オーバランハンドラの起動 */
544 }
545 else {
546 i_unlock_cpu();
547 }
548 }
549 i_end_int(INTNO_TIMER);
550}
551
552#endif /* TOPPERS_SUPPORT_OVRHDR */
Note: See TracBrowser for help on using the repository browser.