戦場のプログラマー

名前は誰も知らない。

「はじめてのOSコードリーディング 読書会 (15)」に行ってきました

先週の5/24(土)に生まれて初めて勉強会に行ってまいりました。
※正確には読書会です。

はじめてのOSコードリーディング 読書会 (15) - connpass

はじめてのOSコードリーディング ~UNIX V6で学ぶカーネルのしくみ (Software Design plus)

はじめてのOSコードリーディング ~UNIX V6で学ぶカーネルのしくみ (Software Design plus)

UNIX V6とはUNIXカーネルのバージョン6のソースコードで、10,000行程度でOSに必要な実装がなされているため、カーネルのコードリーディングにはちょうどよい教材なのだそうです。
ただ、それでもLions本は読み解くのが相当難しいらしいですが・・・。

こういった集まりに参加するのはほんとに初めてなので、
会場はどういったものなのか、どのような人たちが集まって
どのような会話が繰り広げられるのかといったいろいろと想像してドキドキでした。

辿り着くまで

会場は池袋駅近くのビルでした。
まだ東京に来て慣れないので、迷う可能性も考えて2時間前には出発しました。
・・・案の定迷いました。
池袋駅まで来たのは良かったけれども、いったいどこから地上に出られるのかわからない!
案内図を見ると出口がいっぱいある・・・。
どれかそれっぽい出口を出て看板を見るとそこには東京メトロのロゴが・・・。
僕は確かにJRの駅で降りたはず・・・と混乱しながらGoogleマップをたよりにやっとこさ会場にたどり着きました。

会場についてから

会場にはもうすでに2名ほどの方がいらっしゃいました。 少しくして主催者の @7shi さんまでそろい、僕も含めて9名で開催されました。

念のため自分のMBAも持って行っていたのですが、みなさんも全員ノートPCやらMBPやらお持ちでした。 メモをとったり、UNIX V6のソースコードを見たりするときに便利でした。

さりげなくまわりを見渡すと

なんだかとても親近感を覚えながらも読書会は開幕しました。

@7shi さんのプレゼンテーション

ここで @7shi さんが次の日のイベントで発表されるプレゼンのリハーサルを聞かせていただきました。

に参加されるとのことでした。

  • UNIXV1~V7~OpenBSDまでのソースコード発展の流れ
  • PDP-11を勉強していたが不人気
  • 教材としてx86 OSの検討
    • Minix(ack) 意図的な断絶
    • xv6(gcc) むずい
    • V7/x88(ack) むずい

V6のPDP-11からx86プロセッサへの移植作業をし始めた!

  • 16bit(リアルモード=8086)動作限定
  • BIOS経由の同期アクセスのみ

その他やることとしては

  • libcのトランスレート
  • ユーザーランドの移植
  • カーネルの移植
  • 最終的にはVMwareQemuで動くようにする

ちょっとした小話ですが、V1は全部アセンブラで書かれているそうです(!)
ちなみにEXEを作って遊ばれていたとのことでしたが、C言語のソースをVSでビルドするというレベルの話ではなくて、
機械語を自分の手で書いて遊ばれていたそうです、すごい・・・。

BSDカーネルの設計と実装 読書会

これから本題かと思いましたが、「BSDカーネルの設計と実装 読書会 (22)」が同時に開催されるようです。
これについては僕も予想していなかったのですが、隣の方に本を見せていただきながら
読書会に参加させていただきました。 ありがとうございます!

BSDカーネルの設計と実装―FreeBSD詳解

BSDカーネルの設計と実装―FreeBSD詳解

  • 作者: マーシャル・カークマキュージック,ジョージ・V.ネヴィル‐ニール,砂原秀樹,Marshall Kirk McKusick,George V. Neville‐Neil,歌代和正
  • 出版社/メーカー: アスキー
  • 発売日: 2005/10/18
  • メディア: 単行本
  • クリック: 122回
  • この商品を含むブログ (57件) を見る

こちらの本は絶版になっています。購入するには中古で購入する必要があります。

歌代和正さん訳の本とのことで、Perl界隈で有名な方だそうです。
って、あとで調べてみたら jcode.pl を開発された方ですか!
そりゃ有名なはずですね・・・。

以降の話は全体的に8.6ソフトアップデートに関するお話でした。 ジャーナリングとは根本的に違うようです。

8.6.8 新規ディレクトリエントリの依存管理

8.6.9 新規ディレクトリの依存管理

以下、かいつまんで単語レベルでぶつ切りに並べてありますが、
ボイスレコーダー等で正確にトレースしたわけではないので、
私の書いていることは話半分に聞いてください。

  • ビットマップ
  • ディスク上の対応
  • 依存関係がある
  • ビットマップを作成する前にinodeを作成するとまずい
  • どの段階で電源が切れても大丈夫なように依存関係を管理する手法
  • あとでfsckをかければ直る程度になる

8.6.10 ディレクトリエントリの削除にかかわる依存処理

  • ソフトアップデート
  • ディスク上の話

8.6.11 ファイルの短縮

100MB→0バイトにすること。ファイルの削除ではない。

  • 8.6.13 ディレクトリエントリの名称変更にかかわる依存性管理

  • ロールバック

  • diradd
  • dirrem
  • BをXに変える

8.6.14 ファイルの削除に関する依存管理

8.6.15 ソフトアップデートがfsyncをサポートするための条件

  • inodeのビットマップ書き出しが完了しているか
  • FreeBSD3.xのころにソフトアップデートが導入された

ここで 7shi さんからこんな体験談を聞きました。

  • 大量のソースコード削除してみる
  • プロンプトは戻ってきてもずっとディスクアクセスが続く
  • dfの結果がなかなか減らない
  • これがソフトアップデートの結果?

  • 今やってる本はFreeBSD5.2の本

このあたりでZFS(ズィーエフエス)Btrfs(バター エフエス)の話も出ましたね。 ZFSは使ったことがありますが、重複排除機能がすばらしいですね、 2GBのファイルをcpしてもディスク上の使用量は4GBとはならずほぼ2GBでとどまります。 ただ面白いことにdfの結果は全体的な容量が増えたような結果を返すんですよね。 ただ、お話にも出てましたがメモリは積んだら積んだ分だけめっちゃくちゃメモリ食います。

ここで巨大なファイルの読み込みの仕組みの話。

  • ディスクとメモリがマップされる
  • 必要になったらメモリに読み込む
  • 4GBとかデカイ動画ファイルはメモリマップしてファイルの中身を読み書きするらしい。
  • ページキャッシュ

今年の秋頃新板が出る予定(ただし英語、ZFSの話とかも入る)

  • 8.6.17 fsckに必要なソフトアップデートの条件

  • ソフトアップデート + fsckでは

  • lost+found ディレクトリに退避される
  • いっぱいになっちゃう(何がいっぱいになっちゃうのかは忘れてしまいました。。。)

8.6.18 ソフトアップデートの性能

  • 同期とソフトアップデートではかなり性能差がある
  • 同期: 27時間15分
  • ソフトアップデート: 19時間50分

はじめてのOSコードリーディング 読書会 (15)

10分ほど休憩を挟んでいよいよ本題です。
本日の内容は 第11章のパイプ(p.348) からです。
僕はp.60のforkシステムコールのところまで。
さすがにここまで追いつくことはできませんでした・・・。

第11章 パイプ

パイプはパイプのストレージ領域 PIPSIZ(4096) に少しずつためながら流し込んでいますが、

ls | sort

この場合の sort コマンドを実行した時はどうなるの? という疑問が上がりました。 ソート側のバッファにパイプから流れてくる内容をためてからソートしているはずとの予測が出てきました。

@7shiさんから、V6のソートのソースコードは短いですよ~とのお話を頂いたので、この場で読み込んでみる形と相成りました。

このころはlibc自体は発展途上 sort.cの中でテンポラリファイルの作成処理等をやってる

/* src/s2/sort.c */
    i = lspace = sbrk(0);/* 135 */
    while(brk(a) == -1)
        a =- 512;
    brk(a =- 512); /* for recursion */
    a =- i;
    nlines = ((a-L)>>1) & 077777;
    nlines =/ 5;
    ntext = nlines*8;
    tspace = lspace+nlines;/* 143 */
    file = "/usr/tmp/stmXaa";
loop:
    filep = file;
    while(*filep != 'X')
        filep++;
    for(*filep = 'a';;(*filep)++) {
        if(stat(file, lspace) < 0) {
            a = creat(file, 0600);
            if(a >= 0)
                break;
        }
        if(*filep == 'z') {
            if(file[1] != 't') {
                file = "/tmp/stmXaa";
                goto loop;
            }
            mess("Cannot locate temp\n");
            exit(1);
        }
    }
    close(a);
    filep++;
    if ((signal(2, 1) & 01) == 0)
        signal(2, term);
    nfiles = eargc;
    if(!mflg) {
        ibuf[0] = -1;
        sort();
        close(0);
    }
    for(a = mflg?0:eargc; a+N < nfiles; a=+N) {
        newfile();
        merge(a, a+N);
    }
    if(a != nfiles) {
        oldfile();
        merge(a, nfiles);
    }
    error = 0;
    term();
}

sort()
{
    register char *cp;
    register *lp, c;
    int done;
    int i;
    int f;

    done = 0;
    i = 0;
    do {
        cp = tspace;/* 197 */
        lp = lspace;/* 198 */
        while(lp < lspace+nlines && cp < tspace+ntext) {/* 199 */
            *lp++ = cp;
            while((*cp++ = c = getc(ibuf)) != '\n') {
                if(c >= 0) continue;
                cp--;
                close(ibuf[0]);
                if(i < eargc) {
                    if((f = setfil(i++)) == 0)
                        ibuf[0] = 0;
                    else if(fopen(f, ibuf) < 0)
                        cant(f);
                } else
                    break;
            }
            if(c < 0) {
                done++;
                lp--;
                break;
            }
        }

私には難しくてあんまり理解できませんでした・・・。

  • gnu global?
  • カーネル側とlibc側のgetcがある
  • getcはシステムコールのもの?
  • 一般的なパイプ
  • isatty
  • パイプから来てるのか、標準入力から来てるのか

  • teeコマンドの動き

  • 今ならカーネルのバッファに

  • パイプを何段もつないだ場合にエラーとなる

  • pipeシステムコールがいくつも呼ばれてFILE構造体がたくさん確保されてENFILEエラーが発生する

ちょっとここで小話がありました。

  • V1アセンブラはプリントアウトしたソースからOCRで復元したものだそうですw
  • V2, V3のカーネルソースは失われている。ソースはあっても逆アセンブルしたものなので見るものによって見た目が違う。

  • prele(リリース)は root/usr/sys/ken/pipe.c に定義されているのにパイプと関係ないところからいくつも呼ばれているw

/*
 * Unlock a pipe.
 * If WANT bit is on,
 * wakeup.
 * This routine is also used
 * to unlock inodes in general.
 */
prele(ip)
int *ip;
{
    register *rp;

    rp = ip;
    rp->i_flag =& ~ILOCK;
    if(rp->i_flag&IWANT) {
        rp->i_flag =& ~IWANT;
        wakeup(rp);
    }
}

plock()

  • トイレと同じ原理
  • 開けて!

参考としては

以下、覚書です。

  • PDP-11のシミュレータ
  • コルーチン
  • dup
  • STDOUTを保存しとかないと失われる
  • daemonの作法としてSTDOUTを閉じる
  • initの子

雑談

読書会も終盤にさしかかりました。 あまった時間で参加者の方からこういった勉強会に参加してきたよというお話を伺えました。

要約すると1つのOS単位でAPサーバが気軽に立てられる、いかにもクラウド指向なOSのようです。

おわりに

と、ここで18時も過ぎた頃でお開きとなりました。
この場で引き続きラテン語講座も開かれるようでしたが、僕はこのへんで失礼させていただきました。

新・初級ラテン語リーディング(7) - connpass

今回勉強会に参加されていた方たちともいろいろなお話ができてとても刺激になりました。
池袋駅までの帰り道では勉強会に参加されていた方といろいろな世間話をさせていただきました。
さっそくTwitterでフォロー申請させていただきました。
いろいろとコアな方と交流出来て楽しかったです。

次回6/21(土)も続きがあるようですので、是非参加してみたいと思います。
今度は迷わないようにするぞ。

それではそれでは。