Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
たまには名前らしいことを
Search
Takanori Watanabe
May 11, 2025
790
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
たまには名前らしいことを
FreeBSDのinitについて
Takanori Watanabe
May 11, 2025
Featured
See All Featured
We Have a Design System, Now What?
morganepeng
55
8.4k
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
560
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
710
Build your cross-platform service in a week with App Engine
jlugia
234
19k
We Are The Robots
honzajavorek
0
400
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.5k
Practical Orchestrator
shlominoach
192
12k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Automating Front-end Workflow
addyosmani
1369
210k
Building an army of robots
kneath
307
47k
The agentic SEO stack - context over prompts
schlessera
0
970
Facilitating Awesome Meetings
lara
57
7.2k
Transcript
たまには名前らしいことを FreeBSDのinitについて
[email protected]
[email protected]
自己紹介 • 渡辺尊紀 / Takanori Watanabe • takawata(別にひねりもなく自分の名前) • X
@takawata19 • FreeBSDの開発者 最近サボり気味 ACPIなんかをちょっといじっ たりした。
はじめに • 今回、ちょっとした機会があってFreeBSDのinitに付いて調べてみた。 • 基本的にはレガシーなものだがちょっとした発見もあったので発表す る。
initとは • ユーザーランドのおはようからおやすみまでプロセスを見つめるプロ セス。 • 伝統的には直接カーネルから起動される唯一のプロセス • 近年のLinuxではsystemdになっている。
ここでFreeBSDの起動プロセスを軽く • まず、アセンブラで書かれたカーネルエントリに入る • アーキテクチャ依存の初期化関数が走って戻ってくる。 • init_main.c:mi_startup()という関数が呼ばれる。 • かつてはmain()という名前の関数だった。 •
ちなみに私はinit-main.comというドメインを持ってる。 • この中でデバイスドライバ等アーキテクチャ独立な初期化が行われ る。 • 最後付近でユーザーランドプロセスであるinitが起動する。
initの起動前のファイルシステム設定 • ここはkern/vfs_mountroot.cで行われる。 • まず、devfsを/にmountする • ブートローダが初期化するカーネル環境変数にあるルートファイルシ ステムの指定にしたがってルートファイルシステムをmountする。 • そのルートファイルシステムにある/devにdevfsのマウントポイントを
移動させる
initの起動 • initは必ずPID=1である必要があるため、PID=1を作成して初期化す る。 • 今はinitの起動前にカーネルプロセスがそこそこ起動する。 • この時にスレッド起動ハンドラを設定する。 • カーネルの起動の最後付近で作成したプロセスを実行可能にする。
• PID=1のカーネルスレッドの起動ハンドラからinitをexecveする。 • 起動ハンドラ内でカーネルコマンドラインで-sがついていたらexecve のargv[1]に”-s”を渡す
init • initはPID=1以外で起動された時はPID1のプロセスにシグナルを 送って終了するだけ。 • PID1で起動した場合、devfsがmountされていることを確認し、ス テートマシンをずっと無限ループで実行する。
ステートマシン 最初の始状態、停止状態の他に以下の状態がある。 • single_user • runcom • read_ttys • multi_user
• clean_ttys • catatonia • death • death_single • reroot • reroot_phase_two
状態遷移図 initial single_user runcom reroot_phase_two end death_single reroot read_ttys multi_user
clean_ttys death catatonia
状態遷移 • 始状態と終状態以外はinitの中のCの関数として実装されており、そ れぞれの関数は次に遷移する状態の関数ポインタを返す。 • 始状態への遷移も存在し、それはinit自身をexecすることで行われ る。 • 終状態へはreboot(2)システムコールの発行によって移行する。
始状態 • main関数に入った時の状態 • devfsのマウントをチェック • -rオプションが渡された場合reroot_phase_twoに移行 • -sオプションが渡された場合、single_userに移行 •
その他はruncomに移行
single_user • シングルユーザーモード • 最初にReboot変数をチェックしRebootする必要があればreboot(2) をシグナルハンドラで変更されたグローバル変数howtoを引数に発 行する。つまりここから終状態に移行する。 • コンソールに対してシェルを上げる •
そのシェルが正常にexitした場合はruncomに移行する
runcom • /etc/rcを実行する状態。ちなみにruncomとはMITのCTSSシステム のスクリプトに由来し、rcという名前もそれにちなむ • 正常に終了するとread_ttysに移行する
read_ttys • /etc/ttysを読みセッションを作成する状態 • /etc/ttysの有効なエントリごとにセッションを作成する。 • セッションに対して最初にどのプロセスを上げるかその端末は何かな どが含まれる。 • 終わるとmulti_userに移行する
multi_user • 通常の運用状態 • セッションごとに登録済みのプロセスを上げていく。 • あとは延々waitpidを発行して待っておく • signalが発行されたり、子プロセスや孤児プロセスが終了すると waitpidから起きる。
• シグナルハンドラで状態遷移が要求されると別の状態に移行する • 正常にプロセス終了を検知した場合、セッションのpidと比較し、一致 した場合、セッションを再び上げ直す。
そもそもセッションって • セッションとは端末などに結び付けられたプロセスの集合 • 端末ドライバにはセッション全体にシグナルを送る機能が有り、これ によってログアウトした時に残ってるプロセスを全部終了させたりす ることができる。 • 似たような概念にプロセスグループがあり、パイプで繋がれたプロセ スを同じプロセスグループに属させることにより全体にシグナルを送
ることで一体的なジョブ制御ができる。(セッションは複数のプロセス グループで構成される:詳しくは然るべき書籍を参照)
clean_ttys • multi_userでSIGHUPを受け取った時に遷移する。 • /etc/ttysを再読込し、セッションの情報を更新しエントリがないセッ ションに属するプロセスを全て殺す。 • multi_userに遷移する
catatonia • 統合失調症の症状で外部への反応が無くなる緊張病の意味らしい • multi_userでSIGTSTPを受け取った時に遷移する • 全てのセッションに対して以降セッションを上げ直さないようにフラグ を設定する。 • multi_userに戻る
death • SIGUSR1, SIGUSR2 SIGINT SIGWINCHを受け取った時に multi_userから移行する。(微妙な書き方をしているのは、multi_user 以外で受け取った時に戻ってから遷移することもあるため) • 全てのセッションを無効化し/etc/rc.shutdownを実行して、
death_singleへ移行する • なお、シグナルによってRebootやhowtoというグローバル変数に別の 値が入った状態になる。
death_single • 全ての通常のプロセスにSIGTERM を送り、waitpidで待つ • 終わっていないプロセスがあれば数秒後にSIGKILLを送りwaitpidで 待つ • 全ての対象のプロセスが終わるか、数秒後にsingle_userに移行す る
• リブートなどはsingle_user内で行われる。
reroot • multi_userからSIGEMTによって移行 • rootファイルシステムをカーネルリブートせずに変更するもの。 • ttyを無効化しrc.shutdownを実行し全てのプロセスを殺す。 • tmpfsを/dev/rerootにmountし自身を/dev/reroot/initにコピー •
/dev/reroot/initを -rオプションでexecする。(つまり始状態に移行す る)
reroot_phase_two • コマンドラインで-rが指定された時に始状態から遷移する。(つまり実 質的にはrerootからの遷移) • reboot(RB_REROOT)を発行することで、kenvで指定された新たな ルートファイルシステムがマウントされる。 • 新たなrootファイルシステムにあるinitを引数なしでexecveする。(つ まり本当の始状態に遷移する)
結論 • 今回、レガシーなinitについて見てみた。 • 案外とやるべきことがあるのだなということがわかった。 • シングルユーザーモード・マルチユーザーモードはinitで処理される 概念でカーネルは道具を揃えている感じ。 • FreeBSDでルートファイルシステムをカーネルを再起動せずに入れ
替える方法があることを知ったのが発見(なお、ユーザーランドは総 入れ替えが必要)