オペレーティングシステム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 – 位置制御の結果が静定する時間を短縮するため フィードフォワード制御も併用 • 制限事項とともに、制御の計算量が必要となる カウンター割り込みを使用 カウント値の更新により励磁間隔を変更 カウント値の更新間隔は励磁間隔以下 カウント値は位置制御部からの指示
© Copyright 2024 ExpyDoc