本記事は、Linuxの仕組みを読んで学んだことを
アウトプットするために作成しています。
記事全体は、5分程度で読むことが可能です。
カーネルとは?
カーネルを一言で言うと、プロセスからの要求を受け取り、
ハードウェア(CPU・メモリ・ディスク)を効率よく制御してくれる司令塔です。
では、どういった際にカーネルを理解していると役立つのかを考えました。
この本の中に、下記の記述がありました。
【階層】※仕事で利用する階層の上下1つを理解していると円滑に仕事ができる。
ユーザプログラム
OS外ライブラリ
OSライブラリ
カーネル
ハードウェア
つまり、僕らSEが一般的に書いているソースはユーザプログラムですが
OS外ライブラリの知識が必要ですよね。
なぜSEがここを学ぶべきか? それは、トラブルシューティングの「解像度」が上がるからです。
「ロケールはどこを参照するのだろう?」
「ファイル書き込みが遅いのは、ファイルシステムの仕組み上どこにボトルネックがある?」
こういった判断が、カーネルを知っているとスムーズになります。
「このエラーはライブラリ由来? それともOSの制限?」などが見えてきます。
カーネルプロセスについてを理解
前提として、sarコマンドというUnixコマンドがあります。実際にシステムコールができているかなど(Zabbixなどもこれを利用)監視することができます。実際にプロセスを動かしてシステムコールを動かしてみてください。
では、どうやってシステムコールを呼ぶのか?と疑問に思ったと思います。私たちが書くプログラム(高級言語)から直接ハードウェアはいじれません。そこで「システムコール」を使います。
じゃあどうよぶの?答えは、アセンブラ言語(低水準言語)によってcallします。OSがもっている、glibcにて内部的にシステムコールすることになります。glibcは標準Cライブラリで、Unix系のOSでよく利用されているようです。
呼ばれる順は、
高級言語 > 標準ライブラリ(glibc) > システムコール > カーネル
直接アセンブラを書かなくても、OSが用意した「ラッパー関数」が裏側で面倒な処理をやってくれているんですね。つまりユーザプログラム(高級言語)で私たちは常にシステムコールで何かを操作しているのです!
ラッパー関数とは?
既存の関数を「包む」新しい関数であり、元の関数に追加の機能や処理を加えるために使用されます。SEの方ならラッパークラスなどを作ったりしたことがあるのでイメージしやすいと思います。
プロセスを表示するコマンド
下記は、Ubuntuで実際に叩いて欲しいコマンドになります。
プロセスを列挙するコマンド
・ps aux
STAT項目の頭文字がSだとスリープ状態を表して、実行可能状況では、Rを示す。
Zもあるが、ゾンビ状態でプロセス終了に遷移する状況を表しています。
プロセスを木構造で表現してくれるコマンド(視認しやすい)
・pstree -p
詳細は使ってみて調べてみてください!
ASLRによるセキュリティ強化について
PIEという機能で、メモリのマッピングが毎度異なる設定が有効になっています。
これは、マッピング値の値を不正に書き込みされ値が更新されるのを予防するためのものです。
※バッファオーバーフロー攻撃やリターン・オリエンテッド・プログラミング(ROP)攻撃などのメモリ依存攻撃の成功率を低下させます。
ちなみに、Ubunts20.04ではデフォルトで有効となっているようです。
なぜこの話をしたのかは後述のシステムコールでメモリにマッピングするためです。実際には、仮想テーブルがあって仮想メモリにマッピングしたりするのですが、今回の記事の内容と乖離するので、今回は避けたいとおもいます。
システムコールの紹介
Linuxで新しい処理が始まる時、多くの場合この2つがセットで動いています。
fork() 関数
fork()はUNIX系OSで新しいプロセス(子プロセス)を生成するためのシステムコールです。
■処理順
・呼び出し元プロセス(親プロセス)を複製する。
・ほぼ同一の状態を持つ子プロセスを作成する。
※元プロセスとは独立して処理が可能になります。
execve() 関数
execve()も同様にUNIX系のコマンドです。
■処理順
・別挙動とする実行ファイルを読み込みする。
・現在のプロセスのメモリを新たなプロセスのデータで上書きする。
・新しいプロセスを実行する。
また、上記のコマンドなどによりアドレスへ初回書き込みが行われることをコピーオンライトと呼びます。CoWなんても言われたりします(※頭文字を抜粋しています)。
処理の流れは下記です(ページフォールトについては次の記事にあるので参照ください)。
→仮想アドレス空間を再構築(物理メモリなし)
→ 命令・データアクセス
→ ページフォルト
→ 物理メモリをその都度確保
→ 同一プロセスとして実行継続
コンテキストスイッチについても余談程度に解説します。
論理CPU上でプロセスが変更されることで、処理の完了が想定より遅くなったりなどすることです。論理CPU上でプロセスが変更される?と思った方も多くいらっしゃると思います。
まず、論理CPUとはCPUのコア数やスレッド数を指し、同時に処理できる命令やスレッドの数のことです。この中でプロセスが切り替わることにより処理が遅くなるということです。
デーモンとプロセスの違いについて
※ここは要学習課題です。
デーモンとプロセスの違いについてです。
これはRHELを利用している際によく聞いたことなので気になって調べてみました。プロセスは、上記の項目などで説明を設けたので不要かと思います。
デーモンは常駐プロセスのことを指し、initが親になっているので独自セッションで端末I/Oがないので、割り当てがないなどです。
まとめ
今回も読んでいただきありがとうございました。
高級言語のありがたみが物凄くしみます、ソースを書いているPGもすごいのですが、ハードウェア寄りのことをしている人はマニアックだなと、思いますよね。
次回は、カーネルのメモリ管理システムについて解説をしていきたいと思います!


コメント