Linux カルテット

August 31, 2017

使用するコード

Vanilla Kernel v4.12.4

OS とは

wikipedia: https://ja.wikipedia.org/wiki/オペレーティングシステム

Linux ( OS ) なしで sshd を実現可能か考える
-> 可能。OS はただのプログラムなので、処理を代行するプログラムを書けば良いだけ。

OS の代わりにやるべきこと

  • マルチタスク制御 ( 同時に複数人のユーザーが接続した場合の制御 )
  • メモリ管理
  • ファイルシステム
  • ブロックデバイス管理
  • NIC の管理
  • TCP フロー制御

sshd や httpd が共通して用いる基盤を作ろう! -> OS

OS の歴史

  • 1956 年: GM-NAA I/O
  • 1960 年代: CDC Scope
  • 1965 年: Multics
  • 1969 年: Unics ( Unix )
  • 1977 年: BSD ( Unix のコードから )
  • 1981 年: MS-DOS
  • 1985 年: Windows ( Ver.1 )
  • 1987 年: MINIX
  • 1990 年: DOS/V
  • 1991 年: Linux
  • ちなみに Amazon Linux AMI なので、ディストリビューションではない。

( OS についてくるパッケージが用いる共通基盤がカーネル )

システムコールとは

OS の機能を呼び出すために行う命令

C 言語におけるシステムコールについて

malloc() とかは OS のシステムコールっぽく見えるけど、実は glibc ライブラリの 1 関数でしかなく、glibc の malloc() の実装により、実際にシステムコールされるかどうかが決まる。

タスクとは

マルチタスク

  • 複数の処理を切り替えて実行するシステム
  • 瞬間的に 1 CPU コアで動作するタスクは 1 つ

プロセス: 1 実行ファイルを起動すると、 1 プロセスが作成される

スレッド: 1 プロセスには最低限 1 スレッドが存在し、同じプロセス内のスレッドはメモリ空間を共有している

ライトウェイトプロセス: カーネルは LWP で実行をスケジュールしている

プロセスの構造を追いかけたい場合は、./include/linux/sched.h 501 struct task_struct {
linux カーネルの構造として、プロセス構造体は存在せず、スレッドの集合となっている。
つまり getProcessId() -> getThreadGroupId()

コンテキストスイッチ

プロセスの切り替え、スレッドの切り替えにはコストがかかる。

  • どのタスクの処理も CPU 上のレジスタを使用して行う
  • レジスタは全タスクが同じものを使用する
  • スレッドを切り替える場合はレジスタの値を一度バックアップする。-> スレッドの切り替えはちょっと重い

コンテキストスイッチ入り口 ./kernel/sched.core.c l2839 l2840

シグナル

http://equj65.net/tech/linuxprocessgroup/

$ man -s 7 signal

でも確認可能

$ sleep 100 
^C

-> SigInt が sleep に送られ、sleep は SigInt に対するハンドラが定義されておらず、Term がハンドラとして用いられる。

$ ulimit -c
unlimited
/*                                                                                                                                                            
 * Flush all handlers for a task.                                                                                                                             
 */

void
flush_signal_handlers(struct task_struct *t, int force_default)
{
        int i;
        struct k_sigaction *ka = &t->sighand->action[0];
        for (i = _NSIG ; i != 0 ; i--) {
		if (force_default || ka->sa.sa_handler != SIG_IGN)
                        ka->sa.sa_handler = SIG_DFL;
                ka->sa.sa_flags = 0;
#ifdef __ARCH_HAS_SA_RESTORER
		ka->sa.sa_restorer = NULL;
#endif
               	sigemptyset(&ka->sa.sa_mask);
                ka++;
        }
}

カーネルモジュールとは

-> ざっくり言うとカーネルのプラグイン。

$ lsmod #ロードされているカーネルモジュール
$ modinfo ipv6 #カーネルモジュール ipv6 の情報
$ sudo iptables -L #iptables を使うと
$ lsmod #iptables_filter などのカーネルモジュールがロードされていることがわかる
$ sudo modprobe -r potable_filter #アンロード  
$ sudo modprobe potable_filter #手動アンロード

覚えておきたいカーネルモジュール: dsa_filter ( よくメモリを食う )
-> lsmod 叩いてもらうのが一番早い。

マルチスレッド/プロセスとノンブロッキング

マルチスレッド/プロセス: accept()、recv() で接続要求及びデータが来るまで待つ。
ノンブロッキング: データドリブンで、接続要求及びデータが来てからそれを処理する。( イベントが来るまで何をしていても良い )


 © 2023, Dealing with Ambiguity