40
オペレーティングシステム システムソフトウェア論(理) システムソフトウェア(工) 16. UNIX (3) 平成25年度 春学期 担当: 荻原剛志 注意:この資料には、著作権法上の特例に基づき、教育目的でのみ利用を許可された情報が含まれてい ます。講義と無関係な用途に利用したり、受講生以外の者に利用させることを禁止致します。

オペレーティングシステム › ~ogihara › lab › 16Unix3.pdfオペレーティングシステム システムソフトウェア論(理) システムソフトウェア(工)

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

  • オペレーティングシステムシステムソフトウェア論(理)システムソフトウェア(工)

    16. UNIX (3)

    平成25年度 春学期担当: 荻原剛志

    注意:この資料には、著作権法上の特例に基づき、教育目的でのみ利用を許可された情報が含まれています。講義と無関係な用途に利用したり、受講生以外の者に利用させることを禁止致します。

  • 京都産業大学「オペレーティングシステム」(荻原)

    ソケット [1]● 一般的な通信のインタフェースとして使われる

    ✦ BSD系UNIXで開発✦ Windows等でも利用できる(Winsock)✦ TCP/IPおよびアプリケーション層プロトコルの実装としてデファクト・スタンダード

    ● 主なドメイン✦ ホスト内ドメイン:1つのコンピュータ内での通信- PF_LOCAL(マクロ。旧名 PF_UNIX)

    ✦ INETドメイン:ネット上の通信- PF_INET(IPv4)、PF_INET6(IPv6)- その他、特定のネットワークやデバイス用の設定が用意されることもある

  • 京都産業大学「オペレーティングシステム」(荻原)

    ソケット [2]● 通信のタイプ

    ✦ ストリーム:SOCK_STREAM- コネクションを確立して通信。双方向。- バイトストリームのデータが順序通り確実に届く。

    ✦ データグラム:SOCK_DGRAM- コネクションレスで信頼性がない。- 比較的短いデータを送信する。

    ✦ 順序付きパケット列:SOCK_SEQPACKET- コネクションベースで、信頼性のある双方向通信。- 最大長の決まったデータグラムを送信する。

    ✦ その他、生(raw)プロトコルなどがある。

  • 京都産業大学「オペレーティングシステム」(荻原)

    ソケット: TCPのサーバの概要1. INETドメインでストリーム通信を行うソケットを生成する(socket(2))

    2. ソケットをポートにバインドする(bind(2))3. コネクションの要求を待つ設定(listen(2))4. コネクションを受け付ける(accept(2))5. リモートのクライアントと通信する(send(2), recv(2), write(2), read(2))

    6. 通信を終えるには通信断(shutdown(2))7. ソケットをクローズ(close(2))8. 動作を継続するには[4]へ戻る

  • 京都産業大学「オペレーティングシステム」(荻原)

    ソケット: TCPのクライアントの概要1. INETドメインでストリーム通信を行うソケットを生成する(socket(2))

    2. サーバに接続する(connect(2))• サーバのIPとポートが分かっている必要がある• クライアント側のポート番号はOSが適宜割り当ててくれる

    3. サーバと通信する(send(2), recv(2), write(2), read(2))

    4. 通信を終えるには通信断(shutdown(2))5. ソケットをクローズ(close(2))

  • 京都産業大学「オペレーティングシステム」(荻原)

    プログラム例:サーバ [1/3]#include #include #include

    #define PORT 8801#define BUFMAX 120

    static void init_sockaddr(struct sockaddr_in *addr, short port){ memset(addr, 0, sizeof(struct sockaddr_in)); addr->sin_family = AF_INET; addr->sin_port = htons(port); addr->sin_addr.s_addr = htonl(INADDR_ANY);}

    static void do_something(int conn) { int len, i; char buf[BUFMAX]; while ((len = read(conn, buf, BUFMAX)) > 0) { for (i = 0; i < len; i++) buf[i] = toupper(buf[i]); (void)write(conn, buf, len); }}

    #include #include #include #include #include #include

    ※ スペースの都合

    クライアントから文字列を読み込み、小文字を大文字にして送り返す

    構造体の初期設定

    hton...は、マシンの表現をネット共通の表現に変換

    ※ 次ページに続く

  • 京都産業大学「オペレーティングシステム」(荻原)

    プログラム例:サーバ [2/3]

    int main(void){ const char *errmsg = NULL; int sock; struct sockaddr_in sockAddr;

    sock = socket(PF_INET, SOCK_STREAM, 0); if (sock == 0) { errmsg = "can't create a socket"; goto EXIT; } init_sockaddr(&sockAddr, PORT); const struct sockaddr *sp = (struct sockaddr *)&sockAddr; if(bind(sock, sp, sizeof(sockAddr)) != 0) { errmsg = "can't bind to port"; goto EXIT; } if (listen(sock, 6) != 0) { errmsg = "can't listen requests"; goto EXIT; }

    構造体の初期設定

    ポートに割り当てる

    接続要求を待つための設定

    ソケットを作る

    ※ 次ページに続く

  • 京都産業大学「オペレーティングシステム」(荻原)

    プログラム例:サーバ [3/3]

    for ( ; ; ) { int conn = accept(sock, NULL, NULL); if (conn < 0) { errmsg = "can't accept connection"; goto EXIT; } fprintf(stderr, "Connected\n"); do_something(conn); shutdown(conn, SHUT_RDWR); close(conn); fprintf(stderr, "Disconnected\n"); }

    EXIT: if (errmsg) { fprintf(stderr, "ERROR: %s\n", errmsg); return 1; } return 0;}

    接続要求を受け付ける

    何らかの処理

    接続を切る

  • 京都産業大学「オペレーティングシステム」(荻原)

    プログラム例:クライアント [1/3]

    #include #include #include #include #include #include #include #include

    #define PORT 8801#define BUFMAX 120

    static int init_sockaddr(struct sockaddr_in *addr, short port, const char *ipaddr){ memset(addr, 0, sizeof(struct sockaddr_in)); addr->sin_family = AF_INET; addr->sin_port = htons(port); addr->sin_addr.s_addr = htonl(INADDR_ANY); int r = inet_pton(AF_INET, ipaddr, &addr->sin_addr); return (r > 0 ? 0 : -1);}

    構造体の初期設定

    ※ 次ページに続く

  • 京都産業大学「オペレーティングシステム」(荻原)

    プログラム例:クライアント [2/3]

    int main(int argc, const char *argv[]){ const char *errmsg = NULL; const char *ip = "127.0.0.1"; // localhost int sock; struct sockaddr_in sockAddr;

    if (argc > 1) ip = argv[1]; sock = socket(PF_INET, SOCK_STREAM, 0); if (sock == 0 || init_sockaddr(&sockAddr, PORT, ip) != 0) { errmsg = "can't create a socket"; goto EXIT; } const struct sockaddr *sp = (struct sockaddr *)&sockAddr; if (connect(sock, sp, sizeof(sockAddr)) != 0) { errmsg = "can't connect to the server"; goto EXIT; }

    コマンドライン引数で IPを指定できる

    ソケットを作る

    ソケットを接続する

    ※ 次ページに続く

  • 京都産業大学「オペレーティングシステム」(荻原)

    プログラム例:クライアント [3/3]

    int len; char buf[BUFMAX]; while (fgets(buf, BUFMAX, stdin) != NULL) { len = strlen(buf); (void)write(sock, buf, len); len = read(sock, buf, BUFMAX); if (len

  • 京都産業大学「オペレーティングシステム」(荻原)

    FIFO(名前付きパイプ)● ファイルシステムに、名前を持つ特殊なファイルとして生成、消去できる

    ● 書き込む側のプロセスと読み出す側のプロセスの間で、プロセス間通信を実現する✦ パイプと同様に、書き込み側、読み出し側はデータの有無によってブロックされる

    ● シェルからは mkfifo(1) コマンドで作成できるmkfifo [-m mod] file...

    ● システムコールとして mkfifo(2) があるint mkfifo(const char *p, mode_t mode)

  • 京都産業大学「オペレーティングシステム」(荻原)

    名前付きパイプの利用例$ mkfifo myfifo$ ls -l myfifoprw-r--r-- 1 me wheel 0 7 11 22:54 myfifo$ date > myfifo

    $ cat -n < myfifo 1! 2013年 7月11日 木曜日 22時55分23秒 JST

    上のプロセスはこのままブロックされる。別のウィンドウで下のようにすると、dateの出力が現れる。

    ● パイプと異なり、読み書きするプロセスは親子の必要がない。● 読み書きどちらが先に実行されてもよい。● それぞれ別々のディレクトリで実行されるプロセスでよい。

  • 京都産業大学「オペレーティングシステム」(荻原)

    共有メモリ(System V系)● 共有メモリとして使える領域を作成し、IDまたはキーで識別

    ● いったん作成した共有メモリは明示的に消去しない限り存在する

    ● 複数のプロセスで共有できるため、セマフォなどを用いた相互排除(排他制御)が必要になる

  • 京都産業大学「オペレーティングシステム」(荻原)

    共有メモリの取得: shmget(2)

    intshmget(key_t key, size_t sz, int shmflg)

    ✦ keyは領域を識別するための値、szは領域の大きさ。✦ shmflgの下9ビットはファイルのパーミッションと同じ。ただし、実行(x)ビットは参照されない。

    ✦ shmflgにビットORで以下の動作を指定する(主なもの)。! IPC_CREAT keyで指定される領領域がなければ新たに作成する! IPC_EXCL 領領域が既に存在していれば失敗する

    ✦ 返り値は領域を識別するためのID値。失敗した場合は -1。✦ keyを、存在するファイルのパスから作成する ftok(3) という関数もある。

  • 京都産業大学「オペレーティングシステム」(荻原)

    共有メモリの割当て: shmat(2)

    void *shmat(int shmid, const void *shmaddr, int shmflg)

    ✦ shmid は shmget(2) が返した領域を識別するID値。✦ shmaddr は現在のアドレス空間で、領域に割り当てたいアドレス。0を指定するとOSが自動的に割り当てる。

    ✦ shmflgはオプション。以下の値をビットORで指定。!SHM_RDONLY 読み込み専⽤用!SHM_RND 割り当てるアドレスをページ境界に丸める

    ✦ 返り値は、割り当てられたアドレス。失敗した場合は -1。

    int shmdt(const void *shmaddr)✦ 領域の割当てを解除(デタッチ)する。

  • 京都産業大学「オペレーティングシステム」(荻原)

    共有メモリの管理: shmctl(2)

    int shmctl(int shmid, int cmd, struct shmid_ds *buf)

    ✦ shmid は shmget(2) が返した領域を識別するID値。✦ buf は共有メモリに関する情報をまとめた構造体を指す。✦ cmd で動作を指定。

    ! IPC_STAT 指定した領領域に関する情報を取得して  buf  に書き込む! IPC_SET 領領域に属性を設定する(スーパーユーザのみ)! IPC_RMID 領領域を削除する

    ●オンラインコマンド ipcs(1) で共有メモリに関する情報を表示できる。

    ●オンラインコマンド ipcrm(1) で共有メモリを削除できる。

  • 京都産業大学「オペレーティングシステム」(荻原)

    共有メモリの例題: 作成#include #include #include

    #define MEM_KEY (key_t)2011#define MEM_SIZE 1024

    int main(void){ int mem_id = shmget(MEM_KEY, MEM_SIZE, 0666 | IPC_CREAT); if (mem_id < 0) { fprintf(stderr, "Error: can't get\n"); return 1; } char *p = (char *)shmat(mem_id, (void *)0, SHM_RND); time_t t = time(NULL); sprintf(p, "Hello. %s", ctime(&t)); return 0;}

    共有メモリの領域を取得(存在しなければ作成)し、現在時刻を含む文字列を書き込む。

    共有メモリの領域を取得

    アドレス空間に割り当てる

    文字列を書き込む

    shmemget.c

  • 京都産業大学「オペレーティングシステム」(荻原)

    共有メモリの例題: 読み込み

    #include #include

    #define MEM_KEY (key_t)2011#define MEM_SIZE 1024

    int main(void){ int mem_id = shmget(MEM_KEY, MEM_SIZE, 0666); if (mem_id < 0) { fprintf(stderr, "Error: can't get\n"); return 1; } char *p = (char *)shmat(mem_id, (void *)0, SHM_RND); printf("%s", p); return 0;}

    共有メモリの領域を取得し、そこに書かれている文字列を出力する。

    共有メモリの領域を取得

    アドレス空間に割り当てる

    書かれている文字列を出力

    shmemread.c

  • 京都産業大学「オペレーティングシステム」(荻原)

    共有メモリの例題: 実行例[1]$ ./shmemget$ ./shmemreadHello. Fri Jul 12 01:08:27 2013

    $ ipcsIPC status from as of ...T ID KEY MODE OWNER GROUPMessage Queues:

    T ID KEY MODE OWNER GROUPShared Memory:m 65536 0x4d0527d1 --rw-rw---- root wheelm 524289 0x000007db --rw-rw-rw- ogihara ogihara

    T ID KEY MODE OWNER GROUPSemaphores:s 65536 0x530527d1 --ra-ra---- root wheels 65537 0x730527d1 --ra-ra---- root wheel

    共有メモリの領域を取得

    共有メモリのデータを読む

    共有メモリの情報を一覧

  • 京都産業大学「オペレーティングシステム」(荻原)

    共有メモリの例題: 実行例[2]$ ./shmemreadHello. Fri Jul 12 01:08:27 2013

    $ ipcrm -m 524289

    $ ipcsIPC status from as of ...

    T ID KEY MODE OWNER GROUPShared Memory:m 65536 0x4d0527d1 --rw-rw---- root wheel

    $ ./shmemreadError: can't get

    さきほどの共有メモリの情報は表示されなくなる

    共有メモリの領域が取得できない

    共有メモリの領域は存在している

    IDを指定して共有メモリを削除

    ※ shmctl(2)でプログラムから削除することもできる。

    (中略)

    (中略)

  • 京都産業大学「オペレーティングシステム」(荻原)

    共有メモリ(POSIX)● 名前の付いた共有メモリオブジェクトを作成● いったん作成した共有メモリは明示的に消去しない限り存在する

    ● 複数のプロセスで共有できるため、セマフォなどを用いた相互排除(排他制御)が必要になる

    ● 一般のファイルをメモリにマッピングする仕組み(メモリマップトファイル)と同じシステムコールを使う

  • 京都産業大学「オペレーティングシステム」(荻原)

    共有メモリの割当て: shm_open(2)

    int shm_open(const char *name, int oflag, ...)

    ✦ name は共有メモリの識別名で、 “/xyz44” のように「/」から始まり、「/」以外の文字が続く(最長255)もの。

    ✦ oflag はオプション。以下の値をビットORで指定。!O_RDONLY 読み込み専⽤用!O_RDWR 読み書き可能なオブジェクトをオープン!O_CREAT メモリオブジェクトが存在しなければ新規に作成する

    ✦ 共有メモリオブジェクトはファイルと同様にパーミッションを持つ。第3引数は open(2)のものと同様な意味。

    ✦ 返り値は、メモリオブジェクトを参照するファイルディスクリプタ。失敗した場合は -1。

  • 京都産業大学「オペレーティングシステム」(荻原)

    共有メモリの削除: shm_unlink(2)

    int shm_unlink(const char *name)✦ name は共有メモリの識別名。✦ 複数のプロセスから shm_open(2) で参照されている場合、識別名は削除されるが、共有メモリオブジェクトはただちには削除されない。参照するプロセスが存在しなくなったとき、OSがメモリオブジェクトを抹消する。

    ✦ 共有メモリオブジェクトは、識別名が削除された後でも存在していることがある。このとき、同じ識別名を使ってもその共有メモリにはアクセスできない。つまり、O_CREAT を設定しないで shm_open(2) を使うと失敗し、O_CREAT を設定して呼び出すと、別な新しい共用メモリオブジェクトが作成される。

  • 京都産業大学「オペレーティングシステム」(荻原)

    ファイルを指定した大きさにする: ftruncate(2)

    int ftruncate(int fildes, off_t length)✦ fildes はファイルに関係するディスクリプタ。✦ ファイルの大きさは length で指定したバイト数に拡張、あるいは切り詰められる。拡張する場合、0が詰められる。

    ✦ 共有メモリオブジェクトに対しても利用可能。このシステムコールを使って、shm_open(2) で得た共有メモリの大きさを指定する。

    inttruncate(const char *path, off_t length)

    ✦ 通常のファイルに対する指定。path はファイルパス。

  • 京都産業大学「オペレーティングシステム」(荻原)

    共有メモリのマップ: mmap(2) [1]void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)

    ✦ 共有メモリ(fdで指定)をアドレス空間にマップする。✦ 通常のファイルをオープンし、ディスクリプタを指定することができる。その場合、ファイルの内容がメモリ上にマップされる(メモリマップトファイル)。

    ✦ addrはアドレスの指定。NULLの場合、OSが自動的に割り当てる。lenはメモリサイズ。offsetは通常0でよい。

    ✦ 返り値は実際に割り当てられた先頭アドレス。失敗した場合は MAP_FAILED という値が返る。

  • 京都産業大学「オペレーティングシステム」(荻原)

    共有メモリのマップ: mmap(2) [2]✦ protは以下のオプションをビットORで指定。

    !PROT_NONE アクセスできない!PROT_READ 読み出し可能!PROT_WRITE 書き込み可能!PROT_EXEC 実⾏行行可能

    ✦ flags は以下のオプションを指定。!MAP_SHARED メモリの更更新がプロセス間で共有される!MAP_PRIVATE メモリの更更新は共有されない

    ✦ addrはアドレスの指定。NULLの場合、OSが自動的に割り当てる。lenはメモリサイズ。offsetは通常0でよい。

    int munmap(void *addr, size_t len)✦ 開始アドレス addr、大きさ len のメモリ割当てを取り除く(アンマップ)。

  • 京都産業大学「オペレーティングシステム」(荻原)

    マップされた領域とファイルを同期する: msync(2)

    intmsync(void *addr, size_t len, int flags)

    ✦ mmap(2)を使ってマップされたメモリ領域に対する更新をファイルに反映させる。この呼び出しがなければ、munmap(2) までに、確実に反映される保証はない。

    ✦ 開始アドレス addr、大きさ len のメモリ領域を、対応するファイルに書き出し、ファイルの更新日時を変更する。

    ✦ flags は以下から指定。!MS_ASYNC 直ちにリターンする!MS_SYNC 同期書き込みをする(終わるまで戻らない)!MS_INVALIDATE キャッシュを無効にする

  • 京都産業大学「オペレーティングシステム」(荻原)

    共有メモリの例題 [1/2]#include #define MEM_PATH "/Venus"#define MEM_SIZE 4096

    int main(void){ int pid = getpid(); int cflag = 0; int mem_fd = shm_open(MEM_PATH, O_RDWR); if (mem_fd < 0) { mem_fd = shm_open(MEM_PATH, O_RDWR | O_CREAT, 0666); if (mem_fd < 0) { fprintf(stderr, "Error: can't open\n"); return 1; } (void)ftruncate(mem_fd, MEM_SIZE); printf("Created\n"); cflag = 1; }

    共有メモリオブジェクトをオープン。失敗したら自ら作成する。

    大きさを指定する

    shmopen.c#include #include #include #include

    ※ スペースの都合

    ※ 次ページに続く

  • 京都産業大学「オペレーティングシステム」(荻原)

    共有メモリの例題 [2/2]

    char *addr, *p; addr = p = mmap(NULL, MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0); printf("[%d] %s: %p\n", pid, (cflag ? "Created" : "Shared"), addr); do { while (*p) putchar(*p++); time_t t = time(NULL); sprintf(p, "[%d] %s", pid, ctime(&t)); msync(addr, MEM_SIZE, MS_SYNC); }while (getchar() != 'q'); munmap(addr, MEM_SIZE); if (cflag && shm_unlink(MEM_PATH) != 0) fprintf(stderr, "Error: can't unlink\n"); return 0;}

    共有メモリオブジェクトをメモリに割り当てる

    メモリオブジェクトを生成したプロセスが抹消する

    プロセスIDと時刻を末尾に書き込む

    “q”が入力されるまで繰り返す

    何か文字があったら書き出す

    ※ 前ページからの続き

  • 京都産業大学「オペレーティングシステム」(荻原)

    メモリマップトファイルの例題 [1/2]

    #include #include #include

    int main(int argc, char *argv[]){ int fin = open(argv[1], O_RDONLY); int fout = open(argv[2], O_RDWR|O_CREAT, 0666); if (fin < 0 || fout < 0) { fprintf(stderr, "Error: can't open\n"); return 1; }

    struct stat buf; fstat(fin, &buf); size_t sz = buf.st_size; ftruncate(fout, sz);

    第1、第2引数が入力、出力ファイル名

    入力ファイルの大きさを得る

    memmap.c#include #include #include

    ※ スペースの都合

    ※ 次ページに続く出力ファイルのサイズを設定する

    メモリマップトファイルを使って高速なファイル操作を実装してみよう。

  • 京都産業大学「オペレーティングシステム」(荻原)

    メモリマップトファイルの例題 [1/2]

    void *pin, *pout; pin = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, fin, 0); pout = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fout, 0); if (pin == MAP_FAILED || pout == MAP_FAILED) { fprintf(stderr, "Error: can't map\n"); return 2; } memcpy(pout, pin, sz); munmap(pin, sz); munmap(pout, sz); close(fin); close(fout); return 0;}

    入力ファイル、出力ファイルともにメモリにマップする。

    メモリ間でコピーを行う関数

    ※ 前ページからの続き

    アンマップでメモリの変更がファイルに反映される

  • 京都産業大学「オペレーティングシステム」(荻原)

    実行例● 以前の lcopy、fcopy、および cpコマンドと比較してみる

    $ time ./lcopy large.data > xreal 0m1.540suser 0m0.126ssys 0m1.391s

    $ time ./fcopy large.data > xreal 0m0.365suser 0m0.289ssys 0m0.054s

    $ time ./memmap large.data xreal 0m0.220suser 0m0.014ssys 0m0.046s

    $ time cp large.data xreal 0m0.171suser 0m0.001ssys 0m0.031s

    コンパイル時に最適化オプション -O2 を指定。ファイル x は実行の前にいったん削除。

    memmapはなぜ高速なのか?

    データファイルは28MB。

    memcpy(3) ではなく、ループを回して1バイトずつコピーすると 0.028 くらいになる。

    CPUサイクルを使う処理はほとんどないらしい。

  • 京都産業大学「オペレーティングシステム」(荻原)

    メモリマップトファイル● 仮想メモリの領域を、指定したファイルの内容と一致させる✦ 読み込みだけの目的にも使える

    ● ファイルをメモリにマップする仕組みは仮想メモリと同じOSの機能を使っている✦ 一度にすべての内容がメモリに読み込まれるのではなく、必要に応じて動的に読み込んでいる

    ✦ CPUを経由せずにデータを移動する機構(DMA)などを効率的に利用している

    ● 複数プロセスで同時に行うことで、メモリおよびファイルの内容が共有される✦ 通信目的に利用するには、同期を工夫する必要がある

  • 京都産業大学「オペレーティングシステム」(荻原)

    シグナル● 同じユーザの他のプロセスに何らかの事象の発生を伝える✦ メッセージを伝えることはできない

    ● シグナルを受け取ったプロセスの動作:✦ 無視✦ プロセスを終了✦ 指定した関数(シグナルハンドラ)を起動

    ● シグナルは20種類程度あり、用途が決まっている。ユーザの特定の目的に使えるものもある。

  • 京都産業大学「オペレーティングシステム」(荻原)

    主なシグナル番号

    名前 既定の動作 説 明1 SIGHUP プロセスを終了 端末回線のハングアップ2 SIGINT プロセスを終了 プログラムへの割込み(Cntl-C)4 SIGILL コアイメージを作る 不正な命令5 SIGTRAP コアイメージを作る trace命令の実行7 SIGEMT コアイメージを作る emulate命令の実行8 SIGFPE コアイメージを作る 浮動小数点演算のエラー9 SIGKILL プロセスを終了 プロセスをシグナルで停止(捕捉/無視できない)

    10 SIGBUS コアイメージを作る バスエラー11 SIGSEGV コアイメージを作る セグメンテーションエラー12 SIGSYS コアイメージを作る 不正なシステムコール13 SIGPIPE プロセスを終了 読み手のないパイプへの書き込み14 SIGALRM プロセスを終了 実時間タイマーが指定時間経過15 SIGTERM プロセスを終了 プロセスをシグナルで停止17 SIGSTOP プロセスを停止 停止(捕捉/無視できない)18 SIGTSTP プロセスを停止 キーボードからの停止操作20 SIGCHLD シグナルを破棄 子プロセスの状態変化21 SIGTTIN プロセスを停止 バックグラウンドのプロセスが端末から読み込みを試みた22 SIGTTOU プロセスを停止 バックグラウンドのプロセスが端末に書き込みを試みた28 SIGWINCH シグナルを破棄 ウィンドウの大きさが変化した30 SIGUSR1 プロセスを終了 ユーザ定義シグナル 131 SIGUSR2 プロセスを終了 ユーザ定義シグナル 2

  • 京都産業大学「オペレーティングシステム」(荻原)

    シグナルの送信: kill(2)

    int kill(pid_t pid, int sig)✦ pidはシグナルを送信する相手のプロセスID。✦ sigはシグナル(前ページの表を参照)。✦ 同じユーザidを持つプロセスに送信できる。スーパーユーザの特権があれば、任意のプロセスに送信できる。

    ●コマンドラインから kill(1) コマンドを使ってシグナルを送ることもできる。

    $ kill -TERM 5609$ kill -9 5612

    SIGTERM(=15)を送るSIGKILL(=9)を送る

  • 京都産業大学「オペレーティングシステム」(荻原)

    シグナルハンドラの設定: signal(3)

    sig_t signal(int sig, sig_t *func)

    ✦ sigはハンドラを指定するシグナル。ただし、SIGKILLとSIGSTOPには指定できない。

    ✦ funcはシグナルハンドラへの関数ポインタ。次の形を持つ関数。

    ✦ シグナルハンドラの引数には、受け取ったシグナルの種類が渡される。

    ✦ シグナルハンドラとして SIG_DFL を指定すると既定の動作を設定できる。SIG_IGN ならば無視の指定。

    void XXXXX(int)

  • 京都産業大学「オペレーティングシステム」(荻原)

    シグナルハンドラの例#include #include #include

    static void handler(int sig) { printf("Signal %d is received.\n", sig);}

    int main(void){ char buf[20];

    printf("PID = %d\n", getpid()); while (fgets(buf, 20, stdin) != NULL) { if (buf[0] == 's') { signal(SIGHUP, handler); signal(SIGINT, handler); signal(SIGCHLD, handler); printf("Signal handler is set.\n"); }else if (buf[0] == 'q') break; } return 0;}

    シグナルハンドラ:受け取ったシグナルを書き出す

    自身のプロセスID

    シグナルハンドラを設定

  • 京都産業大学「オペレーティングシステム」(荻原)

    シグナルハンドラの例題: 実行例$ ./signalsPID = 15148Hangup: 1

    $ ./signalsPID = 15152sSignal handler is set.^CSignal 2 is received.Signal 1 is received.Signal 20 is received.Killed: 9$

    シグナルハンドラの設定をしていない

    kill -1 15148

    シグナルハンドラの設定をした

    キーボードから Ctrl-C

    kill -HUP 15152

    kill -20 15152

    kill -KILL 15152

    -9 と同じ

    -1 と同じ