オペレーティングシステム

オペレーティングシステムJ/K
(システムプログラミング)
2005年11月21日
酒居敬一([email protected])
http://www.info.kochi-tech.ac.jp/k1sakai/Lecture/OS/2005/
LinuxにおけるAPI: システムコール
• もっとも原始的なもの
– ソフトウェア割り込み0x80番(int 80h)
• 引数はレジスタに設定する
• 戻り値はレジスタに設定される
• 一般的なもの
– C言語の関数インターフェース
• APIとして使いやすい、プログラムを読みやすい
• libcでint 80hインターフェースに変換
– libcはUNIXにおける標準ライブラリの通称
LinuxにおけるAPI: ライブラリ関数
• システムコールをより使いやすくしたもの
– C言語の関数
• システムコールと見かけ上は同じ
• 標準的なものはlibcに含まれている
• 標準ライブラリという形で、互換性をもたせたもの
– プログラムの移植性があがる
buf:
segment .bss align=16 class=DATA use32
resb
256
segment .text align=16 class=CODE use32
global _start ; default entry point
align 16
_start:
プログラム例(アセンブラ)
•
•
•
•
バッファを静的に確保
標準入力から読む
標準出力へ書く
終了
mov
mov
mov
mov
int
test
js
mov
eax,3
ebx,0
ecx,buf
edx,256
0x80
eax,eax
exit
edx,eax
;
;
;
;
;
;
read
stdin
address of buffer
size of buffer
system call
check return status
mov
mov
mov
int
test
js
eax,4
ebx,1
ecx,buf
0x80
eax,eax
exit
;
;
;
;
;
write
stdout
address of buffer [sakai@star training]$ vi echo.asm
system call
[sakai@star training]$ nasm -f elf echo.asm
check return status [sakai@star training]$ ld echo.o -o echo
jmp short _start
exit:
mov
mov
int
eax,1
ebx,0
0x80
; exit
; return status
; system call
[sakai@star training]$ size echo
text
data
bss
dec
63
0
256
319
[sakai@star training]$ ./echo
askdjhaslkdjh
askdjhaslkdjh
[sakai@star training]$
hex filename
13f echo
[sakai@star training]$ objdump -d echo
echo:
ファイル形式 elf32-i386
セクション .text の逆アセンブル:
08048080 <_start>:
8048080:
b8
8048085:
bb
804808a:
b9
804808f:
ba
8048094:
cd
8048096:
85
8048098:
78
804809a:
89
804809c:
b8
80480a1:
bb
80480a6:
b9
80480ab:
cd
80480ad:
85
80480af:
78
80480b1:
eb
03
00
c0
00
80
c0
19
c2
04
01
c0
80
c0
02
cd
00
00
90
01
00
00
04
00
00
00
08
00
00 00 00
00 00 00
90 04 08
080480b3 <exit>:
80480b3:
b8 01 00 00 00
80480b8:
bb 00 00 00 00
80480bd:
cd 80
[sakai@star training]$
CPUは
機械語しかわからない…
mov
mov
mov
mov
int
test
js
mov
mov
mov
mov
int
test
js
jmp
$0x3,%eax
$0x0,%ebx
$0x80490c0,%ecx
$0x100,%edx
$0x80
%eax,%eax
80480b3 <exit>
%eax,%edx
$0x4,%eax
$0x1,%ebx
$0x80490c0,%ecx
$0x80
%eax,%eax
80480b3 <exit>
8048080 <_start>
mov
mov
int
$0x1,%eax
$0x0,%ebx
$0x80
プログラム例(C言語)
#include <unistd.h>
int main(void)
{
char
int
buf[256];
cnt;
while((cnt = read(0, buf, sizeof buf)) > 0){
write(1, buf, cnt);
}
return 0;
}
• 記述が単純。
• わかりやすい。
• よみやすい。
システムプログラムの必要性
• 例: 入出力しながら一定時間ごとに時刻表示
– read()/write()するとプロセスは待ち状態になる。
– 時刻表示をするには?
1. 非同期 read()/write() をする。→ ポーリング
2. 時刻表示にシグナルを使う。→ 割り込み
3. スレッドを複数使用する。→ マルチスレッド処理
• 1と2にはただし、そのものずばりのライブラリ関数はない。
– システムコールを使う。
• 3にはライブラリがある。
• 2か3の方法を使うことが多い。使い分ける。
void timer_handler(int n)
{
char buf[256];
int
cnt;
snprintf(buf, sizeof buf, " %d %n", time(NULL), &cnt);
write(1, buf, cnt);
シグナルによる
実装例
}
int main(void)
{
struct
struct
char
int
itimerval
sigaction
buf[256];
cnt;
timer;
sa;
sa.sa_handler = timer_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_restorer = NULL;
sigaction(SIGALRM, &sa, NULL);
• 1秒ごとに時刻表示
• エコーバック処理
これらを同時処理
timer.it_value = timer.it_interval = (struct timeval){ 1, 0};
setitimer(ITIMER_REAL, & timer, NULL);
while(1) {
if((cnt = read(0, buf, sizeof buf)) > 0){
write(1, buf, cnt);
}
}
}
#include <unistd.h>
#include <pthread.h>
マルチスレッド
による実装例
void *timer(void *arg)
{
char buf[256];
int
cnt;
while(1){
sleep(1);
snprintf(buf, sizeof buf, " %d %n", time(NULL), &cnt);
write(1, buf, cnt);
}
• 1秒ごとに時刻表示
• エコーバック処理
}
int main(void)
{
char
buf[256];
int
cnt;
pthread_t
thr;
これらを同時処理
pthread_create(&thr, NULL, timer, NULL);
while((cnt = read(0, buf, sizeof buf)) > 0){
write(1, buf, cnt);
}
return 0;
}
• 入力すべき文字がある
• 出力が可能である
• 一定時間が経過した
• マウスを動かした…
などなど…
これらをイベント(事象)としてとらえ、
イベント発生を受けて動作するシステム
イベントドリブンシステム
イベントドリブンシステム
 発生したイベントの通知方法
1. (ポーリング)
2. シグナル送信・メッセージ送信
3. スレッドのwake up
 処理を割り付ける方法
1. (条件分岐)
2. シグナルハンドラ・コールバック関数
3. マルチスレッド
イベントと処理を効率的にバインド(bind)することがミソ
イベントドリブンシステムにおける有効性
UI(User Interface)のような非同期で不定間
隔で処理が必要な場合
処理が必要な状況→イベント発生
処理はイベントとバインドする
OSの仕組みを利用すれば効率的
イベントと処理の組み合わせが自在
イベント発生とイベント処理を分離でき構造が
すっきりする。
シグナルやメッセージパッシングを使うとOO的
リアルタイムシステムの構築手法
•
•
•
•
処理オーバーヘッドの削減
応答時間が一定の範囲内にあることを保証
必要な処理時間の予測を行う
複数の処理要求が発生しても時間内に完了
i. 割り込み処理として記述する(モニタなし)
ii. 割り込み処理はスケジューラを呼ぶことにし、
ディスパッチャと分離する(モニタとして実装)
リアルタイムモニタとして実装するとき
• 非プリエンプティブマルチタスク
– 処理時間がわかっている
– 処理が完了すべき時刻(デッドライン)の要求を満たす
• メモリは領域の管理だけ
– タスクは自由に相互に参照可能
• ユーザー空間での割り込み処理
– シグナル機構に変換しない
• プロセッサへの割り込み→イベント発生
• タスクはそれにより順次起動される
– 再帰的に起動されるタスク
– そうでないタスク
• タスクが待ち状態に入る→イベント発生
• 同期通信機構→タスクからのイベント発生
• スケジューラはイベントの発生ごとに呼ばれる
• I/Oの待ちによるCPUの空き時間を利用して、
多重にプログラムを走行させる
例:モーター制御
• ステッピングモータを駆動することで、位置を制御
– 励磁信号はプロセッサが生成
• ハードリアルタイム処理
– モーター駆動速度には上限がある
– モーターの加減速度には上限がある
• フィードフォワード制御とフィードバック制御の併用
– 制御量は位置、位置のずれ(偏差)をもとに制御
– 偏差を最小にするようにフィードバック制御を使用
• 偏差が残ると誤差となるので、PID制御がよく使われる
– P: Proportional
– I: Integral
– D: Differential
– 位置制御の結果が静定する時間を短縮するため
フィードフォワード制御も併用
• 制限事項とともに、制御の計算量が必要となる
カウンター割り込みを使用
カウント値の更新により励磁間隔を変更
カウント値の更新間隔は励磁間隔以下
カウント値は位置制御部からの指示