by shigemk2

当面は技術的なことしか書かない

悪魔本 P455-P457 #readDaemon

だいたいの構図

xterm
|
(xterm)
↓
プロセス(ユーザーの入力)
↕
スレーブ(擬似端末)
↕
マスター(擬似端末)
↕
HW

擬似端末はxterm ssh telnetなどによって利用される

端末管理モード

  • カノニカルモード
  • COOKEDモード
  • 行入力モード

カノニカルモード

入力の取り消しが可

非カノニカルモード

入力の取り消しが不可

回線制御規則

文字処理の多くは擬似端末やハードウェアデバイスに依存せずに、ttyドライバに依存する

ttyドライバとシステム内の他の部分とのインターフェイスは回線制御規則である(line discipline)

シリアル端末インターフェイスはキャラクタデバイススイッチで定義される、標準的なキャラクタデバイスドライバのエントリポイントである。

エントリーポイント - Wikipedia

  • linesw構造体
  • l_open
  • l_lint

データのやりとりはシリアル通信で行う(PDP11あたりからの名残)

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

中古価格
¥7,243から
(2014/7/26 14:51時点)

tty構造体 P386

各端末は対応するtty構造体を持つ。(tty.h)

バッファキューを3つ持つ。

[Q&A] バッファとキューについて 【OKWave】

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[]

パリティビット - Wikipedia

文字列の出力処理に使われる

/*
 */

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にキャストしてる?

割り当てメカニズム

  • 要求されたブロックに最も近いブロックを選択する
  • シリンダグループが満杯だったら別のシリンダグループを求める
  • 近いところから探し、見つからなければ別のところから探していく

Unix File System - Wikipedia

ブロックのサイズは比較的大きいので、ブロックをさらにフラグメントごとに分けて、割り当てていく

  • すでに割り当てられているブロックに余裕があれば、そこに新しいデータを格納
  • 余裕がなければ別のブロックにデータを格納

ブロックの割り当てが終了すると、システムはブロックの内容を保持するバッファを確保して、ブロックをディスクに書き出す準備をする

  • ffs_balloc()
  • ffs_blkpref()

適当なサイズのフラグメントがフラグメントの要約情報になければ、割り当て関数は割り当てマップから探そうとする。

高速化のためにテーブル参照型のアルゴリズムを使う。

空間最適ポリシー フラグメント化を最小限にするメリットとフラグメントのコピー回数を最大化するというデメリットがある。

領域ではなく時間によって最適化するようにファイルシステムを設定することも可能であるが、過剰にフラグメント化されることもありうる。