Linuxシステムプログラミング(1-4章)

Linuxシステムプログラミング

Linuxシステムプログラミング

自分には結構良かった。手元に置きたい位。ただ、本当にできる人はmanやらdocumentやらヘッダファイル(ソース)にあたることでこの程度のことは理解しているんだよね。後半も必ず読みます。

  • 標準I/O
    • fflush()はストリーム内にあるまだ書き込まれて無いデータをカーネルバッファへ書き込む。その後fsync()でカーネルバッファをディスク上へ書き出す。
    • バッファリング方法の変更にはsetvbuf()が使える。(printfで改行を出力するまでメッセージが出力されないケースはこれを使って調整かな。)標準エラー出力を除き、端末はラインバッファリングされ、ファイルはブロックバッファリングされる。ブロックバッファリングのバッファサイズデフォルト値は、stdio.hで定義されるBUFSIZ。
    • 標準I/Oはスレッドセーフ(lock, unlockしている)
    • 標準I/Oの欠点として、二重コピー(ライブラリバッファへのコピー、カーネルバッファへのコピー)による遅延、等がある。
  • readv/writev
    • scatter-gather I/Oとか、ベクタI/Oとか言う。
    • システムコール発行回数の削減に加え、ベクタI/O内部の最適化によりパフォーマンス改善。
    • ベクタの要素数(count)が8以下なら、プロセスのカーネルスタックを使うのでメモリ効率がとても良い。
  • epoll()
    • event poll。poll(), select()の改良版
    • 要はイベントインタフェース。初期化するためのepoll_create(), ディスクリプタ追加/削除のためのepoll_ctl(), イベント待ち実行のためのepoll_wait()の3つのシステムコールによってスケーラビリティのボトルネック解消や機能強化を果たした。
    • エッジトリガとレベルトリガが選択できる。
      • エッジトリガ:信号変化の検出
      • レベルトリガ(デフォルト):イベント状態(アサート状態)の検出
  • mmap()
    • メモリ上のデータ変更が透過的にディスク上のファイルへ反映される。
    • ページサイズ(メモリマッピングの構成要素サイズ)を知る方法
      • unistd.h sysconf() #POSIX標準
      • asm/page.h PAGE_SIZE
    • mmap()の利点として、ユーザ空間のバッファコピーが発生しないこと、などがある。
  • posix_fadvise()
    • fdに対して、その使われ方情報を伝えることで、最適化を効きやすくする。
    • ランダムアクセスか、シーケンシャルアクセスか、等。試す価値ありそう。
  • synchronized, synchronous
    • synchronous: データが少なくともカーネルのバッファに書き込まれるまで戻らないこと。通常のリード/ライト
    • asynchronous: データがユーザ空間にあっても(処理がキューにつながれただけでも)戻ること。いわゆるAIO(非同期IO)
    • synchronized: データが実際にディスク上に書き出され終わることを保障する。いわゆる同期IO
  • 非同期I/O
    • Linuxカーネルではio_submit()およびaioカーネルスレッド(とりあえずキューイングしたIOを実際に実行するスレッド)で実装されている。
  • I/Oスケジューラ
    • コンピュータアーキテクチャを考えると、ディスクアクセスは非常に遅いのでそのスケジューリングが重要。
    • 現在のディスクはcylinder, header, sectorの組み合わせを、ブロック番号(物理ブロック、デバイスブロック)にマッピングしている。さらにファイルシステムは、論理ブロック(ファイルシステムブロック)という単位で処理する。ファイルシステムの論理ブロックは、ディスクの複数の物理ブロックに対応する。
    • 書き込みはデフォルトでノンシンクロナイズ。読み出しはシンクロナイズにする必要があるので遅い。結果、カーネルとディスクが書き込みストリームの処理に集中してしまう問題がおきる。(writes-starving-reads問題)
    • I/Oスケジューラのアルゴリズムはas, cfq, deadline, noop等。