source: asp3_gr_sakura/trunk/kernel/time_event.c@ 317

Last change on this file since 317 was 317, checked in by coas-nagasima, 7 years ago

GR-SAKURA向けASP3を追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 16.6 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) 2000-2003 by Embedded and Real-Time Systems Laboratory
7 * Toyohashi Univ. of Technology, JAPAN
8 * Copyright (C) 2005-2016 by Embedded and Real-Time Systems Laboratory
9 * Graduate School of Information Science, Nagoya Univ., JAPAN
10 *
11 * 上記著作権者
12は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
13 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
14 * 変・再é…
15å¸ƒï¼ˆä»¥ä¸‹ï¼Œåˆ©ç”¨ã¨å‘¼ã¶ï¼‰ã™ã‚‹ã“とを無償で許諾する.
16 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
17 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
18 * スコード中に含まれていること.
19 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
20 * 用できる形で再é…
21å¸ƒã™ã‚‹å ´åˆã«ã¯ï¼Œå†é…
22å¸ƒã«ä¼´ã†ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆï¼ˆåˆ©ç”¨
23 * 者
24マニュアルなど)に,上記の著作権表示,この利用条件および下記
25 * の無保証規定を掲載すること.
26 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
27 * 用できない形で再é…
28å¸ƒã™ã‚‹å ´åˆã«ã¯ï¼Œæ¬¡ã®ã„ずれかの条件を満たすこ
29 * と.
30 * (a) 再é…
31å¸ƒã«ä¼´ã†ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆï¼ˆåˆ©ç”¨è€…
32マニュアルなど)に,上記の著
33 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
34 * (b) 再é…
35å¸ƒã®å½¢æ…
36‹ã‚’,別に定める方法によって,TOPPERSプロジェクトに
37 * 報告すること.
38 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
39 * 害からも,上記著作権者
40およびTOPPERSプロジェクトをå…
41è²¬ã™ã‚‹ã“と.
42 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
43 * 由に基づく請求からも,上記著作権者
44およびTOPPERSプロジェクトを
45 * å…
46è²¬ã™ã‚‹ã“と.
47 *
48 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者
49お
50 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
51 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
52 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
53 * の責任を負わない.
54 *
55 * $Id: time_event.c 317 2017-08-03 13:14:26Z coas-nagasima $
56 */
57
58/*
59 * タイムイベント管理モジュール
60 */
61
62#include "kernel_impl.h"
63#include "time_event.h"
64
65/*
66 * TSTEP_HRTCNTの範囲チェック
67 */
68#if TSTEP_HRTCNT > 4000U
69#error TSTEP_HRTCNT is too large.
70#endif /* TSTEP_HRTCNT > 4000U */
71
72/*
73 * HRTCNT_BOUNDの範囲チェック
74 */
75#if HRTCNT_BOUND >= 4294000000U
76#error HRTCNT_BOUND is too large.
77#endif /* HRTCNT_BOUND >= 4294000000U */
78
79#ifdef TCYC_HRTCNT
80#if HRTCNT_BOUND >= TCYC_HRTCNT
81#error HRTCNT_BOUND is too large.
82#endif /* HRTCNT_BOUND >= TCYC_HRTCNT */
83#endif /* TCYC_HRTCNT */
84
85/*
86 * タイムイベントヒープ操作マクロ
87 */
88#define PARENT(p_tmevtn) (tmevt_heap + (((p_tmevtn) - tmevt_heap) >> 1))
89 /* 親ノードを求める */
90#define LCHILD(p_tmevtn) (tmevt_heap + (((p_tmevtn) - tmevt_heap) << 1))
91 /* 左の子ノードを求める */
92/*
93 * タイムイベントヒープ中のå…
94ˆé ­ã®ãƒŽãƒ¼ãƒ‰
95 */
96#define p_top_tmevtn (&(tmevt_heap[1]))
97#define top_evttim (tmevt_heap[1].p_tmevtb->evttim)
98 /* å…
99ˆé ­ã®ã‚¿ã‚¤ãƒ ã‚¤ãƒ™ãƒ³ãƒˆã®ç™ºç”Ÿæ™‚刻 */
100/*
101 * タイムイベントヒープ中の最後のノード
102 */
103#define p_last_tmevtn (tmevt_heap[0].p_last)
104
105/*
106 * イベント時刻の前後関係の判定[ASPD1009]
107 *
108 * イベント時刻は,boundary_evttimからの相対値で比較する.すなわち,
109 * boundary_evttimを最も早い時刻,boundary_evttim-1が最も遅
110い時刻とみ
111 * なして比較する.
112 */
113#define EVTTIM_ADVANCE(t) ((t) - boundary_evttim)
114#define EVTTIM_LT(t1, t2) (EVTTIM_ADVANCE(t1) < EVTTIM_ADVANCE(t2))
115#define EVTTIM_LE(t1, t2) (EVTTIM_ADVANCE(t1) <= EVTTIM_ADVANCE(t2))
116
117#ifdef TOPPERS_tmeini
118
119/*
120 * 境界イベント時刻[ASPD1008]
121 */
122EVTTIM boundary_evttim;
123
124/*
125 * 最後に現在時刻を算出した時点でのイベント時刻[ASPD1012]
126 */
127EVTTIM current_evttim;
128
129/*
130 * 最後に現在時刻を算出した時点での高分解能タイマのカウント値[ASPD1012]
131 */
132HRTCNT current_hrtcnt;
133
134/*
135 * 最も進んでいた時のイベント時刻[ASPD1041]
136 */
137EVTTIM monotonic_evttim;
138
139/*
140 * システム時刻のオフセット[ASPD1043]
141 */
142SYSTIM systim_offset;
143
144/*
145 * 高分解能タイマ割込みの処理中であることを示すフラグ[ASPD1032]
146 */
147bool_t in_signal_time;
148
149/*
150 * タイムイベント管理モジュールの初期化[ASPD1061]
151 */
152void
153initialize_tmevt(void)
154{
155 current_evttim = 0U; /*ï¼»ASPD1047ï¼½*/
156 boundary_evttim = current_evttim - BOUNDARY_MARGIN;
157 /*ï¼»ASPD1048ï¼½*/
158 monotonic_evttim = 0U; /*ï¼»ASPD1046ï¼½*/
159 systim_offset = 0U; /*ï¼»ASPD1044ï¼½*/
160 in_signal_time = false; /*ï¼»ASPD1033ï¼½*/
161 p_last_tmevtn = tmevt_heap;
162}
163
164#endif /* TOPPERS_tmeini */
165
166/*
167 * タイムイベントの挿å…
168¥ä½ç½®ã‚’上向きに探索
169 *
170 * 時刻evttimに発生するタイムイベントを挿å…
171¥ã™ã‚‹ãƒŽãƒ¼ãƒ‰ã‚’空けるために,
172 * ヒープの上に向かって空ノードを移動させる.移動前の空ノードの位置を
173 * p_tmevtnに渡すと,移動後の空ノードの位置(すなわち挿å…
174¥ä½ç½®ï¼‰ã‚’返す.
175 */
176#ifdef TOPPERS_tmeup
177
178TMEVTN *
179tmevt_up(TMEVTN *p_tmevtn, EVTTIM evttim)
180{
181 TMEVTN *p_parent;
182
183 while (p_tmevtn > p_top_tmevtn) {
184 /*
185 * 親ノードのイベント発生時刻の方が早い(または同じ)ならば,
186 * p_tmevtnが挿å…
187¥ä½ç½®ãªã®ã§ãƒ«ãƒ¼ãƒ—を抜ける.
188 */
189 p_parent = PARENT(p_tmevtn);
190 if (EVTTIM_LE(p_parent->p_tmevtb->evttim, evttim)) {
191 break;
192 }
193
194 /*
195 * 親ノードをp_tmevtnの位置に移動させる.
196 */
197 *p_tmevtn = *p_parent;
198 p_tmevtn->p_tmevtb->p_tmevtn = p_tmevtn;
199
200 /*
201 * p_tmevtnを親ノードの位置に更新.
202 */
203 p_tmevtn = p_parent;
204 }
205 return(p_tmevtn);
206}
207
208#endif /* TOPPERS_tmeup */
209
210/*
211 * タイムイベントの挿å…
212¥ä½ç½®ã‚’下向きに探索
213 *
214 * 時刻evttimに発生するタイムイベントを挿å…
215¥ã™ã‚‹ãƒŽãƒ¼ãƒ‰ã‚’空けるために,
216 * ヒープの下に向かって空ノードを移動させる.移動前の空ノードの位置を
217 * p_tmevtnに渡すと,移動後の空ノードの位置(すなわち挿å…
218¥ä½ç½®ï¼‰ã‚’返す.
219 */
220#ifdef TOPPERS_tmedown
221
222TMEVTN *
223tmevt_down(TMEVTN *p_tmevtn, EVTTIM evttim)
224{
225 TMEVTN *p_child;
226
227 while ((p_child = LCHILD(p_tmevtn)) <= p_last_tmevtn) {
228 /*
229 * 左右の子ノードのイベント発生時刻を比較し,早い方の子ノード
230 * の位置をp_childに設定する.以下の子ノードは,ここで選ばれた
231 * 方の子ノードのこと.
232 */
233 if (p_child + 1 <= p_last_tmevtn
234 && EVTTIM_LT((p_child + 1)->p_tmevtb->evttim,
235 p_child->p_tmevtb->evttim)) {
236 p_child = p_child + 1;
237 }
238
239 /*
240 * 子ノードのイベント発生時刻の方が遅
241い(または同じ)ならば,
242 * p_tmevtnが挿å…
243¥ä½ç½®ãªã®ã§ãƒ«ãƒ¼ãƒ—を抜ける.
244 */
245 if (EVTTIM_LE(evttim, p_child->p_tmevtb->evttim)) {
246 break;
247 }
248
249 /*
250 * 子ノードをp_tmevtnの位置に移動させる.
251 */
252 *p_tmevtn = *p_child;
253 p_tmevtn->p_tmevtb->p_tmevtn = p_tmevtn;
254
255 /*
256 * p_tmevtnを子ノードの位置に更新.
257 */
258 p_tmevtn = p_child;
259 }
260 return(p_tmevtn);
261}
262
263#endif /* TOPPERS_tmedown */
264
265/*
266 * タイムイベントヒープへの追加
267 *
268 * p_tmevtbで指定したタイムイベントブロックを,タイムイベントヒープに
269 * 追加する.
270 */
271Inline void
272tmevtb_insert(TMEVTB *p_tmevtb)
273{
274 TMEVTN *p_tmevtn;
275
276 /*
277 * p_last_tmevtnをインクリメントし,そこから上に挿å…
278¥ä½ç½®ã‚’探す.
279 */
280 p_tmevtn = tmevt_up(++p_last_tmevtn, p_tmevtb->evttim);
281
282 /*
283 * タイムイベントをp_tmevtnの位置に挿å…
284¥ã™ã‚‹ï¼Ž
285 */
286 p_tmevtn->p_tmevtb = p_tmevtb;
287 p_tmevtb->p_tmevtn = p_tmevtn;
288}
289
290/*
291 * タイムイベントヒープからの削除
292 */
293Inline void
294tmevtb_delete(TMEVTB *p_tmevtb)
295{
296 TMEVTN *p_tmevtn = p_tmevtb->p_tmevtn;
297 TMEVTN *p_parent;
298 EVTTIM event_evttim;
299
300 /*
301 * 削除によりタイムイベントヒープが空になる場合は何もしない.
302 */
303 if (--p_last_tmevtn < p_top_tmevtn) {
304 return;
305 }
306
307 /*
308 * 削除したノードの位置に最後のノード(p_last_tmevtn + 1 の位置の
309 * ノード)を挿å…
310¥ã—,それを適切な位置へ移動させる.実際には,最後
311 * のノードを実際に挿å…
312¥ã™ã‚‹ã®ã§ã¯ãªãï¼Œå‰Šé™¤ã—たノードの位置が空ノー
313 * ドになるので,最後のノードを挿å…
314¥ã™ã¹ãä½ç½®ã¸å‘けて空ノードを移
315 * 動させる.
316 *
317 * 最後のノードのイベント発生時刻が,削除したノードの親ノードのイ
318 * ベント発生時刻より前の場合には,上に向かって挿å…
319¥ä½ç½®ã‚’探す.そ
320 * うでない場合には,下に向かって探す.
321 */
322 event_evttim = (p_last_tmevtn + 1)->p_tmevtb->evttim;
323 if (p_tmevtn > p_top_tmevtn
324 && EVTTIM_LT(event_evttim,
325 (p_parent = PARENT(p_tmevtn))->p_tmevtb->evttim)) {
326 /*
327 * 親ノードをp_tmevtnの位置に移動させる.
328 */
329 *p_tmevtn = *p_parent;
330 p_tmevtn->p_tmevtb->p_tmevtn = p_tmevtn;
331
332 /*
333 * 削除したノードの親ノードから上に向かって挿å…
334¥ä½ç½®ã‚’探す.
335 */
336 p_tmevtn = tmevt_up(p_parent, event_evttim);
337 }
338 else {
339 /*
340 * 削除したノードから下に向かって挿å…
341¥ä½ç½®ã‚’探す.
342 */
343 p_tmevtn = tmevt_down(p_tmevtn, event_evttim);
344 }
345
346 /*
347 * 最後のノードをp_tmevtnの位置に挿å…
348¥ã™ã‚‹ï¼Ž
349 */
350 *p_tmevtn = *(p_last_tmevtn + 1);
351 p_tmevtn->p_tmevtb->p_tmevtn = p_tmevtn;
352}
353
354/*
355 * タイムイベントヒープのå…
356ˆé ­ã®ãƒŽãƒ¼ãƒ‰ã®å‰Šé™¤
357 */
358Inline TMEVTB *
359tmevtb_delete_top(void)
360{
361 TMEVTN *p_tmevtn;
362 TMEVTB *p_top_tmevtb = p_top_tmevtn->p_tmevtb;
363 EVTTIM event_evttim;
364
365 /*
366 * 削除によりタイムイベントヒープが空になる場合は何もしない.
367 */
368 if (--p_last_tmevtn >= p_top_tmevtn) {
369 /*
370 * ルートノードに最後のノード(p_last_tmevtn + 1 の位置のノー
371 * ド)を挿å…
372¥ã—,それを適切な位置へ移動させる.実際には,最後
373 * のノードを実際に挿å…
374¥ã™ã‚‹ã®ã§ã¯ãªãï¼Œãƒ«ãƒ¼ãƒˆãƒŽãƒ¼ãƒ‰ãŒç©ºãƒŽãƒ¼ãƒ‰
375 * になるので,最後のノードを挿å…
376¥ã™ã¹ãä½ç½®ã¸å‘けて空ノードを
377 * 移動させる.
378 */
379 event_evttim = (p_last_tmevtn + 1)->p_tmevtb->evttim;
380 p_tmevtn = tmevt_down(p_top_tmevtn, event_evttim);
381
382 /*
383 * 最後のノードをp_tmevtnの位置に挿å…
384¥ã™ã‚‹ï¼Ž
385 */
386 *p_tmevtn = *(p_last_tmevtn + 1);
387 p_tmevtn->p_tmevtb->p_tmevtn = p_tmevtn;
388 }
389 return(p_top_tmevtb);
390}
391
392/*
393 * 現在のイベント時刻の更新
394 */
395#ifdef TOPPERS_tmecur
396
397void
398update_current_evttim(void)
399{
400 HRTCNT new_hrtcnt, hrtcnt_advance;
401 EVTTIM previous_evttim;
402
403 new_hrtcnt = target_hrt_get_current(); /*ï¼»ASPD1013ï¼½*/
404 hrtcnt_advance = new_hrtcnt - current_hrtcnt; /*ï¼»ASPD1014ï¼½*/
405#ifdef TCYC_HRTCNT
406 if (new_hrtcnt < current_hrtcnt) {
407 hrtcnt_advance += TCYC_HRTCNT;
408 }
409#endif /* TCYC_HRTCNT */
410
411 previous_evttim = current_evttim;
412 current_evttim += (EVTTIM) hrtcnt_advance; /*ï¼»ASPD1015ï¼½*/
413 current_hrtcnt = new_hrtcnt; /*ï¼»ASPD1016ï¼½*/
414 boundary_evttim = current_evttim - BOUNDARY_MARGIN; /*ï¼»ASPD1011ï¼½*/
415
416 if (monotonic_evttim - previous_evttim < (EVTTIM) hrtcnt_advance) {
417#ifdef UINT64_MAX
418 if (current_evttim < monotonic_evttim) {
419 systim_offset += 1LLU << 32; /*ï¼»ASPD1045ï¼½*/
420 }
421#endif /* UINT64_MAX */
422 monotonic_evttim = current_evttim; /*ï¼»ASPD1042ï¼½*/
423 }
424}
425
426#endif /* TOPPERS_tmecur */
427
428/*
429 * 現在のイベント時刻を遅
430い方に丸めたイベント時刻の算出[ASPD1027]
431 *
432 * 現在のイベント時刻を更新した後に呼ぶことを想定している.
433 */
434Inline EVTTIM
435calc_current_evttim_ub(void)
436{
437 return(current_evttim + ((EVTTIM) TSTEP_HRTCNT));
438}
439
440/*
441 * 高分解能タイマ割込みの発生タイミングの設定
442 */
443#ifdef TOPPERS_tmeset
444
445void
446set_hrt_event(void)
447{
448 HRTCNT hrtcnt;
449
450 if (p_last_tmevtn < p_top_tmevtn) {
451 target_hrt_set_event(HRTCNT_BOUND); /*ï¼»ASPD1007ï¼½*/
452 }
453 else if (EVTTIM_LE(top_evttim, current_evttim)) {
454 target_hrt_raise_event(); /*ï¼»ASPD1017ï¼½*/
455 }
456 else {
457 hrtcnt = (HRTCNT)(top_evttim - current_evttim);
458 if (hrtcnt > HRTCNT_BOUND) {
459 target_hrt_set_event(HRTCNT_BOUND); /*ï¼»ASPD1006ï¼½*/
460 }
461 else {
462 target_hrt_set_event(hrtcnt); /*ï¼»ASPD1002ï¼½*/
463 }
464 }
465}
466
467#endif /* TOPPERS_tmeset */
468
469/*
470 * タイムイベントブロックのヒープへの挿å…
471¥
472 */
473#ifdef TOPPERS_tmereg
474
475void
476tmevtb_register(TMEVTB *p_tmevtb)
477{
478 tmevtb_insert(p_tmevtb);
479}
480
481#endif /* TOPPERS_tmereg */
482
483/*
484 * 相対時間指定によるタイムイベントの登録
485 *
486 */
487#ifdef TOPPERS_tmeenq
488
489void
490tmevtb_enqueue(TMEVTB *p_tmevtb, RELTIM time)
491{
492 /*
493 * 現在のイベント時刻とタイムイベントの発生時刻を求める[ASPD1026].
494 */
495 update_current_evttim();
496 p_tmevtb->evttim = calc_current_evttim_ub() + time;
497
498 /*
499 * タイムイベントブロックをヒープに挿å…
500¥ã™ã‚‹ï¼»ASPD1030].
501 */
502 tmevtb_insert(p_tmevtb);
503
504 /*
505 * 高分解能タイマ割込みの発生タイミングを設定する[ASPD1031]
506 * [ASPD1034].
507 */
508 if (!in_signal_time && p_tmevtb->p_tmevtn == p_top_tmevtn) {
509 set_hrt_event();
510 }
511}
512
513#endif /* TOPPERS_tmeenq */
514
515/*
516 * タイムイベントの登録解除
517 */
518#ifdef TOPPERS_tmedeq
519
520void
521tmevtb_dequeue(TMEVTB *p_tmevtb)
522{
523 TMEVTN *p_tmevtn;
524
525 /*
526 * タイムイベントブロックをヒープから削除する[ASPD1039].
527 */
528 p_tmevtn = p_tmevtb->p_tmevtn;
529 tmevtb_delete(p_tmevtb);
530
531 /*
532 * 高分解能タイマ割込みの発生タイミングを設定する[ASPD1040].
533 */
534 if (!in_signal_time && p_tmevtn == p_top_tmevtn) {
535 update_current_evttim();
536 set_hrt_event();
537 }
538}
539
540#endif /* TOPPERS_tmedeq */
541
542/*
543 * システム時刻の調整時のエラーチェック
544 */
545#ifdef TOPPERS_tmechk
546
547bool_t
548check_adjtim(int_t adjtim)
549{
550 if (adjtim > 0) {
551 return(p_last_tmevtn >= p_top_tmevtn /*ï¼»NGKI3588ï¼½*/
552 && EVTTIM_LE(top_evttim, current_evttim - TMAX_ADJTIM));
553 }
554 else if (adjtim < 0) { /*ï¼»NGKI3589ï¼½*/
555 return(monotonic_evttim - current_evttim >= -TMIN_ADJTIM);
556 }
557 return(false);
558}
559
560#endif /* TOPPERS_tmechk */
561
562/*
563 * タイムイベントが発生するまでの時間の計算
564 */
565#ifdef TOPPERS_tmeltim
566
567RELTIM
568tmevt_lefttim(TMEVTB *p_tmevtb)
569{
570 EVTTIM evttim, current_evttim_ub;
571
572 /*
573 * 現在のイベント時刻を遅
574い方に丸めた時刻を求める[ASPD1050].
575 */
576 update_current_evttim();
577 current_evttim_ub = calc_current_evttim_ub();
578
579 /*
580 * タイムイベント発生までの相対時間を求める[ASPD1049].
581 */
582 evttim = p_tmevtb->evttim;
583 if (EVTTIM_LE(evttim, current_evttim_ub)) {
584 /*
585 * タイムイベントの発生時刻を過ぎている場合には0を返す[NGKI0552].
586 */
587 return(0U);
588 }
589 else {
590 return((RELTIM)(evttim - current_evttim_ub));
591 }
592}
593
594#endif /* TOPPERS_tmeltim */
595
596/*
597 * 高分解能タイマ割込みの処理
598 */
599#ifdef TOPPERS_sigtim
600
601void
602signal_time(void)
603{
604 TMEVTB *p_tmevtb;
605 bool_t callflag;
606
607 assert(sense_context());
608 assert(!sense_lock());
609
610 lock_cpu();
611 in_signal_time = true; /*ï¼»ASPD1033ï¼½*/
612
613 do {
614 /*
615 * コールバック関数を呼び出さなければループを抜ける[ASPD1020].
616 */
617 callflag = false;
618
619 /*
620 * 現在のイベント時刻を求める[ASPD1022].
621 */
622 update_current_evttim();
623
624 /*
625 * 発生時刻がcurrent_evttim以前のタイムイベントがあれば,タイ
626 * ムイベントヒープから削除し,コールバック関数を呼び出す
627 * [ASPD1018][ASPD1019].
628 */
629 while (p_last_tmevtn >= p_top_tmevtn
630 && EVTTIM_LE(top_evttim, current_evttim)) {
631 p_tmevtb = tmevtb_delete_top();
632 (*(p_tmevtb->callback))(p_tmevtb->arg);
633 callflag = true;
634 }
635 } while (callflag); /*ï¼»ASPD1020ï¼½*/
636
637 /*
638 * 高分解能タイマ割込みの発生タイミングを設定する[ASPD1025].
639 */
640 set_hrt_event();
641
642 in_signal_time = false; /*ï¼»ASPD1033ï¼½*/
643 unlock_cpu();
644}
645
646#endif /* TOPPERS_sigtim */
Note: See TracBrowser for help on using the repository browser.