Operating System Lecture 01/08

Menu Menu


去年の宿題

割り当てられた教科書の問題の回答はメールで
    Subject: Report Operating System Lecture 12/18

というSubject で提出してください。


前回の復習

Unix の lockf


Unix でのプロセス間通信と、Real-time 処理

Unix の API (POSIX によって規定されている) による、プロセス間通信と Real-time 処理を調べよう。


問題 (Busy Wait )

以下のプログラムのUnix での問題点を指摘せよ。

    for (;;) {
	if ( c=kbhit() ) 
	    process(c);
    }

(kbhit() は、MSDOS で良く使われる、キーボードが押されていたら、そのキーコードを返す関数。Unix のマニュアルには載っていません)

C-FAQ をWWW で探して、kbhit() が Unix では使われない理由を調べよ。

速さと言う点ではどうだろう?


実際に kbhit を作ってみる

    NONBLOCKING モードを使ったread
	fcntl で設定する


signal による同期

あるイベントで、呼び出される関数を指定する。

signal では情報を渡すことはできない。

signal によって中断された system call の取り扱いはどうする? エラーとして良いのか?


socket によるプロセス間通信

基本的には、
    あっちのプロセスでwriteしたものが、
    こちらのプロセスで読める

それだけ。問題は、
    どうやって、相手を指定するのか?

である。

共通の親を持つならば、

    socketpair, pipe

を使うことができる。

共通の親を持たない場合は、

    Unix file system の名前空間を使う
    ネットワークの IP address + Port number を使う

という手法がある。前者は、もちろん、ネットワーク経由には使えない。

socket は双方向なので、便利。(pipe は違う)

Perl による例題


redirect と pipe

標準入出力の切替えには、close と dup を使う。

socket は、Unix に取っては file の一種であり、プロセス毎に番号(file descriptor) で管理されている。

    0   標準入力  STDIN
    1   標準出力  STDOUT
    2   標準エラー出力   STDERR

close して open すれば、その番号が振られる。既に、open されているものをdup (duplicate ) しても良い。

以下は、3年生の shell の課題の一部である。

    #include <stdio.h>
    const int debug=1;
    main() {
      char command1[]="wc";
      char command2[]="cat /etc/termcap";
      int pfd[2];
      int save_in;
      int pid;
      pipe(pfd);
      if(pid = fork()){
        save_in = dup(0);
        dup2(pfd[0],0);
        close(pfd[1]);
        system(command1);
  if(debug) fprintf(stderr,"waiting %d\n",pid);
        dup2(save_in,0);
        waitpid(pid,NULL,0);
  if(debug) fprintf(stderr,"done %d\n",pid);
        return;
      }else{
  if(debug) fprintf(stderr,"forked pid %d\n",getpid());
        dup2(pfd[1],1);
        close(pfd[0]);
        system(command2);
        exit(0);
      }
    }


socket による通信の待ち合わせ

bind

    socket に名前をつける

connect
    TCP connection を張る

accept
    TCP connection を受け取る

TCP connection を通して、socket channel そのものを渡すこともできる。=> (fork の例題)


サービスモデル

server.pl client.pl を動かしてみて、サーバの動きを理解しよう。


問題

server.pl を使って、簡単なアクセスカウンター (何回アクセスしたかを数える)を作ってみよ。


サーバ・クライアントモデル

デーモン (daemon )


サービスとトランザクション

サービス内、トランザクション内の並列性

Lock をどのように実現しているかを考えよう。


NFS

RPC と UDP という connection less の通信を使って実装されている。

lock は、lockd という daemon を使う。


WWW counter

WWW server は fork するので、ファイルを lock することにより同期を取ることが多い。なので、非常に重い。

File を配達するだけの WWW server と、CGI を処理するserverを分離するのが効果的。Security 的にも望ましい。


Micro Kernel

OS のサービスのうち、
    プロセスの作成、削除
    スケジュール
    メモリ管理
    プロセス間通信

を除くと、その他のサービスは、すべて、サーバによって実現できる。このようにすることによって、OS の最小限必要な部分を抜きだしたものを
    Micro Kernel

という。

Micro Kernel は、プロセス間通信が増えるので、効率は良くないとされている。しかし、OS の構造の見通しの良さ、拡張性などに利点がある。効率は、プロセス間通信の高速化などによりカバーできる。

    Windows NT
    Mach OS (Mac OS X)

などが実用的に使われている。Windows/Mac OS 9は違います。


select による同期

Unix では、select call が万能であり、ほとんどの同期は select を使って実現できる。

しかし、ファイルと関係しないので、計算をセーブする場合には、ファイル処理を自分で行なう必要がある。


問題 (keyrecord/keyplay)

real-time application を作ってみよう。「キーボードの入力を時間を含めて忠実に再現する プログラムを作れ」

ダメな例

    NONBLOCKING モードを使ったread
	fcntl で設定する

良い例
    select を使った例を考える
	サンプルコードを見てみよう
    select を使わない例を考える
	ioctl でreadが一文字で戻って来るようにする
	man termios

時間をμsec 単位で測るには?
     int gettimeofday(struct timeval *tp, struct timezone *tzp);

を使う。

時間は、usleep で稼ぐ。

     void usleep(unsigned int microseconds);

間違っても100万回ループしたりしない。

keyrecord のサンプルコード RCS って何?

    mkdir RCS
    ci -l
    co -l
    rcsdiff

kbhit() を Unix で作ってみよう。ダメな例を実装してみて、どれくらいダメか調べよう。


Application の Perfomance Tuning

Performance だけで良いのか? Real-time プログラムにとって Performance とは何か?

このkeyrecord の時間の誤差はどこから来るの? Real-time OS とは?

出力ファイルを人間が読めない。出力ファイルを人間が読めるようにするには?


宿題(1) fork する daemon

server.pl を man perlipc などを参考に、fork するように書き換えて見よ。fork する方が適しているサービスにはどんなものがあるかを考えて実装してみよ。(C で書く場合は、課題で行なう stream.c の getstream を使うのが良い)

アクセスカウンタを fork する server で作る場合には、lock 等が必要になる。lock を使う場合はWWWの演習で出て来る。また、アクセスカウンタ用のサーバを作ることにより、実現することもできる。lock と専用サーバの利点と欠点、向いているサービスなどについて考察せよ。


宿題(2) 定期的な実行

決まった時間で実行するには、setitimer というのを使う。signal が来るので、sigpause で待とう。

    void check(void)
    {
	    /* this function does nothing. */
    }
    main() {
	....
        struct itimerval itv ;
        int simt = 0, sent = 0, rect = 0 ;
        itv.it_interval.tv_sec = 0 ;
        itv.it_interval.tv_usec = TIMEDELTA * 1000 ;
        itv.it_value.tv_sec = 0 ;
        itv.it_value.tv_usec = TIMEDELTA * 1000 ;
        signal(SIGALRM, (void (*)(int))check) ;
        setitimer(ITIMER_REAL, &itv, NULL) ;
        for (;;) {
                sigpause(sigblock(0L)) ;
		do someting....
	}
    }

または、select のtimeout を使っても良い。(こちらの方が簡単か?)

どちらかの方法を使い、keyrecord に、途中で時間を表示するコードを足してみよう。


課題

課題 7. WWW プログラミング </a>をさ来週までに行うこと。レポートはメールで

    Subject: Report Operating System Lecture 01/12

というように、課題を出した日付をサブジェクトに入れたメールで提出して下さい。


Shinji KONO / Tue Jan 8 06:18:00 2002