2010年11月4日木曜日

Lions' Commentary (9) - 読書会#1 -

なんと、Lions' Commentary on UNIX 読書会が開かれる、という事で参加してきました。
しばらく独りで読み進めていましたが、まさか読書会に巡り会えるとは!
って、改めて読み返してみると、日記のエントリに1年近いブランクがありますね。
やばいやばい・・・時間が経つのが早過ぎる。

読書会ってのははじめてだったんですが、この会では1章ずつ読み進めます。
まずは時間が与えられて個々に内容を理解。その後、みんなで内容について議論する、と。
初回だったので進め方を決めて、さわりを・・・って感じでしたが、次回からは
月1回のペースで2章ずつ進める事になりました。途中参加もOKだと思うので
興味のある方がいたらぜひ。

1章〜4章は飛ばして実際の内容に入る5章からやりました。
pre K&RなC言語がわけわからんので、やっぱり3章も見とけば良かった・・・
みたいな話もありますが、まぁ必要になったら戻るという感じで。

5章はメモリ管理とpanic用の簡易版printfのところです。
mallocとかprintfとかいう名前だけど、libcの同名関数とは別物なので注意。
内容自体は簡単ですが、癖のある当時の文法が一番の悩みどころでした。

・型について
intとポインタはともに16bit。unsignedという考え方は存在しない。
  unsignedが必要な場合はポインタで代用する!!!
  このためstructのm_sizeの型がchar *になっている。
  ちなみにv7ではm_sizeはsigned shortだったりするけど。。。

・キャストが存在しない
  キャストがないため「*((int *)アドレス直値) = 書き込み値」みたいに書けない。
  そのかわり「->」を使うと型に関係なく構造体だと思ってメンバを探しにいく仕様で、
  構造体の名前空間も単一。これを利用して例えばintのメンバintegを持つ構造体を定義し、
  「アドレス直値->integ」と書く事で「*((int *)アドレス直値)」と等価になる。
  現代人からすると超キモイ仕様。

・大域変数にextern宣言をしない
  これは今でも通用するみたいなので、きちんとC言語の仕様をあたればそういう物かも。
  大域変数はあるソース(.c)に実体を置き、他のソースからはヘッダ(.h)にextern宣言
  された物をincludeして使う、というのが今時の描き方。
[foo.c]
 int global_variable;
 ...

[foo,h]
 extern int global_variable;
 ...

[bar.c]
 #include "foo.h"

 void bar (void) {
  global_variable = 1;
  ...
 }
  なのだが、実はexternは省略しても良い。リンク時に型や初期値の不整合がなければ
  1つにまとめてくれる。実際、coremapとswapmapはsystem.hで宣言されており、
  extern修飾もなければソース側での実体定義も存在しない。

・ldiv/lremはなぜアセンブラ?
  当時のC言語は乗除算は使えなかった? とか効率の良いコードが吐けなかった?
  とか憶測が飛び交ったけど、結局は妥当な理由が見当たらない。
  6th Cでのサポートはoracchaさんが試して通る事を確認しているし、吐かれるコードも
  悪くはない(関数にしなければinlineで展開されるのでprolog/epilogも不要なはず)。
  単純に前の版までアセンブラで書いてあったのでそのまま流用?とも思える。
  あるいはKernel書いてる頃にはコンパイラがサポートしておらず、その後ユーザランドを
  作ってるうちに面倒になってコンパイラサポートが入った、とか。
  v7ではアセンブラは廃止されてCの演算子で書かれてたりするので、この線が濃厚か。
  ちなみに、printnの最後はv6では「putchar(lrem(n, b) + '0');」という全うな書き方だが、
  v7では「putchar("0123456789ABCDEF"[(int)(n%b)]);」という微妙な書き方に。。。
  どう考えても遅いしメモリも食う書き方なので、こう書けるようになったのが嬉しくて
  つい書いてしまったコードに違いない。

・改行後のDEL
  改行がCRとLFにわかれているのと同様、歴史的な配慮?
  consoleがプリンタだった場合、描画位置を左に戻して、紙を送って・・・
  といった時間がかかるので、少し時間稼ぎ。
  プリンタがreadyを返さなければXSTのbusy loopで待つ気もするけど。

・8進数
  DECはPDP1の頃に8進数を使う文化が。。。
  詳細はこの辺とか。

・可変長引数
  stdargみたいな書き方は当然確立されていない。
  もちろん、やってる事はva_startとかva_argの中身と一緒なんだけど、
  実装を隠蔽せずに生でスタックを指すアドレスをずらして使ってる。
  なので、無理矢理ダミーの引数を並べて書いてあるけど、実は意味がない。
  引数を無駄に並べるのはv7で廃止されてるけど、実装はそのまま。

いくつか参考サイトを紹介します。
  1. 2238クラブ または 私は如何にして心配するのを止めてUNIXカーネルを愛するようになったか ... 貴重な日本語情報サイト
  2. Commentary on the Sixth Edition UNIX Operating System ... PDF版Commentaryあり
  3. Dennis Ritchie Home Page ... 6th Edition UNIXのC言語リファレンスマニュアルあり
  4. Operating System Engineering / xv6 ... x86/ANSI版
  5. xv6詳説 ... xv6のソースをひらメソッドで読む
  6. Plan9日記 2010-11-01 ... 読書会参加者のレポート
  7. やる気のないはてだ 2010-10-31 ... 同じく参加者のレポート
  8. PDP1 emulator on flash ... おまけ

0 件のコメント: