LemonHX

LemonHX

CEO of Limit-LAB 喜欢鼓捣底层的代码,意图改变世界
twitter
tg_channel

我對OS的理解

what-is-operating-system.jpg

被噴的對象集

這篇文章或許看起來戾氣太重,所以我不推薦任何中老年人觀看, 同時假如這篇文章所提及的有你不認同的部分,請評論我,並告訴我詳細的原因謝謝~。

什麼是操作系統#

用於處理人與硬體交互的軟體 這是我對操作系統的定義,操作系統和 IE 瀏覽器一樣都是軟體,他們有比爛的可能性。

一般情況下操作系統都具備一個在不同的硬體上都表現得差不多的這麼一個行為,但這不是必須的 其實我並不是很 care 相容性,但是隔離硬體細節統一軟體介面還是對於開發者而言能讓自己的軟體 port 到更多的平台確實是不錯的一件事。

現在操作系統陣營#

遠古陣營不具備現實意義,solaris 也就剩下個 zfs unix 已經死了 minix... 永遠活在教科書裡

操作系統一般都有標準,我們現在有三個標準

  • POSIX 標準
  • GNU/LINUX 事實標準
  • WINDOWS/MAC/ 其他 自己玩標準

首先我們說說 POSIX 是什麼東西,我覺得 POSIX 就是為了讓 原來老舊的 UNIX 上的軟體得以遷移到新的平台,在我看來就是 UNIX 操作系統的歷史包袱強迫大家去遵守的一個標準。

所以 POSIX 標準就是比爛,對於這個我沒有什麼好說的, 而且事實上大家都是部分相容,這個可比完全相容嚇人多了。

然後我們再說說 LINUX, 其實 LINUX 本身的程式碼寫的已經夠意大利麵了, 但是如果拋開 GNU 不談,userland 使用 FreeBSD 所提供的那一套環境, 你會發現你的核心是 LINUX 核心,但什麼軟體都運行不了,這就是為什麼 我把他們兩個綁在一起說的原因,LINUX 沒有 GLIBC 和 GCC 基本就是一個鐵廢物。

LINUX 現在已經成了伺服器開發的事實標準,甚至再具象化一點 CentOS8 相容, 這個其實也無可厚非,反正商用伺服器運維自己的就行了,但是操蛋就操蛋再這群傻逼 開源了自己的程式碼擠死了其他開源專案然後佔據了用戶的心智從而被迫被綁定在 Cent 這條船上。

WINDOWS 標準: 有文檔的標準都是好標準!

MAC 標準:就是糞,拒絕一切討論。

API: Shell? 那是什麼惡心東西#

哦我的上帝,真的有人喜歡寫 shell 嘛? shell 本質上是對一堆 C 程式 (或者說 libc) 還有操作系統的 interface 接在一起,提供了一個非常別扭的語法。

shell 之所以能夠存在就是因為 UNIX 的設計者那一幫人並沒有動腦子設計出一個良好的抽象去對接各種各樣的 C 程式 同時 C 語言的貧瘠的語義也不足以支持這個系統的複雜度

然後我們就看到現在的 shell 活在了他媽的 k8s 的 yaml 裡,非常的嚇人。

私以為操作系統的 API 的整潔度來看 Windows 雖然之前有會碰到 DLL 地獄這種東西,但是這一點上來確實吊打了所有 * nix 的設計。 API 本應該使用一種通用的描述格式,Windows 現在使用的是類似.net IL 的方式去生成的介面的各種描述,然後成功的 對接到了諸如 Rust,C#,C++ 之類的,拋棄了 header 那種蠢驢格式還有 shell 這種蹩腳玩意兒。

安全#

如果操作系統不使用 C 寫,而是使用一個稍微安全一點點的語言,那麼現在一半以上的安全問題都不復存在

-- 我說的

操作系統的安全問題在我看來就是為 C 進行無限續命,我們把它帶入到戰鎚的魔怔世界觀裡居然有一絲吻合

每天把千個靈能者 優秀的程式員 帶到黃金王座 各種操作系統 給帝皇 C 續命,而那些被獻祭的靈能者都認為這是一種無上的光榮,曾經將引導人類走向輝煌的科技 UNIX 變成了迷信的偶像。混沌 syscall 的力量無處不在,無魂的蟲族 bug 妄圖吞噬掉整個銀河。

首先我們先不談現在 CPU 的硬體設計,先談談 ring 的設計#

ring 就是一個環,從 0-N 越小等級越高,ring 0 在一般情況下是核心的位置,然後我們開發者一般用 syscall 去調用 ring 0 的東西,ring 1 ring 2 一般是不希望用戶碰的驅動的位置,ring 3 才是用戶在的地方,乍聽起來好像有點道理,可是事實上現在看起來並沒有那麼必要而且同時還增加了 context switch 的開銷,相信稍微寫過點底層的東西的人都知道要想快就減少 syscall,打個比方 mutex -> futex, vfs -> fuse, io -> spdk, 我們總是知道我們寫的東西絕對的安全,從而為了增加速度,我們放棄了這個設計,全部把常見的東西都拉到了 user space,那麼...ring 這個設計是不是該過時了?

有一些學的更深入的人可能會想說 欸你看 ring -1 不是用來做虛擬化嘛?

我不反感虛擬化,我就認為可能就這個東西需要 ring 包一下,剩下的沒必要。

系統調用(syscall)咋了#

另外我們再說下我們剛才提到的系統調用,不知道這裡有沒有玩過 ebpf 的人,如果有,那麼你應該已經知道我的思想了,我主要介紹給沒有玩過 ebpf 的人。 我們知道 C 語言沒有閉包,假如 C 語言有閉包也不能夠跨進程甚至跨內存空間跨 ring 相互傳遞,所以才發明了這麼一套拧巴的 syscall 機制用來調用內核裡面的東西,甚至 syscall 在一群 OS 裡面還要做什麼 POSIX 相容,我可去你媽的吧,假如我能夠直接寫一個閉包傳遞給操作系統的內核(ebpf 的二進制那種)操作系統進行安全驗證並編譯通過後直接在 ring0 運行在搭配上潮流的 pure async IO,那才看起來更像是正常人寫的程式而不是說手動保存一堆狀態還得記線程安不安全之類的。

什麼是文件?#

我成天看到有人吐槽 00後居然不知道什麼是文件 我想嘴他們 你就知道什麼是文件了? 我想絕大多數人自以為知道什麼是文件,然後給了我一個膚淺到我懶得反駁他們的回答, 而我本人的觀點是: 我們00後為什麼要為你們的傻逼設計來買單?

我們回歸最樸素的文件定義:一張 A4 紙,它看得見摸得著容量有限 (你只能寫有限的東西),你可以給文件取名比如這個 A4 紙叫《檸檬的 8 月份第四週週報》 但這跟計算機裡面的文件有什麼關係嗎?

很顯然最一開始的時候我們就是按照這個方向去抽象的,然而現在好像看起來確實沒有太大的關係了,如果要描述一個現代操作系統裡的文件,我們... 嘗試描述一下

在 linux 系統中文件就是一個馬桶 (明示 flush 沖水) 你可以往裡拉屎也可以把屎沖進下水道,你可以往裡面倒剩菜剩飯只要它不堵塞就行 你在這個馬桶上想蹲多久蹲多久,正常情況下馬桶上只允許有一個人拉屎 馬桶有很多種形式,所以文件也有很多種形式,比如抽水的,木桶的,還有村裡的化糞池等,打個比方你有 tmpfs,你有 rootfs,你有 procfs

所以這其實跟我們的 A4 紙模型相去甚遠,所以我覺得我們必須重新好好抽象一下文件的概念了,打個比方: procfs

在 linux 的垃圾操作系統裡,有個東西叫 procfs,這個東西存放了一堆動態的玩意兒,且通常放在 /proc 目錄下如 /proc/cpuinfo 我們知道正常的 fs 都是可以寫的,而 procfs... 有那麼一點點特殊,你看著它是一個馬桶,當你真的拉屎的時候才發現它居然是一個藝術品。

為什麼現在的 fs 會設計的這麼拧巴? 因為前面我們提到的 shell,shell 更多情況下它是一個字串處理語言,而處理非字串的時候就變得力不從心, 所以 unix 這幫人會設計出一切皆文件的哲學,因為要不然萬能的 C+Shell 就不能處理這個數據了!

計時器,信號,信號量,進程,網路設備,驅動:文件就是歌姬吧!

打個比方我們正常人想去讀到某個操作系統的信息的時候會想有沒有什麼 API,而 unix 程式員喜歡 cat /proc/xxx | sed -i '.*aaa.*/bbbb/ | grep yyy 所以這些到上個世紀為止都被奉為神聖的大道至簡,但是假如有一天有一個信息它並不是以文本的形式存在的... 比如某個有向圖,哦 shell 不行了 可是有向圖可比文本在現實生活中多太多了

文件系統的實現#

剛剛我們說到 VFS 這個東西很拧巴,那麼它是怎麼拧出來的呢? 為了完成我吐槽了半天的 procfs,我們發現如果這個 VFS 不跟操作系統拧巴在一起我們是無法讀取類似 cpuinfo 這種 ring 0 才有權限讀到的東西的, 所以說 VFS 依賴操作系統,但是操作系統依賴各種 shell,shell 又依賴各種 VFS 所以這三個構成了互依賴還是跨 ring 的,也就是說從設計上來講, 這一坨東西其實就已經非常的不安全了...

有些資深用戶應該知道最近大家都在卷什麼 SPDK 或者 FUSE,為什麼會有 FUSE 這種東西,因為 VFS 啊他不安全就算了,他還要假裝他很安全, 假如我們執行 cat ~/.README.md 時會發生什麼呢?

  1. 在 user space 呼叫一個叫 open 的函數
  2. open 是一個 glibc 包裝的 syscall
  3. 陷入內核
  4. 讀 VFS
  5. 讀 XFS
  6. 讀 block
  7. 發起 IO 請求
  8. 硬碟讀進緩衝區
  9. 發起 IO 中斷
  10. 拷貝到內核緩衝區
  11. 拷貝到用戶緩衝區
  12. 返回
  13. 返回
  14. 返回
  15. 出內核
  16. 出 syscall 切回 user space
  17. 拿到字串

哦,我們 tmd 拷貝了兩次,哦我們他媽的有兩次 context switch,哦我們有三個不知道在幹什麼的抽象函數調用,哦我們還完成了好幾次內存映射,哦我們拿到了一個廢文 事實上只有步驟4 6 7 9 11 17 是我們關心的,這幾個步驟並不需要任何什麼 switch 什麼換 user space,那麼我們可以理解為 FUSE 就是只有這幾個步驟的 FS 實現

但你有沒有發現其實 VFS 在 FUSE 系統裡只負責對我們要的這個資源擔當 ID... 所以說現在 RedoxOS 已經把文件使用 URL 來做了。

順便一提有了 FUSE 之後文件系統如雨後春筍般遍地開花,因為複雜度降低了,沒人再鳥垃圾核心在幹啥都把他接到 VFS 自己實現去了。

不過拿 URL 做和那 VFS 做好像對我來講並沒有解決核心問題

文件一開始用來幹什麼的?#

很多人可能會直接說 存儲文件啊!還能幹什麼?! 那你們真的錯了,遠古時期的人類有算 offset 自己寫軟碟的實力!

其實啊一開始 VFS 和文件這麼設計就是因為想給 IPC 做持久化 雖然微軟的 VFS 做了個狗屁可是人家好歹是做對了 COM 介面

那你說這個一切皆文件我看下來也不是特別拧巴,還有更刺激的嗎?!#

有! PID PID (進程的身份證號) 是一個典型的拧巴的例子,他嘗試用一個名字是數字的文件去描述一個正在跑的程式 放在現實生活中這真是妥妥的有病的行為,就好比說我今天早上吃飯舉起了我的勺子我管他叫 3

作為計算機功底很好的你應該知道這個數字是有上限的,假設我舉勺子算 3,我活著算 5,我呼吸算 6,你會發現這些事件的持續時間從很短到很長都有包括,而且 是可以被無限列舉的,那麼當 PID 分配完之後就從 0 開始找有沒有已經空閒出來的,哦,那假如從 0 到 2^22 次方我都用我活著作為進程,那...

沒錯,fork failed: Resource temporarily unavailable

那假如從 0 到 2^22 次方我都用我活著作為進程

這東西我們叫殭屍進程因為他確實描述了個狗屁,但是他就是佔著一個進程還死不掉

那這個怎麼刺激了?

因為我說了一個 PID 是一個文件,文件也有個身份證表示當前打開的文件 FD, 哦... 但好歹這東西是活在進程內部的,不過這東西的數值有趣就有趣在這個數值真的經常變動因為打開 IO 這件事情太過常見,絕大多數 IO 活的確實夠短,同時 unix 的哲學是一切皆文件, 於是你拿到這個 FD 之後當場進行操作都可能給你的腳來一槍。

安全 2: 我們完全相信用戶用戶是狗的疊加態#

書接上文,我們聊完了 FS 這個東西是多拧巴的設計,那麼我們現在可以展開說說 一切皆文件的操作系統的一切的安全機制了

Linux 裡有一套非常簡單且智障的權限系統 文件有所有者

看完剛才那一章的人會發出 啊?! 啊?!的聲音, 沒錯,就連什麼 PID 都有所有者,然後所有者可以設定三個權限,讀 R 寫 W 執行 X 這三個都開就是 7

R + W + X
4 + 2 + 1

第一個權限是 User 第二個權限是 Group 第三個權限是 Other 所以 777 就是最高的權限 波音 777 飛了過去

啊?! Other?對...Other,這麼籠統,以至於正常人都不敢給,然後一個應用炸了 說沒有權限,然後你開開了吧... 問題來了,小而美這種應用會瘋狂掃你...

所以你根本不知道开什么好,你作為用戶不知道誰在哪兒訪問了你這個東西,你也不能讓組裡某個特定成員不訪問,也不能把他踢出組 (如 video 組這種)...

所以剛才的安全 1 用戶是狗,現在又完全相信用戶了,不愧是當婊子立牌坊的 * nix。

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 還提供了一個上個世紀的 GUI

有人可能會說啊你看 linux 也有 SELINUX 你敢開嘛?出了鍋你背就行

windows 的 ntfs 裡面有 TxF(事務系統),可以某些程度上避免這個 TOCTOU 問題(學過數據庫知道啥是 transaction 的 Atomic 定義吧,所以不可能出現剛才那個問題) 但是微軟不建議使用

檸檬建議你們這群 OS 人趕緊學學數據庫吧,比你們領先了兩代了都!#

IPC 和 Socket 和 Net#

相信很多新手根本理不清楚這三個東西是幹啥的,IPC 是本機不同進程用來交互的的,Socket 可以是本機的 IPC 的一種形式,同時還能訪問別人,Net 是訪問別人的。

哦這裡又得噴 linux 了,你看看人家 Windows 有一套 COM 有一套 DLL,COM Object 註冊完成之後 MSVC 直接寫 C 艹繼承一下就能完成 IPC,你看看你拧巴到 socket 不行 dbus 行不行,dbus 三個實現還 tmd 用戶態,結果就是 114514 次拷貝信息慢的要死,然後安卓表示我不幹了,垃圾 dbus,太他媽慢,這種東西你幹嘛不做進 kernel,於是發明了 linux 看了眼馋的單次拷貝的 binder。

可是我又懶得展開說網路棧的事情,因為真的心力交瘁,改天單獨聊聊吧。

IO 篇章#

信號隊列 IO 你給我死一死,沒人用你

先跟看這篇文章的小白說一下這裡的 IO 指的不是純文件而是所有的 IO 如網路打印機啥的都算

對於現代人已經不可以考究的時期:哎呀不就是 IO 嘛,當場讀當場寫拉,內存辣麼小分配啥呀,慢就等等就行了嘛~

首先我們把目光拉回到 Linux 2 的時代的 selectpoll 這兩個哥們兒... 就是為了搞笑而生的!

我們 for 一下所有 IO,然後對所有的 IO 每次調用一下 select/poll, 然後把所有的 fd 從用戶態拷貝到到內核態,然後等呀等,等呀等,等呀等,你的電腦就像死機了一樣欸~!

syslet/LCA : 正經人有在用這麼小丑的實現嗎?

Linux AIO#

  • AIO: 我們 Linux 支持了異步 IO 了!
  • 用戶:想使用異步 IO 和一切皆文件的特性操作一個 socket~
  • AIO: 滾!誰慣著你!

然後 AIO 就被噴爆了!

在無數個堆屎工程師的辛勤勞動下...Linus 本人發表了一些小小的看法

So I think this is ridiculously ugly. AIO is a horrible ad-hoc design, with the main excuse being “other, less gifted people, made that design, and we are implementing it for compatibility because database people — who seldom have any shred of taste — actually use it”.

— Linus Torvalds

呕,這太 TM 惡心了! AIO 是一種嚇人的的玩具,其主要借口是 “這個設計是菜雞提的,因為我們要相容數據庫人所以不得不實現這坨玩意兒,這些數據庫人啊他們真的很沒品居然咽的下這口屎!”。

— 萊納斯・托瓦茲 (實誠檸檬良心翻譯)

因為設計了半天,只對O_DIRECT 也就是真的直接訪問越過了 cache 的文件是有用的,這幾乎就是說為數據庫量身打造的一坨在內核裡的屎,然後這坨屎看起來是異步的還可以用很多奇技淫巧阻塞它!哇!

epoll 和 kqueue , 我們把 epoll 開除了算了,epoll 抄作業都能抄爛 kqueue 這種確實是 async 但是我覺得更像是一種通知機制,所以先不做討論

io_uring (uring: 尿)橫空出世!#

哦,linux 社區終於可以名正言順的壓 BSD 一頭了 (隔壁 windows 的 IOCP 都多少年了?)

這個怎麼樣你們去看別人的文章吧,到目前為止我覺得這個才湊合,唯一的問題在於什麼時候我們放棄一切皆文件設計吧

*nix 人對 UI 的品味#

2022 年了!拜託應用開發者請使用 GUI,別 tmd 寫一堆 cli 了! 爺爺輩兒的電腦是因為水平太拉,根本不足以支撐 GUI 所以沒用,但你看爸爸輩兒的 Smalltalk 和 LISP machine 不都是 GUI 放在第一位的嘛?你說什麼可組合性?你說什麼打字更快,哦,那不是不用 GUI 的理由,而是開發者懶得提供快捷方法。

關於 GUI 怎麼設計我想我的觀點可以再開一個文章單獨聊聊

總結#

要不是 OS 賣不了錢卷不起來你看看如果能創造 DB 那樣的收益 OS 人早就革新了無數代了

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。