例題(measurement)を見てみると
RT-Linux ver2.x になってかなり変更がありました。
今まで独自にスレッドを管理していましたが、これが
POSIX thread を使うようになりました。
例題をもとに、簡単な HOWTO を(自分の為に)書いてみました。
ヘッダーファイル
------ common.h -------
#define LPT_PORT 0x378
#define LPT_IRQ 7
#define RTC_IRQ 8
#include <rtl_time.h>
struct sample {
hrtime_t min;
hrtime_t max;
};
まあ、ヘッダーファイルはこんなもんでしょう。
ここで目を引くのは hrtime_t でしょうか
これは、RT-Linux で使う時間用の変数のタイプです。
typedef long long hrtime_t;
と定義されています。(64ビット符号付の整数)
メインモジュール
/*
* RTL scheduling accuracy measuring example, user program
*
* (C) Michael Barabanov, 1997
* (C) FSMLabs 1999. baraban@fsmlabs.com
* Released under the GNU GENERAL PUBLIC LICENSE Version 2, June 1991
* Any use of this code must include this notice.
*/
#include <stdio.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <rtl_fifo.h>
#include <asm/rt_time.h>
#include "common.h"
int main()
{
int fd0;
int n;
struct sample samp;
if ((fd0 = open("/dev/rtf0", O_RDONLY)) < 0) {
fprintf(stderr, "Error opening /dev/rtf0\n");
exit(1);
}
while (1) {
n = read(fd0, &samp, sizeof(samp));
printf("min: %8d, max: %8d\n", (int) samp.min, (int) samp.max);
fflush(stdout);
}
return 0;
}
メインの方では、FIFOバッファからデータを読んで表示するだけですね
RT-Linux に固有なものは /dev/rtf0 くらいです。
この rtf0 は RT-Linux の FIFOバッファのデバイスです。
この FIFO を通してデータを交換します。
さて、・・・問題なのはリアルタイムで動く以下のモジュールファイルです。
私自身もあまり詳しく無いので、さらりと読んでください(笑)
/*
* RTL scheduling accuracy measuring example
*
* (C) Michael Barabanov, 1997
* (C) FSMLabs 1999. baraban@fsmlabs.com
* Released under the GNU GENERAL PUBLIC LICENSE Version 2, June 1991
* Any use of this code must include this notice.
*/
#include <rtl.h>
#include <rtl_fifo.h>
#include <time.h>
#include <rtl_sched.h>
#include <rtl_sync.h>
#include <pthread.h>
#include <unistd.h>
#include <rtl_debug.h>
#include <errno.h>
#include "common.h"
int ntests=500;
int period=1000000;
int mode=0;
int fifo_size=4000;
int advance=0;
MODULE_PARM(period,"i");
MODULE_PARM(ntests,"i");
MODULE_PARM(mode,"i");
MODULE_PARM(advance,"i");
pthread_t thread;
int fd_fifo;
void *thread_code(void *param) {
hrtime_t expected;
hrtime_t diff;
hrtime_t now;
hrtime_t min_diff;
hrtime_t max_diff;
struct sample samp;
int i;
int cnt = 0;
DECLARE_CPUID(cpu_id);
rtl_printf ("Measurement task starts on CPU %d\n", cpu_id);
if (mode) {
int ret = rtl_setclockmode (rtl_getschedclock(), RTL_CLOCK_MODE_
PERIODIC, period);
if (ret != 0) {
conpr("Setting periodic mode failed\n");
mode = 0;
}
}
if (mode) {
struct timespec resolution;
/* need to round up the period; should this be done
* in pthread_make_periodic? */
clock_getres (rtl_getschedclock(), &resolution);
period = timespec_to_ns (&resolution);
} else {
rtl_setclockmode (rtl_getschedclock(), RTL_CLOCK_MODE_ONESHOT, 0
);
}
expected = clock_gethrtime(rtl_getschedclock()) + 2 * period;
if (advance) {
pthread_make_periodic_np (pthread_self(), expected - advance, pe
riod);
} else {
pthread_make_periodic_np (pthread_self(), expected, period);
}
fd_fifo = open("/dev/rtf0", O_NONBLOCK);
if (fd_fifo < 0) {
rtl_printf("/dev/rtf0 open returned %d\n", fd_fifo);
return (void *) -1;
}
if (advance) {
rtl_stop_interrupts(); /* Be careful with this! The task won't b
e preempted by anything else. This is probably only appropriate for small high-p
riority tasks. */
}
do {
min_diff = 2000000000;
max_diff = -2000000000;
for (i = 0; i < ntests; i++) {
++cnt;
pthread_wait_np();
now = clock_gethrtime(CLOCK_UST);
if (advance && !mode) {
if (now < expected) {
rtl_delay (expected - now);
}
now = clock_gethrtime(CLOCK_UST);
}
diff = now - expected;
if (diff < min_diff) {
min_diff = diff;
}
if (diff > max_diff) {
max_diff = diff;
}
expected += period;
}
samp.min = min_diff;
samp.max = max_diff;
write (fd_fifo, &samp, sizeof(samp));
} while (1);
return 0;
}
int init_module(void)
{
pthread_attr_t attr;
struct sched_param sched_param;
int thread_status;
int fifo_status;
rtf_destroy(0);
fifo_status = rtf_create(0, fifo_size);
if (fifo_status) {
rtl_printf("RTL measurement test fail. fifo_status=%d\n",fifo_st
atus);
return -1;
}
rtl_printf("RTL measurement module on CPU %d\n",rtl_getcpuid());
pthread_attr_init (&attr);
pthread_attr_setcpu_np(&attr, 0 /*!rtl_getcpuid()*/);
sched_param.sched_priority = 1;
pthread_attr_setschedparam (&attr, &sched_param);
rtl_printf("About to thread create\n");
thread_status = pthread_create (&thread, &attr, thread_code, (void *)1)
;
if (thread_status != 0) {
rtl_printf("failed to create RT-thread; errno=\n", errno);
return -1;
} else {
/* rtl_printf("created RT-thread\n"); */
}
return 0;
}
void cleanup_module(void)
{
rtl_printf ("Removing module on CPU %d\n", rtl_getcpuid());
pthread_delete_np (thread);
close(fd_fifo);
/* should be: pthread_cancel(thread); pthread_join(thread); */
/* or: rtl_pthread_kill_other_threads(); */
rtf_destroy(0);
}
このモジュールは以下の3個の関数から出来ています。
- void *thread_code(void *param)
- int init_module(void)
- void cleanup_module(void)
それぞれ、実際に走るスレッド部分、モジュールの初期化、モジュールの終了
となっています。
時間を追って、(簡単に)中を見ていくと
モジュールの初期化
モジュールの初期化は2段階あります、まずデータ入出力のFIFOの確保
次にスレッドの作成です。
- FIFO の確保
- rtf_destroy(0);
- 使用しようとする FIFOバッファを開放して
- fifo_status = rtf_create(0, fifo_size);
- 新しく FIFO バッファを作る
- if (fifo_status) {
- FIFOの確保に失敗したらエラーメッセージを出して -1 を返す
- スレッドを作る
- pthread_attr_init (&attr);
- man で出てこない(??)、構造体 pthread_attr_t を初期化する関数です。
- pthread_attr_setcpu_np(&attr, 0 /*!rtl_getcpuid()*/);
- スレッドを実行するCPUを指定します、指定した結果は attr に入っているようです。CPUを指定するときは /proc/cpuinfo の processorの数字を指定します。
- sched_param.sched_priority = 1;
- スレッドスケジュールの優先度を決めます。
- pthread_attr_setschedparam (&attr, &sched_param);
- そして、スレッドアトリビュートに値を設定します。
- thread_status = pthread_create (&thread, &attr, thread_code, (void *)1)
- スレッドを作ります。
pthread_create() はmanで出てこないので予想ですが
pthread_create(
スレッドIDを書き込むポインター
スレッドのアトリビュートへのポインター
スレッドで走らせる関数へのポインター
その関数への引き数へのポインター)
のようです。
ちなみに、インクルードファイル pthread.h では
Create a thread with given attributes ATTR
(or default attributes if ATTR is NULL),
and call function START_ROUTINE with given arguments ARG.
extern int pthread_create __P ((pthread_t *__thread,
__const pthread_attr_t *__attr,
void *(*__start_routine) (void *),
void *__arg));
と、なっています
- if (thread_status != 0) {
- スレッドの作成でエラーが発生すれば、-1 を返します。
正常に終了すれば、0を返して初期化を終わります。