source: EcnlProtoTool/trunk/asp3_dcre/sample/sample1.c

Last change on this file was 429, checked in by coas-nagasima, 4 years ago

ASP3, TINET, mbed を更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 18.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) 2000-2003 by Embedded and Real-Time Systems Laboratory
7 * Toyohashi Univ. of Technology, JAPAN
8 * Copyright (C) 2004-2019 by Embedded and Real-Time Systems Laboratory
9 * Graduate School of Information Science, Nagoya Univ., JAPAN
10 *
11 * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
12 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
13 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
14 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
15 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
16 * スコード中に含まれていること.
17 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
18 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
19 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
20 * の無保証規定を掲載すること.
21 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
22 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
23 * と.
24 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
25 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
26 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
27 * 報告すること.
28 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
29 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
30 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
31 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
32 * 免責すること.
33 *
34 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
35 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
36 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
37 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
38 * の責任を負わない.
39 *
40 * $Id$
41 */
42
43/*
44 * サンプルプログラム(1)の本体
45 *
46 * ASPカーネルの基本的な動作を確認するためのサンプルプログラム.
47 *
48 * プログラムの概要:
49 *
50 * ユーザインタフェースを受け持つメインタスク(MAIN_TASK)と,3つの並
51 * 行実行されるタスク(TASK1~TASK3),例外処理タスク(EXC_TASK)の5
52 * つのタスクを用いる.これらの他に,システムログタスクが動作する.ま
53 * た,周期ハンドラ,アラームハンドラ,割込みサービスルーチン,CPU例
54 * 外ハンドラをそれぞれ1つ用いる.
55 *
56 * 並行実行されるタスクは,task_loop回のループを実行する度に,タスク
57 * が実行中であることをあらわすメッセージを表示する.ループを実行する
58 * のは,プログラムの動作を確認しやすくするためである.また,低速なシ
59 * リアルポートを用いてメッセージを出力する場合に,すべてのメッセージ
60 * が出力できるように,メッセージの量を制限するという理由もある.
61 *
62 * 周期ハンドラ,アラームハンドラ,割込みサービスルーチンは,3つの優
63 * 先度(HIGH_PRIORITY,MID_PRIORITY,LOW_PRIORITY)のレディキューを
64 * 回転させる.周期ハンドラは,プログラムの起動直後は停止状態になって
65 * いる.
66 *
67 * CPU例外ハンドラは,CPU例外からの復帰が可能な場合には,例外処理タス
68 * クを起動する.例外処理タスクは,CPU例外を起こしたタスクに対して,
69 * 終了要求を行う.
70 *
71 * メインタスクは,シリアルポートからの文字入力を行い(文字入力を待っ
72 * ている間は,並行実行されるタスクが実行されている),入力された文字
73 * に対応した処理を実行する.入力された文字と処理の関係は次の通り.
74 * Control-Cまたは'Q'が入力されると,プログラムを終了する.
75 *
76 * '1' : 対象タスクをTASK1に切り換える(初期設定).
77 * '2' : 対象タスクをTASK2に切り換える.
78 * '3' : 対象タスクをTASK3に切り換える.
79 * 'a' : 対象タスクをact_tskにより起動する.
80 * 'A' : 対象タスクに対する起動要求をcan_actによりキャンセルする.
81 * 'e' : 対象タスクにext_tskを呼び出させ,終了させる.
82 * 't' : 対象タスクをter_tskにより強制終了する.
83 * '>' : 対象タスクの優先度をHIGH_PRIORITYにする.
84 * '=' : 対象タスクの優先度をMID_PRIORITYにする.
85 * '<' : 対象タスクの優先度をLOW_PRIORITYにする.
86 * 'G' : 対象タスクの優先度をget_priで読み出す.
87 * 's' : 対象タスクにslp_tskを呼び出させ,起床待ちにさせる.
88 * 'S' : 対象タスクにtslp_tsk(10秒)を呼び出させ,起床待ちにさせる.
89 * 'w' : 対象タスクをwup_tskにより起床する.
90 * 'W' : 対象タスクに対する起床要求をcan_wupによりキャンセルする.
91 * 'l' : 対象タスクをrel_waiにより強制的に待ち解除にする.
92 * 'u' : 対象タスクをsus_tskにより強制待ち状態にする.
93 * 'm' : 対象タスクの強制待ち状態をrsm_tskにより解除する.
94 * 'd' : 対象タスクにdly_tsk(10秒)を呼び出させ,時間経過待ちにさせる.
95 * 'x' : 対象タスクにras_terにより終了要求する.
96 * 'y' : 対象タスクにdis_terを呼び出させ,タスク終了を禁止する.
97 * 'Y' : 対象タスクにena_terを呼び出させ,タスク終了を許可する.
98 * 'r' : 3つの優先度(HIGH_PRIORITY,MID_PRIORITY,LOW_PRIORITY)のレ
99 * ディキューを回転させる.
100 * 'c' : 周期ハンドラを動作開始させる.
101 * 'C' : 周期ハンドラを動作停止させる.
102 * 'b' : アラームハンドラを5秒後に起動するよう動作開始させる.
103 * 'B' : アラームハンドラを動作停止させる.
104 * 'z' : 対象タスクにCPU例外を発生させる(ターゲットによっては復帰可能).
105 * 'Z' : 対象タスクにCPUロック状態でCPU例外を発生させる(復帰不可能).
106 * '@' : タスク3をacre_tskにより生成する.
107 * '!' : 対象タスクをdel_tskにより削除する.
108 * '$' : アラームハンドラをacre_almにより生成する.
109 * '#' : アラームハンドラをdel_almにより削除する.
110 * 'V' : 短いループを挟んで,fch_hrtで高分解能タイマを2回読む.
111 * 'v' : 発行したシステムコールを表示する(デフォルト).
112 * 'q' : 発行したシステムコールを表示しない.
113 */
114
115#include <kernel.h>
116#include <t_syslog.h>
117#include <t_stdlib.h>
118#include "syssvc/serial.h"
119#include "syssvc/syslog.h"
120#include "kernel_cfg.h"
121#include "sample1.h"
122
123/*
124 * サービスコールのエラーのログ出力
125 */
126Inline void
127svc_perror(const char *file, int_t line, const char *expr, ER ercd)
128{
129 if (ercd < 0) {
130 t_perror(LOG_ERROR, file, line, expr, ercd);
131 }
132}
133
134#define SVC_PERROR(expr) svc_perror(__FILE__, __LINE__, #expr, (expr))
135
136/*
137 * プロセッサ時間の消費
138 *
139 * ループによりプロセッサ時間を消費する.最適化ができないように,ルー
140 * プ内でvolatile変数を読み込む.
141 */
142static volatile long_t volatile_var;
143
144static void
145consume_time(ulong_t ctime)
146{
147 ulong_t i;
148
149 for (i = 0; i < ctime; i++) {
150 (void) volatile_var;
151 }
152}
153
154/*
155 * 並行実行されるタスクへのメッセージ領域
156 */
157char message[3];
158
159/*
160 * ループ回数
161 */
162ulong_t task_loop; /* タスク内でのループ回数 */
163
164/*
165 * 並行実行されるタスク
166 */
167void
168task(intptr_t exinf)
169{
170 int_t n = 0;
171 int_t tskno = (int_t) exinf;
172 const char *graph[] = { "|", " +", " *" };
173 char c;
174
175 while (true) {
176 syslog(LOG_NOTICE, "task%d is running (%03d). %s",
177 tskno, ++n, graph[tskno-1]);
178 consume_time(task_loop);
179 c = message[tskno-1];
180 message[tskno-1] = 0;
181 switch (c) {
182 case 'e':
183 syslog(LOG_INFO, "#%d#ext_tsk()", tskno);
184 SVC_PERROR(ext_tsk());
185 assert(0);
186 case 's':
187 syslog(LOG_INFO, "#%d#slp_tsk()", tskno);
188 SVC_PERROR(slp_tsk());
189 break;
190 case 'S':
191 syslog(LOG_INFO, "#%d#tslp_tsk(10000000)", tskno);
192 SVC_PERROR(tslp_tsk(10000000));
193 break;
194 case 'd':
195 syslog(LOG_INFO, "#%d#dly_tsk(10000000)", tskno);
196 SVC_PERROR(dly_tsk(10000000));
197 break;
198 case 'y':
199 syslog(LOG_INFO, "#%d#dis_ter()", tskno);
200 SVC_PERROR(dis_ter());
201 break;
202 case 'Y':
203 syslog(LOG_INFO, "#%d#ena_ter()", tskno);
204 SVC_PERROR(ena_ter());
205 break;
206#ifdef CPUEXC1
207 case 'z':
208 syslog(LOG_NOTICE, "#%d#raise CPU exception", tskno);
209 RAISE_CPU_EXCEPTION;
210 break;
211 case 'Z':
212 SVC_PERROR(loc_cpu());
213 syslog(LOG_NOTICE, "#%d#raise CPU exception", tskno);
214 RAISE_CPU_EXCEPTION;
215 SVC_PERROR(unl_cpu());
216 break;
217#endif /* CPUEXC1 */
218 default:
219 break;
220 }
221 }
222}
223
224/*
225 * 割込みサービスルーチン
226 *
227 * HIGH_PRIORITY,MID_PRIORITY,LOW_PRIORITY の各優先度のレディキュー
228 * を回転させる.
229 */
230#ifdef INTNO1
231
232void
233intno1_isr(intptr_t exinf)
234{
235 intno1_clear();
236 SVC_PERROR(rot_rdq(HIGH_PRIORITY));
237 SVC_PERROR(rot_rdq(MID_PRIORITY));
238 SVC_PERROR(rot_rdq(LOW_PRIORITY));
239}
240
241#endif /* INTNO1 */
242
243/*
244 * CPU例外ハンドラ
245 */
246ID cpuexc_tskid; /* CPU例外を起こしたタスクのID */
247
248#ifdef CPUEXC1
249
250void
251cpuexc_handler(void *p_excinf)
252{
253 syslog(LOG_NOTICE, "CPU exception handler (p_excinf = %08p).", p_excinf);
254 if (sns_ctx() != true) {
255 syslog(LOG_WARNING,
256 "sns_ctx() is not true in CPU exception handler.");
257 }
258 if (sns_dpn() != true) {
259 syslog(LOG_WARNING,
260 "sns_dpn() is not true in CPU exception handler.");
261 }
262 syslog(LOG_INFO, "sns_loc = %d, sns_dsp = %d, xsns_dpn = %d",
263 sns_loc(), sns_dsp(), xsns_dpn(p_excinf));
264
265 if (xsns_dpn(p_excinf)) {
266 syslog(LOG_NOTICE, "Sample program ends with exception.");
267 SVC_PERROR(ext_ker());
268 assert(0);
269 }
270
271 SVC_PERROR(get_tid(&cpuexc_tskid));
272 SVC_PERROR(act_tsk(EXC_TASK));
273}
274
275#endif /* CPUEXC1 */
276
277/*
278 * 周期ハンドラ
279 *
280 * HIGH_PRIORITY,MID_PRIORITY,LOW_PRIORITY の各優先度のレディキュー
281 * を回転させる.
282 */
283void
284cyclic_handler(intptr_t exinf)
285{
286 SVC_PERROR(rot_rdq(HIGH_PRIORITY));
287 SVC_PERROR(rot_rdq(MID_PRIORITY));
288 SVC_PERROR(rot_rdq(LOW_PRIORITY));
289}
290
291/*
292 * アラームハンドラ
293 *
294 * HIGH_PRIORITY,MID_PRIORITY,LOW_PRIORITY の各優先度のレディキュー
295 * を回転させる.
296 */
297void
298alarm_handler(intptr_t exinf)
299{
300 SVC_PERROR(rot_rdq(HIGH_PRIORITY));
301 SVC_PERROR(rot_rdq(MID_PRIORITY));
302 SVC_PERROR(rot_rdq(LOW_PRIORITY));
303}
304
305/*
306 * 例外処理タスク
307 */
308void
309exc_task(intptr_t exinf)
310{
311 SVC_PERROR(ras_ter(cpuexc_tskid));
312}
313
314/*
315 * メインタスク
316 */
317void
318main_task(intptr_t exinf)
319{
320 char c;
321 ID tskid = TASK1;
322 int_t tskno = 1;
323 ER_UINT ercd;
324 PRI tskpri;
325#ifndef TASK_LOOP
326 SYSTIM stime1, stime2;
327#endif /* TASK_LOOP */
328 HRTCNT hrtcnt1, hrtcnt2;
329 T_CTSK ctsk;
330 ID TASK3 = -1;
331 T_CALM calm;
332 ID ALMHDR1 = -1;
333
334 SVC_PERROR(syslog_msk_log(LOG_UPTO(LOG_INFO), LOG_UPTO(LOG_EMERG)));
335 syslog(LOG_NOTICE, "Sample program starts (exinf = %d).", (int_t) exinf);
336
337 /*
338 * シリアルポートの初期化
339 *
340 * システムログタスクと同じシリアルポートを使う場合など,シリアル
341 * ポートがオープン済みの場合にはここでE_OBJエラーになるが,支障は
342 * ない.
343 */
344 ercd = serial_opn_por(TASK_PORTID);
345 if (ercd < 0 && MERCD(ercd) != E_OBJ) {
346 syslog(LOG_ERROR, "%s (%d) reported by `serial_opn_por'.",
347 itron_strerror(ercd), SERCD(ercd));
348 }
349 SVC_PERROR(serial_ctl_por(TASK_PORTID,
350 (IOCTL_CRLF | IOCTL_FCSND | IOCTL_FCRCV)));
351
352 /*
353 * ループ回数の設定
354 *
355 * 並行実行されるタスク内でのループの回数(task_loop)は,ループ
356 * の実行時間が約0.4秒になるように設定する.この設定のために,
357 * LOOP_REF回のループの実行時間を,その前後でget_timを呼ぶことで
358 * 測定し,その測定結果から空ループの実行時間が0.4秒になるループ
359 * 回数を求め,task_loopに設定する.
360 *
361 * LOOP_REFは,デフォルトでは1,000,000に設定しているが,想定した
362 * より遅いプロセッサでは,サンプルプログラムの実行開始に時間がか
363 * かりすぎるという問題を生じる.逆に想定したより速いプロセッサで
364 * は,LOOP_REF回のループの実行時間が短くなり,task_loopに設定す
365 * る値の誤差が大きくなるという問題がある.そこで,そのようなター
366 * ゲットでは,target_test.hで,LOOP_REFを適切な値に定義すること
367 * とする.
368 *
369 * また,task_loopの値を固定したい場合には,その値をTASK_LOOPにマ
370 * クロ定義する.TASK_LOOPがマクロ定義されている場合,上記の測定
371 * を行わずに,TASK_LOOPに定義された値をループの回数とする.
372 *
373 * ターゲットによっては,ループの実行時間の1回目の測定で,本来より
374 * も長めになるものがある.このようなターゲットでは,MEASURE_TWICE
375 * をマクロ定義することで,1回目の測定結果を捨てて,2回目の測定結
376 * 果を使う.
377 */
378#ifdef TASK_LOOP
379 task_loop = TASK_LOOP;
380#else /* TASK_LOOP */
381
382#ifdef MEASURE_TWICE
383 SVC_PERROR(get_tim(&stime1));
384 consume_time(LOOP_REF);
385 SVC_PERROR(get_tim(&stime2));
386#endif /* MEASURE_TWICE */
387
388 SVC_PERROR(get_tim(&stime1));
389 consume_time(LOOP_REF);
390 SVC_PERROR(get_tim(&stime2));
391 task_loop = LOOP_REF * 400LU / (ulong_t)(stime2 - stime1) * 1000LU;
392
393#endif /* TASK_LOOP */
394
395 /*
396 * タスクの起動
397 */
398 SVC_PERROR(act_tsk(TASK1));
399 SVC_PERROR(act_tsk(TASK2));
400
401 /*
402 * メインループ
403 */
404 do {
405 SVC_PERROR(serial_rea_dat(TASK_PORTID, &c, 1));
406 switch (c) {
407 case 'e':
408 case 's':
409 case 'S':
410 case 'd':
411 case 'y':
412 case 'Y':
413 case 'z':
414 case 'Z':
415 message[tskno-1] = c;
416 break;
417 case '1':
418 tskno = 1;
419 tskid = TASK1;
420 break;
421 case '2':
422 tskno = 2;
423 tskid = TASK2;
424 break;
425 case '3':
426 tskno = 3;
427 tskid = TASK3;
428 break;
429 case 'a':
430 syslog(LOG_INFO, "#act_tsk(%d)", tskno);
431 SVC_PERROR(act_tsk(tskid));
432 break;
433 case 'A':
434 syslog(LOG_INFO, "#can_act(%d)", tskno);
435 SVC_PERROR(ercd = can_act(tskid));
436 if (ercd >= 0) {
437 syslog(LOG_NOTICE, "can_act(%d) returns %d", tskno, ercd);
438 }
439 break;
440 case 't':
441 syslog(LOG_INFO, "#ter_tsk(%d)", tskno);
442 SVC_PERROR(ter_tsk(tskid));
443 break;
444 case '>':
445 syslog(LOG_INFO, "#chg_pri(%d, HIGH_PRIORITY)", tskno);
446 SVC_PERROR(chg_pri(tskid, HIGH_PRIORITY));
447 break;
448 case '=':
449 syslog(LOG_INFO, "#chg_pri(%d, MID_PRIORITY)", tskno);
450 SVC_PERROR(chg_pri(tskid, MID_PRIORITY));
451 break;
452 case '<':
453 syslog(LOG_INFO, "#chg_pri(%d, LOW_PRIORITY)", tskno);
454 SVC_PERROR(chg_pri(tskid, LOW_PRIORITY));
455 break;
456 case 'G':
457 syslog(LOG_INFO, "#get_pri(%d, &tskpri)", tskno);
458 SVC_PERROR(ercd = get_pri(tskid, &tskpri));
459 if (ercd >= 0) {
460 syslog(LOG_NOTICE, "priority of task %d is %d", tskno, tskpri);
461 }
462 break;
463 case 'w':
464 syslog(LOG_INFO, "#wup_tsk(%d)", tskno);
465 SVC_PERROR(wup_tsk(tskid));
466 break;
467 case 'W':
468 syslog(LOG_INFO, "#can_wup(%d)", tskno);
469 SVC_PERROR(ercd = can_wup(tskid));
470 if (ercd >= 0) {
471 syslog(LOG_NOTICE, "can_wup(%d) returns %d", tskno, ercd);
472 }
473 break;
474 case 'l':
475 syslog(LOG_INFO, "#rel_wai(%d)", tskno);
476 SVC_PERROR(rel_wai(tskid));
477 break;
478 case 'u':
479 syslog(LOG_INFO, "#sus_tsk(%d)", tskno);
480 SVC_PERROR(sus_tsk(tskid));
481 break;
482 case 'm':
483 syslog(LOG_INFO, "#rsm_tsk(%d)", tskno);
484 SVC_PERROR(rsm_tsk(tskid));
485 break;
486 case 'x':
487 syslog(LOG_INFO, "#ras_ter(%d)", tskno);
488 SVC_PERROR(ras_ter(tskid));
489 break;
490 case 'r':
491 syslog(LOG_INFO, "#rot_rdq(three priorities)");
492 SVC_PERROR(rot_rdq(HIGH_PRIORITY));
493 SVC_PERROR(rot_rdq(MID_PRIORITY));
494 SVC_PERROR(rot_rdq(LOW_PRIORITY));
495 break;
496 case 'c':
497 syslog(LOG_INFO, "#sta_cyc(CYCHDR1)");
498 SVC_PERROR(sta_cyc(CYCHDR1));
499 break;
500 case 'C':
501 syslog(LOG_INFO, "#stp_cyc(CYCHDR1)");
502 SVC_PERROR(stp_cyc(CYCHDR1));
503 break;
504 case 'b':
505 syslog(LOG_INFO, "#sta_alm(ALMHDR1, 5000000)");
506 SVC_PERROR(sta_alm(ALMHDR1, 5000000));
507 break;
508 case 'B':
509 syslog(LOG_INFO, "#stp_alm(ALMHDR1)");
510 SVC_PERROR(stp_alm(ALMHDR1));
511 break;
512 case '@':
513 ctsk.tskatr = TA_NULL;
514 ctsk.exinf = 3;
515 ctsk.task = task;
516 ctsk.itskpri = MID_PRIORITY;
517 ctsk.stksz = STACK_SIZE;
518 ctsk.stk = NULL;
519 SVC_PERROR(ercd = acre_tsk(&ctsk));
520 if (ercd >= 0) {
521 TASK3 = ercd;
522 syslog(LOG_NOTICE, "task3 is created with tskid = %d.",
523 (int_t) TASK3);
524 }
525 break;
526 case '!':
527 syslog(LOG_INFO, "#del_tsk(%d)", tskno);
528 SVC_PERROR(del_tsk(tskid));
529 break;
530 case '$':
531 calm.almatr = TA_NULL;
532 calm.nfyinfo.nfymode = TNFY_HANDLER;
533 calm.nfyinfo.nfy.handler.exinf = (intptr_t) 0;
534 calm.nfyinfo.nfy.handler.tmehdr = (TMEHDR) alarm_handler;
535 SVC_PERROR(ercd = acre_alm(&calm));
536 if (ercd >= 0) {
537 ALMHDR1 = ercd;
538 syslog(LOG_NOTICE, "alarm handler is created with almid = %d.",
539 (int_t) ALMHDR1);
540 }
541 break;
542 case '#':
543 syslog(LOG_INFO, "#del_alm(ALMHDR1)");
544 SVC_PERROR(del_alm(ALMHDR1));
545 break;
546
547 case 'V':
548 hrtcnt1 = fch_hrt();
549 consume_time(1000LU);
550 hrtcnt2 = fch_hrt();
551 syslog(LOG_NOTICE, "hrtcnt1 = %tu, hrtcnt2 = %tu",
552 (uint32_t) hrtcnt1, (uint32_t) hrtcnt2);
553 break;
554
555 case 'v':
556 SVC_PERROR(syslog_msk_log(LOG_UPTO(LOG_INFO),
557 LOG_UPTO(LOG_EMERG)));
558 break;
559 case 'q':
560 SVC_PERROR(syslog_msk_log(LOG_UPTO(LOG_NOTICE),
561 LOG_UPTO(LOG_EMERG)));
562 break;
563
564#ifdef BIT_KERNEL
565 case ' ':
566 SVC_PERROR(loc_cpu());
567 {
568 extern ER bit_kernel(void);
569
570 SVC_PERROR(ercd = bit_kernel());
571 if (ercd >= 0) {
572 syslog(LOG_NOTICE, "bit_kernel passed.");
573 }
574 }
575 SVC_PERROR(unl_cpu());
576 break;
577#endif /* BIT_KERNEL */
578
579 case '\003':
580 case 'Q':
581 break;
582
583 default:
584 syslog(LOG_INFO, "Unknown command: '%c'.", c);
585 break;
586 }
587 } while (c != '\003' && c != 'Q');
588
589 syslog(LOG_NOTICE, "Sample program ends.");
590 SVC_PERROR(ext_ker());
591 assert(0);
592}
Note: See TracBrowser for help on using the repository browser.