RTLinuxからRedHawk Linuxへの移植ガイド
リアルタイムカーネルのアーキテクチャ
RedHawk Linux は、シングルカーネルを採用しているため、通常のアプリケーションの作成と、リアルタイムアプリケーションに差はありませんが、RTLinuxは、マルチカーネルを作用しているため、リアルタイムアプリケーションは、カーネル内で実行するように作成し、FIFOを使って通信するように作成しなければなりません。

リアルタイム部分

リアルタイム部分
標準Linux用

リアルタイムアプリ

RedHat Linux
ユーザ

ケーション1/1

リケーション1/2

RedHat Enterprise Linux 5
割込み制御

2.6.26 RedHawk Linux

リアルタイムアプリケーション２／２

2.6.21 Linux +PREEMPT_RT
デバイスドライバ

デバイスドライバ

2.6.14 Linux
RealTime
Scheduler

Core0

Core1

Shared Memory
….

割込み制御

カーネル
空間

アプリケーションプログラム

FIFO

アプリケーションプログラム空間

リアルタイムアプ

Shared Memory
Core0

Core31

Core1•版の異なるカーネル•ただ１つのカーネル•異なるプログラムモデル•POSIXプログラムモデル(RedHat互換)•全てのアプリケーションがリアルタイムに •全てのアプリケーションがリアルタイムになります（ドライバ、ネットワーク、グラフィク

はなりません（ネットワークやグラフィクス）ス）•標準Linuxを低優先度スレッドとして実行します

このため、RT Linuxで、作成されているアプリケーションプログラムを移植するには、２つの方法が考えられます。

1.

RT Linuxのリアルタイムアプリケーション1/2+2/2のパートを一体になるように書き直す。

2.

RT Linuxの構造を模擬する。

１の方法は、移植の手間がかかりますが、より高速になり、２の方法は能力が１の方法に比べて劣り、エミュレートライブラリを新規に開発する必要があります。

また、RTLinuxのアプリケーションプログラムは、pthreadベースの関数で作成されているため、1/32

移植にはpthreadを利用することになると考えられます。しかし、リアルタイム拡張規格である
POSIX1003.1bは、シングルタスに対する規格であるため、Process/PthreadモデルでPOSIX1b関数を利用するためには、各の定義を正しく理解する必要があります。
標準Linuxのスレッド実装であるNPTL (Native POSIX Threads Library)は、新しい Pthreads の実装でLinux-Threadsと比べると、NPTL は POSIX.1 の要求仕様への準拠の度合いが高く、多数のスレッドを作成した際の性能も高くNPTLはLinux 2.6カーネルに実装されている機能を必要とします。
NPTLでは、一つのプロセスの全てのスレッドは同じスレッド・グループに属し、スレッド・グ
ループの全メンバーは同じProcessIDを共有すします。NPTLは管理スレッド (manager thread)を利用しません。NPTLは内部でリアルタイムシグナルのうち最初の2つの番号を使用していて、これらのシグナルはアプリケーションでは使用できません。さらに、NPTLにもPOSIX.1に準拠していない点があり、NPTLスレッドは同一プロセススレッドで、共通の nice 値を共有しません。
このことは、スレッド個別に優先度を設定する必要がある事を意味します。

RTLinux 関数から POSIX 関数へ
下記に、RTLinux 関数から POSIX 関数へのマッピング表を掲げます。
基本的には、rtl̲pthread̲xxx()関数は rtl̲部分を削除すれば移植が可能ですが、その意味が異なる場合がありますので、注意してください。
RT Linux V1 API
rt_get_time

rt_task_init
rt_task_delete
rt_task_make_periodic

RT Linux V2 API
gethrtime
システムが起動してからカウントを始めるリセットや調整が不可能な時間を返してくる関数
周波数は 1193180Hz によって管理している。
clock_gettime
時間を返してくる関数
周波数は 1193180Hz で時間を管理している gethrtime だと多少誤差がでてくるため他の方法で行っている。
以下の方法で時間を管理できる。
* CLOCK_REALTIME
The standard POSIX clock* CLOCK_8254
The clock that is used on non-SMP x86
systems* CLOCK_APIC
The local APIC clock on SMP x86
systems.

pthread_create
pthread_delete_np
pthread_make_periodic_np

2/32

RedHat/RedHawk/POSIX API
clock_gettime参照#include <time .h>
int clock_gettime (clockid_t which_clock,
struct timespec *setting) ;gcc [options] file -lccur_rt ...
引数は以下のように定義されます。
which_clock
それから時間を取得するクロックにおける識別子。which_clockの値は、CLOCK_REALTIMEまたはCLOCK_MONOTONICです。
setting
which_clockの時間が返される構造へのポインタ。
0の返り値はclock_gettimeへの呼び出しが成功したことを示します。-1の返り値はエラーが発生したことを示します。errnoはエラーを示すように設定されています。起こり得るエラーの種類のリストについてはclock_gettime (2) man pageを参照してくだ
さい。
同じ
なし
なし
Posix timerを使用しなければならないが、
timerは、プロセスに対してシグナルを発生

rt_task_wait

pthread_wait_np.
pthread_make_periodic_npによって指定された次の開始時間までスレッドを停止させる。

pthread_attr_getcpu_np.
RT-LinuxではどのスレッドがどのCPUで実行されているのか調べてくれない。また，スレッドは そのスレッドを呼び出したCPUで実行される。しかしRT-Linux は
そのスレッドがどこで実行されているかを聞いてくる。
そこでこの関数を用いてpthreadの属性を調べる。
pthread_attr_setreserve_np(V3)pthread_attr_setcpu_np.
pthreadの属性を変更する。
pthread_attr_getreserve_np(V3)pthread_delete_np.
リアルタイムスレッドを消去する。
pthread_setfp_np.
浮動小数点数の利用の可，不可を決定する。0 で不可，それ以外で可となる。
pthread_suspend_np.
pthread_wakeup_np を呼び出すまでスレ
ッドをサスペンドさせる。
pthread_wakeup_np.
pthread_suspend_np によってサスペンド
させたスレッドを復帰させる。

pthread_make_periodic_np.
周期的なスレッドを作成する。
pthread_linux
Comドライバ

rt_com_read.
シリアルポートからデータを読み込みこむ。
rt_com_setup.
シリアルポートに関するパラメータを変更する。
rt_com_table.3
シリアルポート 1 つにつき 1 つ作られるテーブルである。
rt_com_write.3
シリアルポートへデータを送る。

rtf
RT-FIFO 用のキャラクタ型デバイスのこと
メジャーナンバ 150，マイナーナンバ 063
デバイスファイルは"/dev/rtf"になる。
# rtf_create.
RT-FIFO を作る。 その際，名前とサイズを決定する。
rtf_create_handler
RT-FIFO 用のハンドラをインストールする。
ハンドラは Linux のプロセスが RT-FIFOにアクセスする度に呼び出される。
rtf_destroy
rtf_create によって作られた RT-FIFO の
削除。

3/32

させるので、pthreadに対して正しくシグナ
ルマスクを設定しなければなりません。
なし
プロセスをサスペンドさせたり、再起動させるpthread関数は存在しない。
任意のプロセス、スレッドから再起動させることの出来るメソッドはシグナルしかないため、sigwait()を使用する。
POSIXにこだわらないのであれば、server_block(),server_wake()が利用できる。
pthread_getaffinity_np()
CPUのアフィニティマスクを得る。
しかし、どのＣＰＵで実行されているかは、この関数では解らない。
実行されているＣＰＵを調べるためには、
mpadvise(MPA_PRC_GETRUN,MPA_TID,0,setp);
を使用する。

pthread_setaffinity()
CPUのアフィニティマスクを設定する。
なし
なし
なし
周期タイマーを停止させる。
なし
プロセスをサスペンドさせたり、再起動させるpthread関数は存在しない。
任意のプロセス、スレッドから再起動させることの出来るメソッドはシグナルしかないため、sigwait(),sigsupend()を使用する。
POSIXにこだわらないのであれば、server_block(),server_wake()が利用できる。
なし
周期タイマーを生成し、シグナルを発生させるなし
pthread_create()read()

tcseta(),ioctl()

write()

mkfifo()なし
メソッドはメッセージキューの通知スレ
ッドが最も近いclose(),unlink()

request_RTirq

free_RTirq
割り込みハンドラの開放

request_RTirq

rtf_get.
RT-FIFO からデータを読み込む。
rtf_put.
RT-FIFO へデータを書き込む。

read()

rtl_request_irq.
IRQ への割り込みを行うリアルタイムハ
ンドラのインストール。
rtl_free_irq.
IRQ への割り込みを行うリアルタイムハ
ンドラの開放。
rtl_get_soft_irq
ソフトウェアハンドラのインストール。
rtl_free_soft_irq.
ソフトウェアハンドラの開放。
rtl_getcpuid.
現在スレッドの実行されている CPU の IDを調べる。
rtl_getschedclock.
リアルタイムスケジューラの利用しているクロックの ID を返してくる。
rtl_global_pend_irq.
Linux への割り込みを行う IRQ のスケジ
ュールを決める。
rtl_hard_disable_irq.
IRQ を使用不可にする
rtl_hard_enable_irq.
IRQ を使用可にする。
rtl_allow_interrupts.
cpu への割り込み処理の許可。
rtl_no_interrupts.
割り込みに関するパラメータを保存してから割り込みの中止。
rtl_restore_interrupts.
rtl_no_interrupts によって保存されたパラメータを読み込んでから割り込み可能にする。
rtl_stop_interrupts.
cpu への割り込み処理の中止。
rtl_setclockmode.
クロックモードの設定。

なし

4/32

write()

なし
なし
なし
mpadvise()なし
常にCLOCK_REALTIME
なし
なし
なし
なし
なし
なし

なし
なし

RTLinux 関数の模擬
RTLinx 関数を模擬するプログラムのサンプルを下記に示します。
このプログラムは、RTLinux のサンプルプログラムである、frank プログラムを動作させるためのもので、RTLinux の関数の動作を標準 Linux の関数で模擬することで、移植における問題点を明確にすることができます。
RTLinux における frank プログラムは、カーネル空間スレッドである、frank_module.c とユーザ空間スレッドである、frank_app.c が FIFO を使って通信を行うものです。
RTLinux Module

Linux Process(frank̲module)(frank̲app)

RT-FIFO 4task[0]

RT-FIFO 1"frank"RT-FIFO 5

task[1]

RT-FIFO 2"Zappa"my̲handler()

RT-FIFO 3

コマンド

カーネル空間スレッド

ユーザ空間スレッド

このサンプルプログラムは、frank_module をリアルタイムスレッド、frank_app をタイムシェアリングスレッドとして、実行するためのライブラリです。
real-time threadtime-shareing thread(frank̲module)(frank̲app)

FIFO 4task[0]

FIFO 1"frank"FIFO 5task[1]

FIFO 2"Zappa"my̲handler()

FIFO 3

コマンド

ユーザ空間スレッド

ユーザ空間スレッド

5/32

RTLinux では、frank_module.c は、カーネルドライバモジュールであるため main()を持っていません。
そこで、ユーザ空間で実行可能にするため、frank_module.に以下の行を追加します。
int main(){init_valueue();//ライブラリ変数の初期化
init_module();pause();
cleanup_module();}ここで、RTLinux の構造を模擬するために、以下の置き換えを行います。
”RT-FIFO”→”named pipe”“カーネルスレッド”→“realtime pthread”“周期スケジューリングスレッド”→“POSIX タイマー待ち pthread”“rtf_get(),rtf_put()”→“非ブロック read(),非ブロック write()”“pthread_wakeup_np()”→“リアルタイムシグナルの送信”“pthread_wait_np()”→“リアルタイムシグナルの待ち“pthread_suspend_np()”→“POSIX タイマー停止”“pthread_make_periodic_np()”→”POSIX タイマーと pthread の生成”

“rtf_create_handler()”→“select()待ち pthread の生成”

“rtf_printf()”→”printf()”“gethrtime()”→“リアルタイムカウンタの読み出し”

この実装で、注意を要するのは、リアルタイムシグナルです。
リアルタイムシグナルは、NPTL の実装で利用しているため、SIGRTMIN+2 以上しか利用できません。
また、現在の NPTL では、POSIX タイマーはスレッドを生成できません。したがって、POSIX
タイマーハンドリングスレッドを生成し、そこから、ターゲットスレッドを呼び出す必要があります。そのうえ１つの RTLinux スレッドから複数の rtf_create_handler()を呼び出す可能性があるため、タイマーハンドリングスレッド毎に異なるリアルタイムシグナルを割り当てる必要があります。このため、最大でも(SIGRTMAX-SIGRTMIN-2)個のタイマースレッドしか生成出来
ません。
また、

6/32

では、実際の動作に従って、エミュレーションライブラリを使った frank_module.c の動作を詳しく見て行きます。
frank_module.c の関数 init_module()で、thread_code と my_handler の 2 種類のスレッドを作成しています。
frank_module.c より

pthread_attr_init (&attr);

優 先 度 ４ の thread_code

sched_param.sched_priority = 4;

pthread 生成

pthread_attr_setschedparam (&attr, &sched_param);
ret = pthread_create (&tasks[0],&attr, thread_code, (void *)1);

pthread_attr_init (&attr);

優 先 度 5 の thread_code
pthread 生成

sched_param.sched_priority = 5;
pthread_attr_setschedparam (&attr, &sched_param);
ret = pthread_create (&tasks[1],&attr, thread_code, (void *)2);

rtf_create_handler(3, &my_handler);

notification pthread 生成
このスレッドは daemon 型/*エミュレーションライブラリ */static void notification(void *arg){
unsigned int fifo,sno;
rtl_fifo_t *tcb;
int status=0,retval, fd_flags;
fifo = (int)arg;
tcb = &RTL_FIFO[fifo];tcb->flag=1;
while(tcb->flag){tcb->timeout.tv_sec = 0;
tcb->timeout.tv_usec = 500000;
FD_ZERO(&tcb->readfds);
FD_SET(tcb->f_id, &tcb->readfds);
retval = select(FD_SETSIZE,&tcb->readfds, NULL, NULL, &tcb->timeout);
if (retval>0)/* fifo にデータが到着すると True になる */{if (FD_ISSET(tcb->f_id, &tcb->readfds)){
tcb->handler(fifo);/*my_handler()はここから呼び出される*/}}}
pthread_exit((void*)&status);}

thread_code()では、関数の冒頭①でret = pthread_wait_np()を実行し、pthread_wakeup_np()
で起動されるか、次のスケジューリングタイムまでブロックされています。
このブロックは、my_handler()中②の pthread_wakeup_np()より起こされます。
pthread_wait_np()は、エミュレーション関数では、リアルタイムシグナル待ちの sigwait()③によって置き換えられていますので、pthread_wakeup()は、④の pthread_kill()に置き換えられ
ます。

7/32

void *thread_code(void *t){
int fifo = (int) t;
int taskno = fifo - 1;
struct my_msg_struct msg;
while (1) {int ret;int err;
ret = pthread_wait_np();/*①：下記②から起こされる*/
if ((err = rtf_get (taskno + TASK_CONTROL_FIFO_OFFSET,(char*) &msg, sizeof(msg))) == sizeof(msg)) {rtl_printf("Task %d: executing the ¥"%d¥" command to task %d; period %d¥n",
fifo - 1, msg.command, msg.task, msg.period);
switch (msg.command) {case START_TASK:
rtl_printf("RTLinux task: START_TASK: command¥n");pthread_make_periodic_np(pthread_self(), gethrtime(), msg.period * 1000);/*⑤*/
break;
case STOP_TASK:
rtl_printf("RTLinux task: STOP_TASK: command¥n");pthread_suspend_np(pthread_self());/*⑨*/
break;
default:
rtl_printf("RTLinux task: bad command¥n");return 0;}}
rtf_put(fifo, data[fifo - 1], 6);}
return 0;}
int my_handler(unsigned int fifo){
struct my_msg_struct msg;
int err;
while ((err = rtf_get(COMMAND_FIFO,(char*) &msg, sizeof(msg))) == sizeof(msg)) {rtf_put (msg.task + TASK_CONTROL_FIFO_OFFSET,(char*) &msg, sizeof(msg));
rtl_printf("FIFO handler: sending the ¥"%d¥" command to task %d; period %d¥n", msg.command,
msg.task, msg.period);
pthread_wakeup_np (tasks [msg.task]);/*②：上記①を起こす*/}
if (err != 0) {int pthread_wait_np(void)
return -EINVAL;{/*エミュレーションライブラリ */}sigset_t diset,eiset,oset;
return 0;
int ret,signo,tno;}
tno = get_tno(pthread_self());
sigfillset(&diset);for(signo=WAITSIGNAL;signo<=SIGRTMAX;signo++)int pthread_wakeup_np(pthread_t thread){{/*エミュレーションライブラリ */sigdelset(&diset,signo);
int tno;}tno = get_tno(pthread_self());
if (pthread_sigmask(SIG_BLOCK,&diset,&oset)==(-1))
RTL_TSD[tno].state=RTL_RUN;{
return(pthread_kill(thread, WAITSIGNAL)/*④*/);return (-1);}}
sigemptyset(&eiset);sigaddset(&eiset,WAITSIGNAL);
sigaddset(&eiset,RTL_TSD[tno].timer_sno);
sigaddset(&eiset,SIGINT);
sigaddset(&eiset,SIGIO);
RTL_TSD[tno].state=RTL_SUSPEND;
ret = sigwait(&eiset,&signo);/*③*/
RTL_TSD[tno].state=RTL_RUN;
if (pthread_sigmask(SIG_SETMASK,&oset,&eiset)==(-1)){
return (-1);}
return(ret);}

8/32

pthread_wakeup_np()によって起こされたスレッドは、rtf_get()の START_TASK メッセージによって⑤の pthread_make_periodic_np(pthread_self(), gethrtime(), msg.period * 1000);が実行されます。
int pthread_make_periodic_np(pthread_t thread,hrtime_t start_time,hrtime_t period){/*エミュレーションライブラリ */static struct sigevent event;int pthread_suspend_np(pthread_t thread)static timer_t timer;{*エミュレーションライブラリ */static struct itimerspec itspec;
int tno;int tno;tno = get_tno(pthread_self());
void * val=NULL;
if (pthread_equal(pthread_self(),thread) )tno = get_tno(thread);{/* Create the POSIX timer to generate signum */if (RTL_TSD[tno].timer_key!=((timer_t)-1))
event.sigev_notify = SIGEV_SIGNAL;/*⑥*/
timer_delete(RTL_TSD[tno].timer_key);/*⑩*/
RTL_TSD[tno].timer_sno = event.sigev_signo = get_sno();}else{
if (event.sigev_signo < (WAITSIGNAL+1))
return(pthread_kill(thread, WAITSIGNAL));/*⑪*/{}
return (-1);}}
if (timer_create((clockid_t)CLOCK_REALTIME,&event,&timer)==(-1))/*⑦*/{
RTL_TSD[tno].timer_key=(timer_t)-1;
return (-1);}/* Set the initial delay and period of the timer.
This also arms the timer */clock_gettime(CLOCK_REALTIME,&itspec.it_value);
start_time+=10000LL;
itspec.it_value.tv_sec = (unsigned long int)(start_time>>32);
itspec.it_value.tv_nsec = (unsigned long int)(start_time & 0xFFFFFFFFLL);
itspec.it_interval.tv_sec = (unsigned long int)(period>>32);
itspec.it_interval.tv_nsec = (unsigned long int)(period & 0xFFFFFFFFLL);
if (timer_settime( timer, TIMER_ABSTIME, &itspec, NULL)==(-1))/*⑧*/{
RTL_TSD[tno].timer_key=(timer_t)-1;
return (-1);}
RTL_TSD[tno].timer_key=timer;
RTL_TSD[tno].state=RTL_RUN;
sched_yield();
return(0);}この関数は、スレッドを周期的に呼び出すための API で、スレッドの開始時間 start_time と呼び出す周期 period を hrtime_t 型変数として取ります。hrtime_t 型変数は long long 型として定義されています。
エミュレーションライブラリでは、⑥イベントとしてリアルタイムシグナルを定義し、⑦POSIX タイマーを生成し、起動時間を⑧で設定しています。
この動作によって、呼び出したスレッドに対して、リアルタイムシグナルが発信されますが、この実装では、自分自身にしかイベントは送信されないため、完全なエミュレーションを実現するためには、管理スレッドを生成し、そのスレッドから改めて、pthread_kill()を発行する必要があります。
同様に、rtf_get()の STOP_TASK メッセージによって⑨のpthread_suspend_np(pthread_self());が実行された場合には、エミュレーションライブラリで、⑩タイマーを停止し、⑪pthread_kill()を実行します。

9/32

下記にこの実装の全てのソースコードを掲げますが、この説明に必要ない機能は、コメントになっています。
/*
rtl.h*/#ifndef ̲̲RTL̲H̲̲
#define ̲̲RTL̲H̲̲
#include <stdio.h>#include <pthread.h>#include <limits.h>#include <time.h>#include <mqueue.h>#include <signal.h>#include <errno.h>#include <sys/time.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <fcntl.h>#include <sched.h>#include <string.h>#include <sys/mman.h>#include <cpuset.h>#include <sched.h>#include <mpadvise.h>#include <termios.h>#define ̲̲EMULATE̲RTLINUX̲̲
#define hrtime̲t long long/* Section 2 */#define rtl̲close#define rtl̲ftruncate#define rtl̲gpos̲unlink#define rtl̲inb#define rtl̲inb̲p#define rtl̲inl#define rtl̲inl̲p#define rtl̲inw#define rtl̲inw̲p#define rtl̲ioctl#define rtl̲lseek#define rtl̲mmap#define rtl̲munmap#define rtl̲open#define rtl̲outb#define rtl̲outb̲p#define rtl̲outl#define rtl̲outl̲p#define rtl̲outw#define rtl̲outw̲p#define rtl̲read#define rtl̲shm̲open#define rtl̲shm̲unlink#define rtl̲unlink#define rtl̲write

close
rtl̲ftruncate
unlink
inb
inb̲p
inl
inl̲p
inw
inw̲p
ioctl
lseek
mmap
unmap
open
outb
outb̲poutl
outl̲poutw
outw̲pread
shm̲openshm̲unlink
unlinkwrite/* Section 3 *//* malloc */#definertl̲size̲t#define rtl̲rt̲malloc#define rtl̲rt̲free#define rtl̲rt̲realloc/* calloc */size̲tmallocfree
realloc

10/32

#define
rtl̲rt̲calloc calloc//void *rtl̲rt̲malloc̲pool(int pool, rtl̲size̲t size);//void *rtl̲rt̲calloc̲pool(int pool, rtl̲size̲t nmemb, rtl̲size̲t size);//int rtl̲init̲mem̲pool(int pool, int type, int chunksize, int numchunks);//void rtl̲cleanup̲mem̲pool(int pool);/* debugpr */#definedebugprprintf/* onewayq */ // not support
int rtf̲create(unsigned int fifo,int size);
int rtf̲create̲handler(unsigned int fifo,int (*handler)(unsigned int fifo) );#define rtf̲create̲rt̲handler
rtf̲create̲handler
int rtf̲destroy(unsigned int fifo);
int rtf̲flush(unsigned int fifo);
int rtf̲get(unsigned int fifo,char *buff,int count);// rtf̲isempty// rtf̲isused// rtf̲link̲user̲ioctl// rtf̲make̲user̲pair
int rtf̲put(unsigned int fifo,char *buff,int count);// rtf̲resize// rtl̲a̲clear// rtl̲a̲decr// rtl̲a̲incr// rtl̲allow̲interrupts// rtl̲a̲set// rtl̲breakpoint// rtl̲cleanup̲mem̲pool
hrtime̲t clock̲gethrtime(clockid̲t clock);#define RTL̲CLOCK̲REALTIME CLOCK̲REALTIME#define rtl̲timespec timespec#define rtl̲clockid̲tclockid̲t#define rtl̲clock̲getres clock̲getres#define rtl̲clock̲gettime clock̲gettime#define rtl̲clock̲nanosleep
clock̲nanosleep#define rtl̲clock̲settime clock̲settime
int rtl̲cpu̲exists (int cpu);// rtl̲decr̲dev̲usage// rtl̲free̲irq// rtl̲free̲soft̲irq// rtl̲freq̲cur// rtl̲freq̲list// rtl̲freq̲set// rtl̲getcpuid// rtl̲get̲soft̲irq// rtl̲global̲pend̲irq// rtl̲gpos̲free// rtl̲gpos̲malloc// rtl̲gpos̲register̲dev// rtl̲gpos̲unregister̲dev// rtl̲hard̲disable̲irq// rtl̲hard̲enable̲irq// rtl̲incr̲dev̲usage// rtl̲init̲mem̲pool// rtl̲irq̲set̲affinity#definertl̲longjmp longjmp#define rtl̲jmp̲buf
jmp̲buf#definertl̲main̲wait pause#definertl̲mkfifo
mkfifo#definertl̲mode̲t mode̲t// rtl̲namei#define rtl̲nanosleep
nanosleep// rtl̲no̲interrupts
int rtl̲num̲cpus(void);#define rtl̲perror
perror#define rtl̲printf
printf#define rtl̲pthread̲t rtl̲pthread#define rtl̲pthread̲attr̲destroy
pthread̲attr̲destroy#define rtl̲pthread̲attr̲tpthread̲attr̲t// rtl̲pthread̲attr̲getcpu̲np#define rtl̲pthread̲attr̲getdetachstatepthread̲attr̲getdetachstate// rtl̲pthread̲attr̲getfp̲np// rtl̲pthread̲attr̲getreserve̲np

11/32

#define rtl̲pthread̲attr̲getschedparam
pthread̲attr̲getschedparam#define rtl̲pthread̲attr̲getstackaddr
pthread̲attr̲getstackaddr#define rtl̲pthread̲attr̲getstacksize
pthread̲attr̲getstacksize#define rtl̲pthread̲attr̲init
pthread̲attr̲init// rtl̲pthread̲attr̲setcpu̲np#define rtl̲pthread̲attr̲setdetachstatepthread̲attr̲setdetachstate// rtl̲pthread̲attr̲setfp̲np// rtl̲pthread̲attr̲setreserve̲np#define rtl̲pthread̲attr̲setschedparam
pthread̲attr̲setschedparam#define rtl̲pthread̲attr̲setstackaddr
pthread̲attr̲setstackaddr#define rtl̲pthread̲attr̲setstacksize
pthread̲attr̲setstacksize#define rtl̲pthread̲cancel
pthread̲cancel#define rtl̲pthread̲cleanup̲pop
pthread̲cleanup̲pop#define rtl̲pthread̲cleanup̲push
pthread̲cleanup̲push#define rtl̲pthread̲condattr̲tpthread̲condattr̲t#define rtl̲pthread̲condattr̲destroy
pthread̲condattr̲destroy#define rtl̲pthread̲condattr̲getpsharedpthread̲condattr̲getpshared#define rtl̲pthread̲condattr̲init
pthread̲condattr̲init#define rtl̲pthread̲condattr̲setpsharedpthread̲condattr̲setpshared#define rtl̲pthread̲cond̲broadcast
pthread̲cond̲broadcast#define rtl̲pthread̲cond̲destroy
pthread̲cond̲destroy#define rtl̲pthread̲cond̲init
pthread̲cond̲init#define rtl̲pthread̲cond̲signal
pthread̲cond̲signal#define rtl̲pthread̲cond̲timedwait
pthread̲cond̲timedwait#define rtl̲pthread̲cond̲wait
pthread̲cond̲wait
int rtl̲pthread̲create(pthread̲t *thread, pthread̲attr̲t *attr, void *(*start̲routine)(void *), void *arg);// rtl̲pthread̲delete̲np#define rtl̲pthread̲detachpthread̲detach#define rtl̲pthread̲equal
pthread̲equal#define rtl̲pthread̲exit
pthread̲exit#define rtl̲pthread̲getcpuclockid
pthread̲getcpuclockid#define rtl̲pthread̲getschedparam
pthread̲getschedparam#define rtl̲pthread̲getspecificpthread̲getspecific#define rtl̲pthread̲idle
pause#define rtl̲pthread̲join
pthread̲join#define rtl̲pthread̲key̲create
pthread̲key̲delete#define rtl̲pthread̲key̲delete
pthread̲key̲delete#define rtl̲pthread̲kill
pthread̲kill#define rtl̲pthread̲linux
pause#define rtl̲pthread̲mutex̲tpthread̲mutex̲t#define rtl̲pthread̲make̲periodic̲np
pthread̲make̲periodic̲np#define rtl̲pthread̲mutexattr̲destroy
pthread̲mutexattr̲destroy#define rtl̲pthread̲mutexattr̲getprioceiling
pthread̲mutexattr̲getprioceiling#define rtl̲pthread̲mutexattr̲getprotocol
pthread̲mutexattr̲getprotocol#define rtl̲pthread̲mutexattr̲getpsharedpthread̲mutexattr̲getpshared#define rtl̲pthread̲mutexattr̲gettype
pthread̲mutexattr̲gettype#define rtl̲pthread̲mutexattr̲init
pthread̲mutexattr̲init#define rtl̲pthread̲mutexattr̲setprioceiling
pthread̲mutexattr̲setprioceiling#define rtl̲pthread̲mutexattr̲setprotocol
pthread̲mutexattr̲setprotocol#define rtl̲pthread̲mutexattr̲setpsharedpthread̲mutexattr̲setpshared#define rtl̲pthread̲mutexattr̲settype
pthread̲mutexattr̲settype#define rtl̲pthread̲mutex̲destroy
pthread̲mutex̲destroy#define rtl̲pthread̲mutex̲getprioceiling
pthread̲mutex̲getprioceiling#define rtl̲pthread̲mutex̲init
pthread̲mutex̲init#define rtl̲pthread̲mutex̲lock
pthread̲mutex̲lock#define rtl̲pthread̲mutex̲setprioceiling
pthread̲mutex̲setprioceiling#define rtl̲pthread̲mutex̲timedlock
pthread̲mutex̲timedlock#define rtl̲pthread̲mutex̲trylock
pthread̲mutex̲trylock#define rtl̲pthread̲mutex̲unlock
pthread̲mutex̲unlock#define rtl̲pthread̲self
pthread̲self#define rtl̲pthread̲setcancelstatepthread̲setcancelstate#define rtl̲pthread̲setcanceltype
pthread̲setcanceltype// rtl̲pthread̲setfp̲np#define rtl̲pthread̲setschedparam
pthread̲setschedparam#define rtl̲pthread̲setspecificpthread̲setspecific#define rtl̲pthread̲spin̲destroy
pthread̲spin̲destroy#define rtl̲pthread̲spin̲init
pthread̲spin̲init#define rtl̲pthread̲spin̲lock
pthread̲spin̲lock#define rtl̲pthread̲spin̲trylock
pthread̲spin̲trylock#define rtl̲pthread̲spin̲unlock
pthread̲spin̲unlock
int pthread̲suspend̲np(pthread̲t thread);#define rtl̲pthread̲testcancel
pthread̲testcancel
int pthread̲wait̲np(void);

12/32

int pthread̲wakeup̲np(pthread̲t thread);//rtl̲put̲circle//rtl̲put̲fillcircle//rtl̲put̲fillrect//rtl̲put̲line//rtl̲put̲pixel//rtl̲put̲rect//rtl̲put̲text//rtl̲register̲dev//rtl̲register̲rtldev//rtl̲request̲irq//rtl̲restore̲interrupts//rtl̲rt̲calloc//rtl̲rt̲calloc̲pool//rtl̲rt̲free//rtl̲rt̲malloc//rtl̲rt̲malloc̲pool//rtl̲rt̲realloc#define rtl̲sched̲get̲priority̲max#define rtl̲sched̲get̲priority̲min#define rtl̲sched̲yield#define rtl̲sem̲t#define rtl̲sem̲close#define rtl̲sem̲destroy#define rtl̲sem̲getvalue#define rtl̲sem̲init#define rtl̲sem̲open#define rtl̲sem̲post#define rtl̲sem̲timedwait#define rtl̲sem̲trywait#define rtl̲sem̲unlink#define rtl̲sem̲wait#definertl̲jmp̲buf#define rtl̲setjmp#define rtl̲sigaction// rtl̲stop̲interrupts// rtl̲test̲bit̲and̲clear// rtl̲test̲bit̲and̲set#define rtl̲timespec// rtl̲timespec̲add// rtl̲timespec̲add̲ns// rtl̲timespec̲eq// rtl̲timespec̲from̲ns// rtl̲timespec̲ge// rtl̲timespec̲gt// rtl̲timespec̲le// rtl̲timespec̲lt// rtl̲timespec̲normalize// rtl̲timespec̲nz// rtl̲timespec̲sub// rtl̲timespec̲to̲ns#define rtl̲uname// rtl̲unregister̲dev// rtl̲unregister̲rtldev#define rtl̲usleep// sched̲get̲cpufreq̲max// sched̲get̲cpufreq̲min#define WAITSIGNAL
typedef struct{timer̲t
int
int
int
int
pthread̲t} rtltsd̲t;get̲priority̲max
get̲priority̲minsched̲yieldsem̲tsem̲closesem̲destroysem̲getvaluesem̲initsem̲opensem̲post
sem̲timedwait
sem̲trywait
sem̲unlink
sem̲wait
jmp̲buf
setjmpsigaction

timespec

uname
usleep(SIGRTMIN+2)

timer̲key;
timer̲sno;
state;
request;tno;
pid;

typedef struct
{

13/32

int flag;char
f̲name[256];int (*handler)(unsigned int fifo);
pthread̲attr̲tattributes;#ifdef MESSAGE̲QUEUE
mqd̲t f̲id;
struct mq̲attr f̲attr;
struct sigevent notification;#else
int f̲id;pthread̲t pid;//struct timespec timeout;
struct timeval timeout;
sigset̲t sigmask;fd̲set readfds;#endif} rtl̲fifo̲t;#define RTL̲SUSPEND (0)#define RTL̲RUN(1)

hrtime̲t gethrtime(void);void init̲valueue(void);
int pthread̲make̲periodic̲np(pthread̲t thread,hrtime̲t start̲time,hrtime̲t period);
int pthread̲suspend̲np(pthread̲t thread);int pthread̲wait̲np(void);
int pthread̲wakeup̲np(pthread̲t thread);int pthread̲attr̲setcpu̲np(const pthread̲attr̲t *attr,int cpu);
int pthread̲attr̲getcpu̲np(const pthread̲attr̲t *attr,int *cpu);#endif /* ̲̲RTL̲H̲̲ */

14/32

/*
rtl.c
*/
#include <rtl.h>static rtltsd̲t RTL̲TSD[̲POSIX̲THREAD̲THREADS̲MAX];
static rtl̲fifo̲t RTL̲FIFO[̲POSIX̲THREAD̲THREADS̲MAX];
static int RTL̲NUMBER=0;
static int SNO̲NUMBER=0;
static int Stop̲flag=0;
static int global̲setup̲signal(int signo, void (*interrupt̲handler)(int,siginfo̲t *, void *)){static struct sigaction newact;
static sigset̲t set,oset;
if (sigprocmask(0,NULL,&set)==(-1)){
return(-1);}
sigdelset(&set,signo);
if (sigprocmask(SIG̲SETMASK,&set,&oset)==(-1)){
return(-2);}
sigemptyset(&newact.sa̲mask);sigaddset(&newact.sa̲mask,signo);
newact.sa̲sigaction = interrupt̲handler;
newact.sa̲flags = SA̲SIGINFO|SA̲RESTART;
if (sigaction(signo, &newact, 0)==(-1)){
return(-3);}
return(0);}static void sigint̲handler(int signo, siginfo̲t *siginfo, void *misc){if ((siginfo->si̲pid==0)||(getpid()==siginfo->si̲pid)|| (getppid()==siginfo->si̲pid)){
fprintf(stderr,"\nSIG%d DETECT\n",signo);
Stop̲flag = 1;}}
void wait̲module(void){
while(Stop̲flag==0) pause();}void init̲valueue(void){
int fifo,sno;
sigset̲t diset,oset;
struct sched̲param myparam;
SNO̲NUMBER=WAITSIGNAL+1;
sigemptyset(&diset);sigaddset(&diset,WAITSIGNAL);
for(sno=WAITSIGNAL+1;sno<=SIGRTMAX;sno++){sigaddset(&diset,sno);}
sigprocmask(SIG̲BLOCK,&diset,&oset);
memset(RTL̲TSD,0,sizeof(RTL̲TSD));
memset(RTL̲FIFO,0,sizeof(RTL̲FIFO));
RTL̲NUMBER=0;
for(fifo=0;fifo<̲POSIX̲THREAD̲THREADS̲MAX;fifo++){
RTL̲FIFO[fifo].f̲id = -1;}
myparam.sched̲priority = sched̲get̲priority̲max(SCHED̲FIFO);
sched̲setscheduler(getpid(),SCHED̲FIFO,&myparam);

15/32

mlockall(MCL̲CURRENT|MCL̲FUTURE);
global̲setup̲signal(SIGINT,sigint̲handler);}static int get̲sno(void){
int sno;sno = SNO̲NUMBER;
if (sno>=SIGRTMAX)++SNO̲NUMBER;
return(sno);}

return(-1);

static int get̲tno(pthread̲t pid){
int tno;if (RTL̲NUMBER){
for (tno=0;tno<RTL̲NUMBER;tno++){if (pthread̲equal(RTL̲TSD[tno].pid,pid) ){return(tno);}}}
tno = RTL̲NUMBER;++RTL̲NUMBER;
RTL̲TSD[tno].pid = pid;
RTL̲TSD[tno].tno = tno;
return(tno);}
int pthread̲wait̲np(void){
sigset̲t diset,eiset,oset;
int ret,signo,tno;
tno = get̲tno(pthread̲self());
resume:{sigfillset(&diset);for(signo=WAITSIGNAL;signo<=SIGRTMAX;signo++){sigdelset(&diset,signo);}if (pthread̲sigmask(SIG̲BLOCK,&diset,&oset)==(-1)){
return (-1);}
sigemptyset(&eiset);sigaddset(&eiset,WAITSIGNAL);
sigaddset(&eiset,RTL̲TSD[tno].timer̲sno);
sigaddset(&eiset,SIGINT);
sigaddset(&eiset,SIGIO);
RTL̲TSD[tno].state=RTL̲SUSPEND;
ret = sigwait(&eiset,&signo);
RTL̲TSD[tno].state=RTL̲RUN;
if (pthread̲sigmask(SIG̲SETMASK,&oset,&eiset)==(-1)){
return (-1);}}//printf("pthread̲wait̲np(ret)\n");return(ret);}hrtime̲t clock̲gethrtime(clockid̲t clock){
struct timespec nowtime;long long x;

16/32

clock̲gettime(clock,&nowtime);
x = (long long)nowtime.tv̲sec << 32;
x |= (long long)nowtime.tv̲nsec;
return(x);}int rtl̲cpu̲exists (int cpu){
cpuset̲t* setp;
char *cpustr;
int ret,mask;
setp = cpuset̲alloc();
cpuset̲init(setp);
ret = mpadvise (MPA̲CPU̲PRESENT,0,0,setp);
if (ret!=MPA̲FAILURE){
cpustr = cpuset̲get̲string(setp);
mask= strtol(cpustr, (char **)NULL, 16);free(cpustr);
return(mask & cpu);}
free(cpustr);
return(-1);}
int rtl̲num̲cpus(void){
cpuset̲t* setp;
char *cpustr;
int ret,cpu,mask;
setp = cpuset̲alloc();
cpuset̲init(setp);
ret = mpadvise (MPA̲CPU̲ACTIVE,0,0,setp);
if (ret!=MPA̲FAILURE){
free(cpustr);
return ( cpuset̲count(setp) );}free(cpustr);
return(-1);}
hrtime̲t gethrtime(void){
struct timespec nowtime;long long x;
clock̲gettime(CLOCK̲REALTIME,&nowtime);
x = (long long)nowtime.tv̲sec << 32;
x |= (long long)nowtime.tv̲nsec;
return(x);}int pthread̲make̲periodic̲np(pthread̲t thread,hrtime̲t start̲time,hrtime̲t period){
static struct sigevent event;static timer̲t timer;
static struct itimerspec itspec;
int tno,policy;
void * val=NULL;
struct sched̲param param;
pthread̲getschedparam(pthread̲self(),&policy,(struct sched̲param *)&param);
param.sched̲priority = sched̲get̲priority̲max(SCHED̲FIFO);
pthread̲setschedparam(pthread̲self(),SCHED̲FIFO,(const struct sched̲param *)&param);
tno = get̲tno(thread);/* Create the POSIX timer to generate signum */event.sigev̲notify = SIGEV̲SIGNAL;

17/32

RTL̲TSD[tno].timer̲sno = event.sigev̲signo = get̲sno();if (event.sigev̲signo < (WAITSIGNAL+1)){
return (-1);}
if (timer̲create((clockid̲t)CLOCK̲REALTIME,&event,&timer)==(-1)){
RTL̲TSD[tno].timer̲key=(timer̲t)-1;
return (-1);}/*
Set the initial delay and period of the timer.
This also arms the timer */clock̲gettime(CLOCK̲REALTIME,&itspec.it̲value);
start̲time+=10000LL;
itspec.it̲value.tv̲sec = (unsigned long int)(start̲time>>32);
itspec.it̲value.tv̲nsec = (unsigned long int)(start̲time & 0xFFFFFFFFLL);
itspec.it̲interval.tv̲sec = (unsigned long int)(period>>32);
itspec.it̲interval.tv̲nsec = (unsigned long int)(period & 0xFFFFFFFFLL);
if (timer̲settime( timer, TIMER̲ABSTIME, &itspec, NULL)==(-1)){
RTL̲TSD[tno].timer̲key=(timer̲t)-1;
return (-1);}
RTL̲TSD[tno].timer̲key=timer;
RTL̲TSD[tno].state=RTL̲RUN;
sched̲yield();
return(0);}int pthread̲wakeup̲np(pthread̲t thread){
int tno;tno = get̲tno(pthread̲self());
RTL̲TSD[tno].state=RTL̲RUN;
return(pthread̲kill(thread, WAITSIGNAL));}int pthread̲suspend̲np(pthread̲t thread){
int tno;tno = get̲tno(pthread̲self());
if (pthread̲equal(pthread̲self(),thread) ){if (RTL̲TSD[tno].timer̲key!=((timer̲t)-1))
timer̲delete(RTL̲TSD[tno].timer̲key);}else{
return(pthread̲kill(thread, WAITSIGNAL));}}static void notification(void *arg) /* スレッド開始関数 */{unsigned int fifo,sno;
rtl̲fifo̲t *tcb;
int status=0,retval, fd̲flags;
fifo = (int)arg;
tcb = &RTL̲FIFO[fifo];tcb->flag=1;
while(tcb->flag){tcb->timeout.tv̲sec = 0;
tcb->timeout.tv̲usec = 500000;
FD̲ZERO(&tcb->readfds);
FD̲SET(tcb->f̲id, &tcb->readfds);
retval = select(FD̲SETSIZE,&tcb->readfds, NULL, NULL, &tcb->timeout);
if (retval>0){
if (FD̲ISSET(tcb->f̲id, &tcb->readfds))
{

18/32

tcb->handler(fifo);}}}
pthread̲exit((void*)&status);}
int rtf̲create̲handler(unsigned int fifo,int (*handler)(unsigned int fifo) ){rtl̲fifo̲t *tcb;
tcb = &RTL̲FIFO[fifo];
if (pthread̲attr̲init(&tcb->attributes)){
return(-1);}
if (pthread̲attr̲setscope(&tcb->attributes,PTHREAD̲SCOPE̲SYSTEM)){
return(-1);}
if (pthread̲attr̲setdetachstate(&tcb->attributes,PTHREAD̲CREATE̲DETACHED)){
return(-1);}
if (pthread̲attr̲setinheritsched(&tcb->attributes,PTHREAD̲INHERIT̲SCHED)){
return(-1);}
tcb->handler = handler;if (pthread̲create(&tcb->pid,&tcb->attributes,(void*)notification,(void *)fifo) < 0){return(-1);}
return(0);}int rtf̲create(unsigned int fifo,int size){rtl̲fifo̲t *tcb;
tcb = &RTL̲FIFO[fifo];tcb->flag=0;
sprintf(tcb->f̲name,"/dev/rtf%d",fifo);
if (size>4096){
return(-1);}
if (mkfifo(tcb->f̲name, 0666)<0){
return(-1);}
tcb->f̲id = open(tcb->f̲name,O̲RDWR|O̲NONBLOCK,0666);
return(tcb->f̲id);
return(0);}int rtf̲destroy(unsigned int fifo){rtl̲fifo̲t *tcb;
tcb = &RTL̲FIFO[fifo];
if (tcb->f̲id!=(-1)){
close(tcb->f̲id);tcb->f̲id = -1;}
sprintf(tcb->f̲name,"/dev/rtf%d",fifo);
if (!access(tcb->f̲name,F̲OK)){
unlink(tcb->f̲name);}if (tcb->flag)

19/32

{
tcb->flag=0;
if (tcb->pid) pthread̲kill(tcb->pid,SIGINT);
tcb->pid=0;}
return(0);}int rtf̲put(unsigned int fifo,char *buff,int count){rtl̲fifo̲t *tcb;
int ret;tcb = &RTL̲FIFO[fifo];
ret = write(tcb->f̲id,buff,count);
return(ret);}
int rtf̲get(unsigned int fifo,char *buff,int count){rtl̲fifo̲t *tcb;
tcb = &RTL̲FIFO[fifo];
return(read(tcb->f̲id,buff,count));}
int rtf̲flush(unsigned int fifo){rtl̲fifo̲t *tcb;
tcb = &RTL̲FIFO[fifo];
return(tcflush(tcb->f̲id,TCIOFLUSH));}int pthread̲attr̲setcpu̲np(const pthread̲attr̲t *attr,int cpu){
cpuset̲t*cpuset;int ret;cpuset = cpuset̲alloc();
cpuset̲init(cpuset);
cpuset̲set̲cpu(cpuset,cpu,1);/* CPU set */ret = pthread̲attr̲setaffinity̲np(attr, sizeof(cpuset), cpuset);
cpuset̲free(cpuset);
return(ret);}
int pthread̲attr̲getcpu̲np(const pthread̲attr̲t *attr,int *cpu){
cpuset̲t*cpuset;char *str;
int i,ret;
cpuset = cpuset̲alloc();
cpuset̲init(cpuset);
ret = pthread̲attr̲getaffinity̲np(attr, sizeof(cpuset), cpuset);*cpu=-1;for(i=cpuset̲min̲cpu();i<cpuset̲max̲cpu();i++){if (cpuset̲get̲cpu(cpuset,i)) *cpu = i;}
cpuset̲free(cpuset);
return(ret);}
int rtl̲pthread̲create(pthread̲t *thread, pthread̲attr̲t *attr, void *(*start̲routine)(void *), void *arg){
struct sched̲param param;
pthread̲attr̲setschedpolicy(attr,SCHED̲FIFO);
param.sched̲priority = sched̲get̲priority̲max(SCHED̲FIFO);

20/32

pthread̲attr̲setschedparam(attr,&param);
return(pthread̲create(thread, attr, start̲routine, arg));}
int rtl̲gpos̲mknod(const char *pathname, int mode, int major, int minor){
return(mknod(pathname,(mode̲t)(mode|S̲IFCHR),(dev̲t)((major<<16)|(minor))));
}

21/32

標準 pthread によるミニスケジューラーの実装
前節の frank̲module.c,frank̲app.c の実装は、周期の異なるスレッドを制御する RTLinux のプログラム例でした。しかし、RedHawk では、標準 API だけで、このプログラムモデルを構築できます。
下記のプログラムは、POSIX リアルタイムタイマーを使って、複数のスレッドをスケジュール
するプログラム例です。

tswitch.c では、２つのスレッドを生成し、１つの POSIX タイマーをつかって制御します。
POSIX タイマーは、1ms のインターバル割り込みを生成し、sigsuspend();に割り込む形でinterval̲handler()が実行されます。

do̲main()create̲timer();thread̲main0
while(1){sigsuspend()；

1KHz 割り込み

interval̲handler()}thread̲main1()

thread̲main2()

interval̲handler()では、割り込みの数を GLOBAL̲COUNTER でカウントし、任意のメジャー周期を作り出し、pthread̲mutex(),pthread̲cond()によって thread̲main1(),thread̲main2()に対して起動を繰り返しています。スレッドを起動停止しているのは、pthread̲mutex と pthread̲cond
関数で、この２種類は、以下の様にペアで使用します。

スレッド側

シグナルハンドラー側

pthread_mutex_lock (&Mutex);if(Event==0) pthread_cond_wait(&Condition,&Mutex);
Event--;
pthread_mutex_unlock(&Mutex);

pthread_mutex_lockMUTEX_LOCK(&Mutex);
Event++;
pthread_cond_signal(&Condition);pthread_mutex_unlock(&Mutex);

pthread_mutex_lock()/pthread_mutex_unlock()は、mutex 変数 Mutex で、クリティカ
ルセクションを作っています。
この例でのクリティカルセクションデータは Event で、この値を操作する間、Mutex で保護されています。今、スレッド側で、Evant の値が０である（つまりイベントが無い）
とき、スレッドは、pthread_mutex_cond_wait()で、Mutex を解放し、Condition 変数で、眠りにつきます。シグナルハンドラーは、POSIX タイマーにより起動され、スレッドが22/32

Mutex を解放している間に、Event を加算し、pthread_cond_signal()を発行します。
休眠状態にあった、スレッドは、シグナルハンドラーが Mutex を解放した時に、
pthread_cond_wait()から目覚め、そのとき再び Mutex をロックします。
この動作で、Mutex 変数 Event はイベントカウンターとして動作するため、イベントを失うことなく、スレッドの実行−停止を繰り返すことができます。
したがって、スレッド側の完全な記述は以下のようになります。
do{pthread_mutex_lock(&Mutex[1]);if(Event[1]==0){
pthread_cond_wait(&Condition[1],&Mutex[1]);}else{/* オーバーラン状態 */}Event[1]--;pthread_mutex_unlock(&Mutex[1]);/*ここで必要な動作を行う; */} while (loop_flag);

23/32

tswitch.c のリスト
#include <stdio.h>#include <errno.h>#include <sys/types.h>#include <time.h>#include <signal.h>#include <string.h>#include <unistd.h>#include <mpadvise.h>#include <pthread.h>#include <locale.h>#include <cpuset.h>#include <stdlib.h>#include <math.h>#define CYCLE#define THREAD̲NO
char

1000
3

*progname,*lang;volatile sig̲atomic̲t loop̲flag=1,GlobalCounter=0;
sigset̲t diset,oset,eiset;#define TESTNUMBER#define MAXJITTER

10000
(30)

pthread̲cond̲t Condition[THREAD̲NO];#define COND̲SIGNAL
pthread̲cond̲signal#define COND̲WAIT
pthread̲cond̲wait
pthread̲mutex̲t Mutex[THREAD̲NO];#define MUTEX̲LOCK
pthread̲mutex̲lock#define MUTEX̲UNLOCK
pthread̲mutex̲unlock
int Event[THREAD̲NO]={0,0,0};
float SwitchTime1[TESTNUMBER/2];
float SwitchTime2[TESTNUMBER/2];
float IntervalTime[TESTNUMBER];
struct timespec StartTime={0,0},EndTime={0,0};
struct timespec CurrrentTime={0,0};
void
readtime(struct timespec *nowtime){clock̲gettime(CLOCK̲REALTIME,nowtime);}void
adjust(struct timespec *start,struct timespec *finish, float *realtime){
int
sec,nsec;
sec = finish->tv̲sec - start->tv̲sec;
nsec = finish->tv̲nsec - start->tv̲nsec;
if (nsec<0){
sec --;
nsec += 1000000000;}*realtime = (float)(nsec/1000)+(float)(sec*1000000);}
timer̲tcreate̲posix̲timer(int signum,int sec,int nsec){
static struct sigevent event;static timer̲t timer;
static struct itimerspec itspec;/* Create the POSIX timer to generate signum */event.sigev̲notify = SIGEV̲SIGNAL;

24/32

//event.sigev̲notify = SIGEV̲THREAD;
event.sigev̲signo = signum;
if (timer̲create((clockid̲t)CLOCK̲REALTIME,&event,&timer)==(-1)){
fprintf(stderr, "create̲posix̲timer() Cannot create timer - %s\n",strerror(errno));return ((timer̲t)-1);}/*
Set the initial delay and period of the timer.
This also arms the timer */clock̲gettime(CLOCK̲REALTIME,&itspec.it̲value);itspec.it̲value.tv̲sec += 1;
itspec.it̲interval.tv̲sec = sec;
itspec.it̲interval.tv̲nsec = nsec;
if (timer̲settime( timer, TIMER̲ABSTIME, &itspec, NULL)==(-1)){
return ((timer̲t)-1);}
return(timer);}void interval̲hadler(int sig){
#ifdef DEBUG
printf("interval̲hadler(%d)\n",GlobalCounter);#endifif(Event[0]!=THREAD̲NO) return;readtime(&StartTime);
if(CurrrentTime.tv̲sec){
adjust(&CurrrentTime,&StartTime,&IntervalTime[GlobalCounter]);}
CurrrentTime.tv̲sec = StartTime.tv̲sec;
CurrrentTime.tv̲nsec = StartTime.tv̲nsec;
switch(GlobalCounter%10){
case 0:MUTEX̲LOCK(&Mutex[1]); /* lock */Event[1]++;
COND̲SIGNAL(&Condition[1]);MUTEX̲UNLOCK(&Mutex[1]); /* unlock */break;
case 1:
MUTEX̲LOCK(&Mutex[2]); /* lock */Event[2]++;
COND̲SIGNAL(&Condition[2]);MUTEX̲UNLOCK(&Mutex[2]); /* unlock */break;
case 2:
MUTEX̲LOCK(&Mutex[1]); /* lock */Event[1]++;
COND̲SIGNAL(&Condition[1]);MUTEX̲UNLOCK(&Mutex[1]); /* unlock */break;
case 3:
MUTEX̲LOCK(&Mutex[2]); /* lock */Event[2]++;
COND̲SIGNAL(&Condition[2]);MUTEX̲UNLOCK(&Mutex[2]); /* unlock */break;
case 4:
MUTEX̲LOCK(&Mutex[1]); /* lock */Event[1]++;
COND̲SIGNAL(&Condition[1]);MUTEX̲UNLOCK(&Mutex[1]); /* unlock */break;
case 5:
MUTEX̲LOCK(&Mutex[2]); /* lock */Event[2]++;
COND̲SIGNAL(&Condition[2]);MUTEX̲UNLOCK(&Mutex[2]); /* unlock */25/32

break;case 6:
MUTEX̲LOCK(&Mutex[1]); /* lock */Event[1]++;
COND̲SIGNAL(&Condition[1]);MUTEX̲UNLOCK(&Mutex[1]); /* unlock */break;
case 7:
MUTEX̲LOCK(&Mutex[2]); /* lock */Event[2]++;
COND̲SIGNAL(&Condition[2]);MUTEX̲UNLOCK(&Mutex[2]); /* unlock */break;
case 8:MUTEX̲LOCK(&Mutex[1]); /* lock */Event[1]++;
COND̲SIGNAL(&Condition[1]);MUTEX̲UNLOCK(&Mutex[1]); /* unlock */break;
case 9:MUTEX̲LOCK(&Mutex[2]); /* lock */Event[2]++;
COND̲SIGNAL(&Condition[2]);MUTEX̲UNLOCK(&Mutex[2]); /* unlock */break;}
GlobalCounter++;}void *thread̲main0(void *arg){
int class = 3;/* FIFO Schedule */int priority = 1;/* RealTime Priority min */struct sched̲param param;/* RealTime Priority min */cpuset̲t*cpumask;
cpu̲t
cpu = 1;
volatile int thread̲no;
int i;
float min,max,avr;
struct timespec w0 = {0,100 * 1000* 1000};
struct timespec wait = {0,200* 1000};
if (pthread̲getschedparam(pthread̲self(),&class,&param)){
fprintf(stderr, "pthread %d Cannot get priority %s\n",pthread̲self(),strerror(errno));}param.sched̲priority = priority;
if (pthread̲setschedparam(pthread̲self(),SCHED̲FIFO,(const struct sched̲param *)&param)){
fprintf(stderr, "pthread %d Cannot set priority %s\n",pthread̲self(),strerror(errno));}#ifdef CCURRT
cpumask = cpuset̲alloc();
cpuset̲init(cpumask);
cpuset̲set̲cpu(cpumask,cpu,1);/* 2nd CPU set */if ( mpadvise(MPA̲PRC̲SETBIAS,MPA̲TID,0,cpumask)<0){
fprintf(stderr, "thread %d Cannot bind processor %s\n",pthread̲self(),strerror(errno));}if (mpadvise (MPA̲PRC̲GETRUN,MPA̲TID,0,cpumask)!=MPA̲FAILURE){
char * cpustr;
cpustr = cpuset̲get̲string(cpumask);
printf("Thread %d is \"%s\" running\n",*(int*)arg,cpustr);
free(cpustr);}
cpuset̲free(cpumask);

26/32

#endif
MUTEX̲LOCK(&Mutex[0]);Event[0]++;MUTEX̲UNLOCK(&Mutex[0]);do{
MUTEX̲LOCK(&Mutex[0]);thread̲no = Event[0];
MUTEX̲UNLOCK(&Mutex[0]);nanosleep(&w0,0);} while (thread̲no<THREAD̲NO);if (pthread̲sigmask(SIG̲SETMASK,&eiset,&oset)==(-1)){
fprintf(stderr, "Cannot set sigprocmask - %s\n",strerror(errno));}do{sigsuspend(&eiset);if(GlobalCounter>=TESTNUMBER) loop̲flag=0;} while (loop̲flag);
COND̲SIGNAL(&Condition[1]);COND̲SIGNAL(&Condition[2]);min=99999999999.0,max=0,avr=0;
for(i=0;i<TESTNUMBER/2;i++){if(min>SwitchTime1[i]) min = SwitchTime1[i];if(max<SwitchTime1[i]) max = SwitchTime1[i];avr += SwitchTime1[i];}printf("Switch1 %10.3f: %10.3f : %10.3f\t",min,avr/(float)(TESTNUMBER/2),max);
if (fabs(max-min)<=MAXJITTER){
printf("GOOD(fabs(%f)<%d micro sec)\n",max-min,MAXJITTER);}
else{
printf("FAIL(fabs(%f)>%d micro sec)\n",max-min,MAXJITTER);}
min=99999999999.0,max=0,avr=0;
for(i=0;i<TESTNUMBER/2;i++){if(min>SwitchTime2[i]) min = SwitchTime2[i];if(max<SwitchTime2[i]) max = SwitchTime2[i];avr += SwitchTime2[i];}printf("Switch2 %10.3f: %10.3f : %10.3f\t",min,avr/(float)(TESTNUMBER/2),max);
if (fabs(max-min)<=MAXJITTER){
printf("GOOD(fabs(%f)<%d micro sec)\n",max-min,MAXJITTER);}
else{
printf("FAIL(fabs(%f)>%d micro sec)\n",max-min,MAXJITTER);}

min=99999999999.0,max=0,avr=0;
for(i=1;i<TESTNUMBER;i++){if(min>IntervalTime[i]) min = IntervalTime[i];if(max<IntervalTime[i]) max = IntervalTime[i];avr += IntervalTime[i];}printf("Interval %10.3f: %10.3f : %10.3f\t",min,avr/(float)(TESTNUMBER-1),max);
if (fabs(max-min)<=MAXJITTER){
printf("GOOD(fabs(%f)<%d micro sec)\n",max-min,MAXJITTER);
}
else
{

27/32

printf("FAIL(fabs(%f)>%d micro sec)\n",max-min,MAXJITTER);}
return(0);}void *thread̲main1(void *arg){
static int err=-1;
int class = 3;/* FIFO Schedule */int priority = 2;/* RealTime Priority min */static struct sched̲param param;/* RealTime Priority min */cpuset̲t*cpumask;
cpu̲t cpu = 1;/* boot PROCESSOR */if (pthread̲getschedparam(pthread̲self(),&class,&param)){
fprintf(stderr, "thread %d Cannot get priority %s\n",pthread̲self(),strerror(errno));}param.sched̲priority = priority;
if (pthread̲setschedparam(pthread̲self(),SCHED̲FIFO,(const struct sched̲param *)&param)){
fprintf(stderr, "thread %d Cannot set priority %s\n",pthread̲self(),strerror(errno));}if (pthread̲sigmask(SIG̲SETMASK,&diset,&oset)==(-1)){
fprintf(stderr, "Cannot set sigprocmask - %s\n",strerror(errno));err = errno;
pthread̲exit((void*)&err);}#ifdef CCURRT
cpumask = cpuset̲alloc();
cpuset̲init(cpumask);
cpuset̲set̲cpu(cpumask,cpu,1);/* CPU set */if ( mpadvise(MPA̲PRC̲SETBIAS,MPA̲TID,0,cpumask)<0){
fprintf(stderr, "thread %d Cannot bind processor %s\n",pthread̲self(),strerror(errno));}if (mpadvise (MPA̲PRC̲GETRUN,MPA̲TID,0,cpumask)!=MPA̲FAILURE){
char * cpustr;
cpustr = cpuset̲get̲string(cpumask);
printf("Thread %d is \"%s\" running\n",*(int*)arg,cpustr);
free(cpustr);}
cpuset̲free(cpumask);#endif
MUTEX̲LOCK(&Mutex[0]);Event[0]++;MUTEX̲UNLOCK(&Mutex[0]);do{
MUTEX̲LOCK(&Mutex[1]); /* lock */if(Event[1]==0) COND̲WAIT(&Condition[1],&Mutex[1]);readtime(&EndTime);
if (GlobalCounter<TESTNUMBER)
adjust(&StartTime,&EndTime,&SwitchTime1[GlobalCounter/2]);
Event[1]--;#if 0
printf("\t\tthread̲main1 %d\n",Event[1]);#endif
MUTEX̲UNLOCK(&Mutex[1]); /* unlock *//* event1̲exec(); */} while (loop̲flag);28/32

err=0;pthread̲exit((void *)err);
return(0);}void *thread̲main2(void *arg){
static int err=-1;
int class = 3;
int priority = 3;
struct sched̲param param;
cpuset̲t*cpumask;
cpu̲t cpu = 1;/* FIFO Schedule *//* RealTime Priority min *//* RealTime Priority min *//* 2nd PROCESSOR */if (pthread̲getschedparam(pthread̲self(),&class,&param)){
fprintf(stderr, "thread %d Cannot get priority %s\n",pthread̲self(),strerror(errno));}param.sched̲priority = priority;
if (pthread̲setschedparam(pthread̲self(),SCHED̲FIFO,(const struct sched̲param *)&param)){
fprintf(stderr, "thread %d Cannot set priority %s\n",pthread̲self(),strerror(errno));}if (pthread̲sigmask(SIG̲SETMASK,&diset,&oset)==(-1)){
fprintf(stderr, "Cannot set sigprocmask - %s\n",strerror(errno));err = errno;
pthread̲exit((void*)&err);}#ifdef CCURRT
cpumask = cpuset̲alloc();
cpuset̲init(cpumask);
cpuset̲set̲cpu(cpumask,cpu,1);/* CPU set */if ( mpadvise(MPA̲PRC̲SETBIAS,MPA̲TID,0,cpumask)<0){
fprintf(stderr, "thread %d Cannot bind processor %s\n",pthread̲self(),strerror(errno));}if (mpadvise (MPA̲PRC̲GETRUN,MPA̲TID,0,cpumask)!=MPA̲FAILURE){
char * cpustr;
cpustr = cpuset̲get̲string(cpumask);
printf("Thread %d is \"%s\" running\n",*(int*)arg,cpustr);
free(cpustr);}
cpuset̲free(cpumask);#endif
MUTEX̲LOCK(&Mutex[0]);Event[0]++;MUTEX̲UNLOCK(&Mutex[0]);do{
MUTEX̲LOCK(&Mutex[2]); /* lock */if (Event[2]==0) COND̲WAIT(&Condition[2],&Mutex[2]);readtime(&EndTime);
if (GlobalCounter<TESTNUMBER)
adjust(&StartTime,&EndTime,&SwitchTime2[GlobalCounter/2]);
Event[2]--;#if 0
printf("\t\t\t\tthread̲main2 %d\n",Event[2]);#endif
MUTEX̲UNLOCK(&Mutex[2]); /* unlock *//* event2̲exec(); */} while (loop̲flag);pthread̲exit((void *)err);
return(0);}void*(*thread̲main[THREAD̲NO])(void *arg) =

29/32

{
thread̲main0,
thread̲main1,
thread̲main2};

do̲main(progname,fdin,filename,opt)
char*progname;FILE*fdin;
char*filename;int opt;{
static int
no,thread̲status[THREAD̲NO],thread̲arg[THREAD̲NO];
static pthread̲ttid[THREAD̲NO];
static pthread̲attr̲tattributes[THREAD̲NO];
void *status̲p;
int signum;
static struct sigaction newact;
static sigset̲t set,oset;
static timer̲t timer̲id;
printf("*************************************************** \n");printf("**** posix timer & thread contexst switch test **** \n");printf("*************************************************** \n");if (opt){
system("/usr/bin/shield -a 1");system("/usr/bin/shield -c");}
if (sigprocmask(0,NULL,&set)==(-1)){
fprintf(stderr, "%s: Cannot get sigprocmask - %s\n",progname,strerror(errno));exit(1);}
sigaddset(&set,SIGRTMIN+2);#if 1
if (sigprocmask(SIG̲SETMASK,&set,&oset)==(-1)){
fprintf(stderr, "%s: Cannot set sigprocmask - %s\n",progname,strerror(errno));exit(1);}#endifsignum = SIGRTMIN+2;
printf("Create POSIX timer %d Hz\n",CYCLE);
timer̲id = create̲posix̲timer(signum,0,1000000000/CYCLE);
if (timer̲id<0){fprintf(stderr, "%s: Cannot set posix timer - %s\n",progname,strerror(errno));exit(1);}/* Set up the signal handler using sigaction(2) or sigset(2) */sigemptyset(&newact.sa̲mask);sigaddset(&newact.sa̲mask,signum);
newact.sa̲handler = interval̲hadler;
newact.sa̲flags = SA̲SIGINFO|SA̲RESTART;
if (sigaction(signum, &newact, 0)==(-1)){
fprintf(stderr, "%s: Cannot set sigaction - %s\n",progname,strerror(errno));exit(1);}
sigfillset(&diset);
sigfillset(&eiset);
sigdelset(&eiset,SIGRTMIN+2);

30/32

sigdelset(&eiset,SIGALRM);
sigdelset(&eiset,SIGINT);
#if 0
do
{
sigsuspend(&eiset);if(GlobalCounter>=TESTNUMBER) loop̲flag=0;} while (loop̲flag);#endifprintf("Create %d thread\n",THREAD̲NO);for (no=0;no<THREAD̲NO;no++){if (pthread̲cond̲init(&Condition[no],0)<0){
fprintf(stderr, "%s: Cannot create condition - %s\n",progname,strerror(errno));exit(1);}if (pthread̲mutex̲init(&Mutex[no],0)<0){
fprintf(stderr, "%s: Cannot create condition - %s\n",progname,strerror(errno));exit(1);}
Event[no]=0;}
for (no=0;no<THREAD̲NO;no++){if (pthread̲attr̲init(&attributes[no])){fprintf(stderr, "%s: Cannot set attributes - %s\n",progname,strerror(errno));exit(1);}if (pthread̲attr̲setscope(&attributes[no],PTHREAD̲SCOPE̲SYSTEM)){
fprintf(stderr, "%s: Cannot set attributes - %s\n",progname,strerror(errno));exit(1);}if (pthread̲attr̲setdetachstate(&attributes[no],PTHREAD̲CREATE̲JOINABLE)){
fprintf(stderr, "%s: Cannot set attributes - %s\n",progname,strerror(errno));exit(1);}if (pthread̲attr̲setinheritsched(&attributes[no],PTHREAD̲INHERIT̲SCHED)){
fprintf(stderr, "%s: Cannot set attributes - %s\n",progname,strerror(errno));exit(1);}}
MUTEX̲LOCK(&Mutex[0]); /* lock */for (no=1;no<THREAD̲NO;no++){thread̲arg[no] = no;thread̲status[no] = pthread̲create(&tid[no],&attributes[no],thread̲main[no],(void*)&thread̲arg[no]);if (thread̲status[no]){fprintf(stderr, "%s: Cannot create thread - %s\n",progname,strerror(errno));exit(1);}}
MUTEX̲UNLOCK(&Mutex[0]); /* unlock */thread̲arg[0] = 0;
thread̲main[0]((void *)&thread̲arg[0]);timer̲delete(timer̲id);for (no=1;no<THREAD̲NO;no++)
{

31/32

pthread̲join(tid[no],&status̲p);}}main(argc, argv)
int argc;
char **argv;{
extern int errno;
extern int optind;extern char *optarg;
register int i,c, opt = 0;
progname = argv[0];while((c = getopt(argc, argv, "b")) != EOF){
switch(c) {case 'b':
opt =1;break;
default:
fprintf(stderr,"usage: %s [-b]\n",progname);exit(1);}}#if 0
if (optind != argc) {for (c = optind; c < argc; c++) {if (access(argv[c], 4)) {fprintf(stderr,"%s: \"%s\" %s\n",progname,argv[c],strerror(errno));exit(1);}}}#endifif (optind == argc) {do̲main(progname,stdin, "(stdin)",opt);} else {register FILE *fd;
for (c = optind; c < argc; c++) {if ((fd = fopen(argv[c], "w")) == NULL) {fprintf(stderr,"%s: \"%s\" %s\n",progname,argv[c],strerror(errno));exit(1);}do̲main(progname,fd,argv[c],opt);
fprintf(fd,"Interval,Switch1,Switch2\n");for(i=0;i<TESTNUMBER/2;i++){fprintf(fd,"%f,%f,%f\n",IntervalTime[i+1], SwitchTime1[i], SwitchTime2[i]);}for(i=TESTNUMBER/2;i<TESTNUMBER-1;i++){fprintf(fd,"%f,,\n",IntervalTime[i+1]);}
fclose(fd);
}
}
}

32/32