はじめてのOSコードリーディング ~UNIX V6で学ぶカーネルのしくみ (Software Design plus) 新品価格 |
悪魔本 P455-P457 #readDaemon
だいたいの構図
xterm | (xterm) ↓ プロセス(ユーザーの入力) ↕ スレーブ(擬似端末) ↕ マスター(擬似端末) ↕ HW
擬似端末はxterm ssh telnetなどによって利用される
端末管理モード
- カノニカルモード
- COOKEDモード
- 行入力モード
カノニカルモード
入力の取り消しが可
非カノニカルモード
入力の取り消しが不可
回線制御規則
tty構造体 P386
各端末は対応するtty構造体を持つ。(tty.h)
バッファキューを3つ持つ。
ttyのフラグがあったりttyの状態フラグがあったりする
struct tty { struct clist t_rawq; /* input chars right off device */ struct clist t_canq; /* input chars after erase and kill */ struct clist t_outq; /* output list to device */ int t_flags; /* mode, settable by stty call */ int *t_addr; /* device address (register or startup fcn) */ char t_delct; /* number of delimiters in raw q */ char t_col; /* printing column of device */ char t_erase; /* erase character */ char t_kill; /* kill character */ char t_state; /* internal state, not visible externally */ char t_char; /* character temporary */ int t_speeds; /* output+input line speed */ int t_dev; /* device name */ };
データの処理は行単位で行われ、改行の入力でtty.t_trawqにデリミタが追加される。
端末はキーを1つ押したらkl11に垂れ流す
比較 proc構造体
maptabとpartab
maptab[]
端末は文字セットにASCIIコードを用いる
純粋な文字として扱うためには\のあとに入力しないといけない文字をmaptabで管理している
dmr/tty.c
/* * Input mapping table-- if an entry is non-zero, when the * corresponding character is typed preceded by "\" the escape * sequence is replaced by the table value. Mostly used for * upper-case only terminals. */ char maptab[] { 000,000,000,000,004,000,000,000, 000,000,000,000,000,000,000,000, 000,000,000,000,000,000,000,000, 000,000,000,000,000,000,000,000, 000,'|',000,'#',000,000,000,'`', '{','}',000,000,000,000,000,000, 000,000,000,000,000,000,000,000, 000,000,000,000,000,000,000,000, '@',000,000,000,000,000,000,000, 000,000,000,000,000,000,000,000, 000,000,000,000,000,000,000,000, 000,000,000,000,000,000,'~',000, 000,'A','B','C','D','E','F','G', 'H','I','J','K','L','M','N','O', 'P','Q','R','S','T','U','V','W', 'X','Y','Z',000,000,000,000,000, };
partab[]
文字列の出力処理に使われる
/* */ char partab[] { 0001,0201,0201,0001,0201,0001,0001,0201, 0202,0004,0003,0205,0005,0206,0201,0001, 0201,0001,0001,0201,0001,0201,0201,0001, 0001,0201,0201,0001,0201,0001,0001,0201, 0200,0000,0000,0200,0000,0200,0200,0000, 0000,0200,0200,0000,0200,0000,0000,0200, 0000,0200,0200,0000,0200,0000,0000,0200, 0200,0000,0000,0200,0000,0200,0200,0000, 0200,0000,0000,0200,0000,0200,0200,0000, 0000,0200,0200,0000,0200,0000,0000,0200, 0000,0200,0200,0000,0200,0000,0000,0200, 0200,0000,0000,0200,0000,0200,0200,0000, 0000,0200,0200,0000,0200,0000,0000,0200, 0200,0000,0000,0200,0000,0200,0200,0000, 0200,0000,0000,0200,0000,0200,0200,0000, 0000,0200,0200,0000,0200,0000,0000,0201 };
KL11/DL11
端末関連のソースコードは「端末共通の処理」と「各端末インターフェース専用のデバイスドライバ」に分かれる
KL11/DL11 16ビットのレジスタを4つ持つ
1つのポートを持って1つの端末と接続出来、かつKL11/DL11インターフェースはシステムに複数接続される。
ドライバの仕様
なぜかアドレス埋め込み…
/* base address */ #define KLADDR 0177560 /* console */ #define KLBASE 0176500 /* kl and dl11-a */ #define DLBASE 0175610 /* dl-e */
で、デバイスドライバ関数がいろいろ登録されている。
テレタイプ(tty=teletype)
テレタイプは商品名で、ただデータを通信するだけの装置。
klopen()
端末のオープン処理を行うデバイスドライバである。
openシステムコールを発行うるとklopenが実行される。
該当端末のアドレスを算出して、tty構造体とレジスタの初期設定を行う。
klopen(dev, flag) { register char *addr; register struct tty *tp; if(dev.d_minor >= NKL11+NDL11) { /* #define NKL11 1 #define NDL11 0 */ u.u_error = ENXIO; return; } tp = &kl11[dev.d_minor]; if (u.u_procp->p_ttyp == 0) { u.u_procp->p_ttyp = tp; tp->t_dev = dev; } /* レジスタのベースアドレスを計算する */ /* マイナー番号によって割り振り方が変わる */ /* * set up minor 0 to address KLADDR * set up minor 1 thru NKL11-1 to address from KLBASE * set up minor NKL11 on to address from DLBASE */ addr = KLADDR + 8*dev.d_minor; if(dev.d_minor) addr =+ KLBASE-KLADDR-8; if(dev.d_minor >= NKL11) addr =+ DLBASE-KLBASE-8*NKL11+8; tp->t_addr = addr; /* 端末の状態をチェック */ if ((tp->t_state&ISOPEN) == 0) { /* tty構造体の初期化 */ tp->t_state = ISOPEN|CARR_ON; tp->t_flags = XTABS|LCASE|ECHO|CRMOD; tp->t_erase = CERASE; /* # */ tp->t_kill = CKILL; /* @ */ } addr->klrcsr =| IENABLE|DSRDY|RDRENB; addr->kltcsr =| IENABLE; }
ISOPENとCARR_ONの違いはなんぞや
klopen実行
- エラーチェック
- アドレス割り当てチェック
- アドレス割り当て
- tty初期化
- レジスタにフラグをセット
devの型はintで、intにキャストしてる?
割り当てメカニズム
- 要求されたブロックに最も近いブロックを選択する
- シリンダグループが満杯だったら別のシリンダグループを求める
- 近いところから探し、見つからなければ別のところから探していく
ブロックのサイズは比較的大きいので、ブロックをさらにフラグメントごとに分けて、割り当てていく
- すでに割り当てられているブロックに余裕があれば、そこに新しいデータを格納
- 余裕がなければ別のブロックにデータを格納
ブロックの割り当てが終了すると、システムはブロックの内容を保持するバッファを確保して、ブロックをディスクに書き出す準備をする
- ffs_balloc()
- ffs_blkpref()
適当なサイズのフラグメントがフラグメントの要約情報になければ、割り当て関数は割り当てマップから探そうとする。
高速化のためにテーブル参照型のアルゴリズムを使う。
空間最適ポリシー フラグメント化を最小限にするメリットとフラグメントのコピー回数を最大化するというデメリットがある。
領域ではなく時間によって最適化するようにファイルシステムを設定することも可能であるが、過剰にフラグメント化されることもありうる。