批判の対象集
この記事は少し攻撃的に見えるかもしれないので、私は中高年の方々にはお勧めしません。また、この記事で言及されている部分に同意できない場合は、コメントをいただき、詳細な理由を教えていただけると幸いです。
何がオペレーティングシステムか#
ハードウェアとの相互作用を処理するためのソフトウェア これが私のオペレーティングシステムの定義です。オペレーティングシステムは IE ブラウザと同様にソフトウェアであり、彼らには劣悪な可能性があります。
一般的に、オペレーティングシステムは異なるハードウェア上でほぼ同じように機能する行動を持っていますが、これは必須ではありません。実際、私は互換性にはあまり関心がありませんが、ハードウェアの詳細を隔離し、ソフトウェアインターフェースを統一することは、開発者にとって自分のソフトウェアをより多くのプラットフォームに移植するのに役立つことは確かです。
現在のオペレーティングシステム陣営#
古代の陣営は現実的な意味を持たず、Solaris は ZFS だけが残り、Unix は死に、Minix は教科書の中で永遠に生き続けます。
オペレーティングシステムには一般的に標準があります。現在、私たちは 3 つの標準を持っています。
- POSIX 標準
- GNU/LINUX 事実標準
- WINDOWS/MAC/ その他独自の標準
まず、POSIX が何であるかを説明しましょう。私は POSIX を、古い UNIX 上のソフトウェアを新しいプラットフォームに移行するためのものだと考えています。私の見解では、UNIX オペレーティングシステムの歴史的な負担が皆に遵守を強制する標準です。
したがって、POSIX 標準は劣悪なものであり、これについては特に言うことはありません。実際、皆が部分的に互換性を持っているのですが、これは完全な互換性よりも恐ろしいことです。
次に LINUX について話しましょう。実際、LINUX 自体のコードはすでに十分に複雑ですが、GNU を除外すると、ユーザーランドは FreeBSD が提供する環境を使用しています。そうすると、あなたのカーネルは LINUX カーネルですが、何のソフトウェアも動作しないことがわかります。これが、私がこの二つを一緒に語る理由です。LINUX には GLIBC と GCC がなければ、基本的には無用の長物です。
LINUX は現在、サーバー開発の事実上の標準となっており、CentOS8 との互換性もあります。これは商用サーバーの運用においては問題ありませんが、問題はこの愚かな連中が自分たちのコードをオープンソースにして他のオープンソースプロジェクトを圧迫し、ユーザーの心を占有して CentOS という船に縛り付けられていることです。
WINDOWS 標準: 文書化された標準はすべて良い標準です!
MAC 標準:ただのクソ、すべての議論を拒否します。
API: シェル?それは何の気持ち悪いものですか#
おお、神よ、本当にシェルを書くのが好きな人がいるのですか?シェルは本質的に一連の C プログラム(または libc)とオペレーティングシステムのインターフェースを接続し、非常に不器用な構文を提供します。
シェルが存在できるのは、UNIX の設計者たちがさまざまな C コードと接続するための良好な抽象を設計しなかったからであり、同時に C 言語の貧弱な意味論もこのシステムの複雑さを支えるには不十分です。
そして、現在のシェルは k8s の yaml の中で生き続けており、非常に恐ろしいです。
私の意見では、オペレーティングシステムの API の整然さから見ると、Windows は以前に DLL 地獄のような問題に直面したことがありますが、この点ではすべての * nix の設計を圧倒しています。API は本来、一般的な記述形式を使用すべきであり、Windows は現在、.net IL のような方法で生成されたインターフェースのさまざまな記述を使用し、Rust、C#、C++ などに成功裏に接続しています。ヘッダーのような愚かな形式やシェルのような拙劣なものを放棄しました。
セキュリティ#
オペレーティングシステムが C で書かれていなかったら、もう少し安全な言語を使用していたら、現在のセキュリティ問題の半分以上は存在しないでしょう。
-- 私の言葉
オペレーティングシステムのセキュリティ問題は、私の見解では C の無限の延命です。私たちはそれをウォーハンマーの魔法の世界観に持ち込むと、驚くほどの一致があります。
毎日千人のサイキック
優秀なプログラマー
を黄金の玉座さまざまなオペレーティングシステム
に連れて行き、皇帝C
に命を与え、犠牲にされたサイキックたちはこれを至高の栄光だと考え、かつて人類を栄光に導いた技術UNIX
は迷信の偶像に変わりました。混沌syscall
の力は至る所に存在し、無魂の虫族bug
は銀河全体を飲み込もうとしています。
まず、現在の CPU のハードウェア設計については触れず、リングの設計について話しましょう。#
リングは環状で、0 から N までの小さいほど高いレベルを持ち、リング 0 は一般的にカーネルの位置です。開発者は一般的に syscall を使用してリング 0 のものを呼び出します。リング 1、リング 2 は一般的にユーザーが触れないドライバの位置であり、リング 3 がユーザーのいる場所です。一見すると理にかなっているように思えますが、実際にはそれほど必要ではなく、同時にコンテキストスイッチのオーバーヘッドを増加させます。少しでも低レベルのものを書いたことがある人は、速くするためには syscall を減らすべきだと知っています。たとえば、mutex -> futex、vfs -> fuse、io -> spdk、私たちは常に自分たちが書いたものが絶対に安全であると信じており、速度を上げるためにこの設計を放棄し、一般的なものをすべてユーザースペースに持ち込んでいます。さて、リングの設計は時代遅れではないでしょうか?
より深く学んでいる人は、リング - 1 が仮想化に使われることを知っているかもしれません。
私は仮想化に反対ではありませんが、これにはリングが必要だと思います。それ以外は必要ありません。
システムコール(syscall)はどうなったのか#
次に、先ほど言及したシステムコールについて話しましょう。ここで ebpf を使ったことがある人がいるかどうかわかりませんが、もしそうなら、私の考えをすでに理解しているはずです。私は ebpf を使ったことがない人に主に紹介します。C 言語にはクロージャがないことを知っています。仮に C 言語にクロージャがあっても、プロセス間やメモリ空間を越えてリングを跨いで相互に渡すことはできません。だからこそ、カーネル内のものを呼び出すためにこのような拗れた syscall メカニズムが発明されたのです。さらに、syscall は一部の OS の中で POSIX 互換を行う必要があります。くそったれ、もし私が直接クロージャをオペレーティングシステムのカーネルに渡すことができたら(ebpf のバイナリのような)、オペレーティングシステムは安全性を検証し、コンパイルを通過した後にリング 0 で実行され、流行の pure async IO と組み合わさることができるでしょう。それは、手動で状態を保存し、スレッドが安全かどうかを気にする必要がない、より正常なプログラムのように見えるでしょう。
ファイルとは何ですか?#
私は毎日、00年代生まれ
が何がファイルか知らないと文句を言っているのを見ます。私は彼らに言いたいです、あなたはファイルが何か知っているのか?
私は大多数の人が自分はファイルが何かを知っていると思い込んでおり、私が反論するのも面倒なほど浅い回答を返してくると考えています。そして私の見解は、私たち00年代生まれがあなたたちの愚かな設計のために代償を払う必要があるのか?
です。
私たちは最も単純なファイルの定義に戻りましょう:A4 用紙です。目に見え、触れることができ、容量が限られています(限られたことしか書けません)。ファイルに名前を付けることができ、たとえばこの A4 用紙を「レモンの 8 月第 4 週の週報」と呼ぶことができますが、これはコンピュータ内のファイルと何の関係がありますか?
明らかに、最初はこの方向で抽象化されていましたが、現在ではあまり関係がないように見えます。現代のオペレーティングシステム内のファイルを説明する必要がある場合、私たちは... 試してみましょう。
Linux システムにおいて、ファイルはトイレのようなものです(明示的にフラッシュして流す)。あなたはそこに排泄することもでき、排泄物を下水道に流すこともできます。あなたはそこに残り物を捨てることができ、詰まらなければそれで良いのです。あなたはこのトイレの上でどれだけ長く座っても構いません。通常、トイレには一人しか座ることが許可されていません。トイレにはさまざまな形があるため、ファイルにもさまざまな形があります。たとえば、抽水式、木製の桶、村の汚水処理場などです。たとえば、tmpfs、rootfs、procfs があります。
したがって、これは私たちの A4 用紙モデルとは大きく異なります。したがって、私たちはファイルの概念を再度しっかりと抽象化する必要があります。たとえば、procfs です。
Linux のゴミオペレーティングシステムには procfs というものがあります。これは一連の動的なものを保存しており、通常は/proc
ディレクトリにあります。たとえば、/proc/cpuinfo
です。通常のファイルシステムは書き込み可能ですが、procfs は... 少し特別です。あなたはそれをトイレのように見ますが、実際に排泄すると、それが芸術作品であることに気づきます。
なぜ現在のファイルシステムはこんなに拗れた設計になっているのでしょうか?それは前述のシェルに起因しています。シェルは多くの場合、文字列処理言語であり、非文字列を処理する際には力不足になります。したがって、UNIX の人々はすべてはファイルであるという哲学を設計しました。さもなければ、万能の C + シェルはこのデータを処理できなくなります!
タイマー、シグナル、セマフォ、プロセス、ネットワークデバイス、ドライバ:ファイルは歌姫のようなものです!
たとえば、私たちが特定のオペレーティングシステムの情報を読み取ろうとするとき、API があるかどうかを考えますが、UNIX プログラマーはcat /proc/xxx | sed -i '.*aaa.*/bbbb/ | grep yyy
のようにします。したがって、これらは 20 世紀まで神聖視されていた大道至簡です。しかし、もしある情報がテキスト形式で存在しない場合... たとえば、ある有向グラフがあるとします。ああ、シェルは機能しませんが、有向グラフは現実の生活の中でテキストよりもはるかに多いのです。
ファイルシステムの実装#
先ほど VFS が非常に拗れたものであることを述べましたが、それはどのようにして拗れたのでしょうか?私が半日文句を言った procfs を完成させるために、VFS がオペレーティングシステムと拗れ合わなければ、cpuinfo のようなリング 0 だけが読み取る権限を持つものを読み取ることはできません。したがって、VFS はオペレーティングシステムに依存していますが、オペレーティングシステムはさまざまなシェルに依存し、シェルはさまざまな VFS に依存しています。したがって、これらの三つは互いに依存し合っており、リングを越えています。つまり、設計上、この一塊のものは非常に不安全です...
一部の熟練ユーザーは最近、SPDK や FUSE について話題になっていることを知っているかもしれません。なぜ FUSE のようなものがあるのでしょうか?VFS は不安全であるだけでなく、非常に安全であるふりをしなければなりません。たとえば、cat ~/.README.md
を実行すると、何が起こるでしょうか?
- ユーザースペースで open という関数を呼び出します。
- open は glibc でラップされた syscall です。
- カーネルに入り込みます。
- VFS を読み取ります。
- XFS を読み取ります。
- ブロックを読み取ります。
- IO リクエストを送信します。
- ハードディスクがバッファに読み込みます。
- IO 割り込みを発生させます。
- カーネルバッファにコピーします。
- ユーザーバッファにコピーします。
- 戻ります。
- 戻ります。
- 戻ります。
- カーネルを出ます。
- syscall を出てユーザースペースに戻ります。
- 文字列を取得します。
ああ、私たちは 2 回コピーしました。ああ、私たちは 2 回のコンテキストスイッチをしました。ああ、私たちは 3 つの何をしているかわからない抽象関数呼び出しをしました。ああ、私たちはいくつかのメモリマッピングを完了しました。ああ、私たちは無駄な文を取得しました。実際には、ステップ4 6 7 9 11 17
だけが私たちが関心を持つものであり、これらのステップには何のスイッチもユーザースペースの変更も必要ありません。したがって、FUSE はこれらのステップだけの FS 実装であると理解できます。
しかし、実際には FUSE システム内の VFS は、私たちが必要とするリソースの ID を担当しているだけです... したがって、現在RedoxOSはファイルを URL で扱うようになりました。
ちなみに、FUSE が登場した後、ファイルシステムは雨後の筍のように広がりました。なぜなら、複雑さが減少したからであり、誰もゴミのカーネルが何をしているのか気にせず、VFS に接続して自分たちの実装を行ったからです。
しかし、URL を使用することと VFS を適切に扱うことは、私にとって核心的な問題を解決したわけではありません。
ファイルは最初に何のために使われたのか?#
多くの人が直接「ファイルを保存するためだ!他に何がある?」と言うかもしれませんが、あなたたちは本当に間違っています。古代の人類は自分でソフトディスクのオフセットを書く能力を持っていました!
実際、最初は VFS とファイルがこのように設計されたのは、IPC の永続化を目的としていました。Microsoft の VFS はひどいものでしたが、彼らは COM インターフェースを正しく作成しました。
では、このすべてがファイルであるということは特に拗れているわけではなく、もっと刺激的なことはありますか?#
あります! PID PID(プロセスの ID 番号)は典型的な拗れた例です。これは、数字の名前を持つファイルを使用して実行中のプログラムを説明しようとしています。現実の生活では、これは明らかに病的な行動です。たとえば、今朝の食事中にスプーンを持ち上げたとき、私はそれを 3 と呼びます。
コンピュータの基礎がしっかりしているあなたは、この数字には上限があることを知っているはずです。たとえば、スプーンを持ち上げると 3、私が生きていると 5、呼吸すると 6 とします。これらのイベントの持続時間は非常に短いものから非常に長いものまであり、無限に列挙可能です。したがって、PID が割り当てられなくなると、0 から始めて空いているものを探します。ああ、もし私が 0 から 2^22 までをプロセスとして使用したら...
そうです、fork failed: Resource temporarily unavailable
もし私が 0 から 2^22 までをプロセスとして使用したら
このものを私たちはゾンビプロセスと呼びます。なぜなら、これは確かに無意味なものを説明していますが、プロセスを占有して死なないからです。
それがどう刺激的なのか?
なぜなら、私は PID がファイルであり、ファイルには現在開いているファイルを示す ID FD
があると言ったからです。ああ... しかし、これはプロセス内部に存在しています。しかし、この数値は面白いことに、IO を開くことが非常に一般的であるため、頻繁に変動します。ほとんどの IO は確かに非常に短命です。同時に、UNIX の哲学はすべてはファイルであるため、したがって、あなたがこの FD を取得した後、即座に操作を行うと、あなたの足に銃弾が飛んでくる可能性があります。
セキュリティ 2: 私たちはユーザーを完全に信頼する
と ユーザーは犬である
の重ね合わせ#
前の章で、私たちはファイルシステムがどれほど拗れた設計であるかを話しましたので、今度はすべてはファイルであるオペレーティングシステムのすべて
のセキュリティメカニズムについて展開できます。
Linux には非常にシンプルで愚かな権限システムがあります。ファイルには所有者があります。
先ほどの章を読んだ人は「え?!」と驚くでしょう。そうです、PID さえも所有者がいます。そして、所有者は 3 つの権限を設定できます。読み取り R、書き込み W、実行 X。この 3 つがすべて開いていると 7 になります。
R + W + X
4 + 2 + 1
最初の権限はユーザー、2 番目の権限はグループ、3 番目の権限はその他です。したがって、777 は最高の権限です。ボーイング 777 が飛んでいきました。
え?その他?そう... その他です。非常に漠然としているため、普通の人はそれを許可することを躊躇します。そして、あるアプリケーションがクラッシュして「権限がありません」と言います。あなたは「じゃあ、開けてみて」と言いますが、問題が発生します。小さくて美しいアプリケーションはあなたを狂ったようにスキャンします...
したがって、あなたは何を開くべきか全くわかりません。ユーザーとして、誰があなたのものにアクセスしているのかを知ることはできず、グループ内の特定のメンバーにアクセスを許可しないこともできず、彼をグループから追い出すこともできません(たとえば、video グループなど)...
したがって、先ほどのセキュリティ 1 ではユーザーは犬であり、今は完全にユーザーを信頼しています。まさに * n *ix の偽善です。
TOCTOU 問題(チェック時と使用時が一致しない)#
if (access("file", W_OK) != 0) {
exit(1);
}
symlink("/etc/passwd", "file");
int fd = open("file", O_WRONLY);
write(fd, buffer, sizeof(buffer));
ああ、私たちは/etc/passwd
の権限がなくても、書き込むことができました!
ここで、正しく行った Windows の小さな友達について言及する必要があります。#
Windows のファイルの権限はメタ情報に保存されています。このメタ情報には、Access Control List(アクセス制御リスト)と呼ばれるものがあり、さらに Mandatory Access Control(強制アクセス制御)があり、プロセス、スレッド、ファイル、ディレクトリ、ポート、メモリ、デバイスの権限を詳細に制御できます。また、Windows は 20 世紀の GUI を提供しています。
誰かが「Linux にも SELINUX がある」と言うかもしれませんが、あなたはそれを開けますか?問題が発生したら、あなたが背負うことになります。
Windows の NTFS には TxF(トランザクションシステム)があり、ある程度この TOCTOU 問題を回避できます(データベースでトランザクションの原子性の定義を学んだことがあるでしょうから、あの問題は発生しません)。しかし、Microsoft は使用を推奨していません。
レモンは、あなたたち OS の人々にデータベースを学ぶように勧めます。彼らはあなたたちよりも 2 世代先を行っています!#
IPC とソケットとネットワーク#
多くの初心者は、これら 3 つのものが何をするのか全く理解できないと思います。IPC はローカルの異なるプロセス間の相互作用に使用され、ソケットはローカルの IPC の一形態であり、他の人にアクセスすることもできます。ネットワークは他の人にアクセスすることです。
ああ、ここでも Linux を批判しなければなりません。Windows には COM と DLL のセットがあります。COM オブジェクトが登録されると、MSVC は直接 C++ で継承して IPC を実現できます。あなたはソケットに拗れているのか、dbus に拗れているのか、dbus の 3 つの実装はすべてユーザーモードであり、その結果、114514 回の情報コピーが遅くなります。そして、Android は「私はやらない、ゴミ dbus は遅すぎる」と言います。このようなものをカーネルに実装しない理由は何でしょうか?それで、Linux は一度のコピーで済む Binder を発明しました。
しかし、私はネットワークスタックのことを話すのは面倒なので、また別の機会に話しましょう。
IO の章#
信号キュー IO、死んでくれ、誰もお前を使わない
まず、この記事を読んでいる初心者に言っておきますが、ここでの IO は純粋なファイルだけでなく、すべての IO(ネットワークプリンターなど)を含みます。
現代の人々にとっては考慮すべき時期ではありません:ああ、IO とは何か、すぐに読み書きすればいいのです。メモリはそんなに小さくないのに、何を割り当てる必要があるのでしょうか?遅ければ待てばいいのです。
まず、私たちは Linux 2 の時代のselect
とpoll
の 2 つの兄弟に目を向けましょう... これは笑いを取るために生まれたものです!
私たちはすべての IO を for し、すべての IO に対して毎回 select/poll を呼び出し、すべての fd をユーザーモードからカーネルモードにコピーし、待ち続けます。あなたのコンピュータはまるでフリーズしたかのように見えます!
syslet/LCA:本当にこんな小道具の実装を使っている人はいますか?
Linux AIO#
- AIO: 私たちは Linux で非同期 IO をサポートしました!
- ユーザー:非同期 IO を使用して、すべてはファイルの特性を持つソケットを操作したいです。
- AIO: どけ!誰があなたを甘やかすのか!
そして AIO は批判されました!
無数のクソエンジニアの努力の下で...Linus 本人がいくつかの小さな見解を発表しました。
だから、私はこれが非常に醜いと思います。AIO はひどいアドホックデザインであり、主な言い訳は「他の、あまり才能のない人々がそのデザインを作ったので、私たちは互換性のためにそれを実装しています。データベースの人々は、ほとんど味のない人々なので、実際にそれを使用しています」。
— Linus Torvalds
うわ、これは本当に気持ち悪い!AIO は恐ろしいおもちゃであり、その主な言い訳は「このデザインは素人が提案したもので、データベースの人々に合わせるために実装せざるを得なかった。これらのデータベースの人々は、本当に品がない、こんなクソを飲み込むなんて!」。
— ライナス・トーバルズ(誠実なレモンの良心的翻訳)
設計に時間をかけた結果、O_DIRECT
、つまりキャッシュを越えて直接アクセスするファイルにのみ有用であることがわかりました。これはほぼデータベースのために設計されたカーネル内のクソであり、このクソは非同期に見え、さまざまなトリックでそれをブロックすることができます!わあ!
epoll と kqueue、私たちは epoll を除外することにしましょう。epoll は宿題をコピーすることさえできる kqueue を確かに抄襲していますが、私はこれを通知メカニズムのように感じますので、先に進めることはしません。
io_uring(uring: 尿)が登場!#
ああ、Linux コミュニティはついに BSD を名実ともに圧倒することができました (隣の Windows の IOCP は何年経っていますか?)
これについては、他の人の記事を見てください。現時点では、これがなんとかなると思います。唯一の問題は、いつすべてはファイルの設計を放棄するかということです。
*nix の人々の UI に対するセンス#
2022 年です!お願いです、アプリケーション開発者は GUI を使用してください。もうクソ CLI を書くのはやめてください!おじいさん世代のコンピュータは、技術が不足しているため GUI をサポートできませんでしたが、あなたは父親世代の Smalltalk や LISP マシンが GUI を第一に置いていたことを見ているでしょう?あなたは何を言っていますか?組み合わせ性?タイピングが速い?ああ、それは GUI を使わない理由ではなく、開発者がショートカットを提供するのが面倒なだけです。
GUI の設計については、私の見解を別の記事で詳しく話すことができると思います。
まとめ#
もし OS が金を生み出せなければ、あなたは DB のような利益を生み出すことができるなら、OS の人々はすでに無数の世代を革新していたでしょう。