我对OS的理解
被喷的对象集

这篇文章或许看起来戾气太重,所以我不推荐任何中老年人观看, 同时假如这篇文章所提及的有你不认同的部分,请评论我,并告诉我详细的原因谢谢~。

什么是操作系统

用于处理人于硬件交互的软件 这是我对操作系统的定义,操作系统和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的时代的 select 和 poll 这两个哥们儿…就是为了搞笑而生的!

我们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人早就革新了无数代了

评论

  1. luoqeng
    3周前
    2022-9-02 12:02:23

    Fuchsia 怎么样?

    • 博主
      luoqeng
      3周前
      2022-9-02 12:02:56

      还凑合但没仔细看

发送评论 编辑评论


|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇