亲爱的 KV,
我一直在两个相关但分歧的开源项目之间移植一些代码。我正在移植到的项目是多年前从另一个项目分支出来的,而且似乎 API 的名称已经更改,没有人跟踪另一个项目中正在发生的事情。这导致了完全相同类型的功能的 API 具有不同的名称,即使它们的功能是相同的。您可以想象,这真是令人恼火,这意味着“移植”的第一部分更像是从一个名称到另一个名称的机械翻译。我可以理解在秘密开发的专有软件中发生这种情况,但这两个项目都是公开开发的,有长期的邮件列表和公共存储库。肯定有更好的方法。
移植分叉路径
亲爱的 PPP,
我看到您已经陷入了我们在构建软件时都会陷入的常见陷阱:我们假设问题不在于人,并且一切都有一个漂亮的、整洁的技术解决方案。唉,事实并非如此。事实上,在开源中——甚至比在企业开发中更甚,在企业开发中,人们可以使用金钱的胡萝卜和大炮发射人员的棍棒(KV 最喜欢的解雇方式)——人们可以 просто 说“Fork you(分支你)”,然后各走各的路。
开源项目中经常因为个人分歧而产生分支,当然,这些分歧总是用技术术语来掩饰。Alice 认为她正在以比 Bob 更好、更强大、更快速的方式设计或实现软件,当然,Bob 认为他做得更好。因此他们分道扬镳,并分叉。
现在,有时分支就像离婚一样,既混乱又有时是友好的,但任何经历过分手的人都知道,即使是最友好的分手,通常也会经历一段冷静期。即使你们同意“做朋友”,你们也不会在一段时间内联系或见面。软件中的分支也是如此。
因此,我们得到了软件漂移。Alice 添加了一个功能,但没有告诉 Bob,她为什么要告诉 Bob 呢?Bob 可以像其他任何人一样阅读邮件列表,并且存储库是开放的。Alice 为什么要告诉 Bob 任何事情?当然,Bob 也有同样的感觉。因此,代码库现在开始分道扬镳,缓慢或快速,但不可避免且无法挽回。
由于这些系统有一个共同的父项,它们可能在相同的技术领域工作,因此将要添加的功能和修复程序可能类似。KV 碰巧手头有一个示例案例:两个操作系统在添加 SMP(对称多处理)支持之前就分道扬镳了。当操作系统向现有内核添加 SMP 时,我们首先想到的是锁,那些方便的小型性能杀手,自从 Dennard 缩放定律结束以来,我们一直在我们的代码中到处洒洒。
锁有很多类型——只需查看任何操作系统教科书——但其中最基本的是互斥锁。您可能会认为这种非常简单的锁类型会有一个非常简单的 API,一个系统可以轻松地从另一个系统复制。当它们表达的是相同的东西时,为什么要使 API 不同呢?我不知道。问问 Bob 和 Alice,因为您可以在这里看到他们所做的
Alice 的互斥锁
void
mtx_init(struct mtx *mutex, const char *name, const char *type, int opts);
void
mtx_destroy(struct mtx *mutex);
void
mtx_lock(struct mtx *mutex);
void
mtx_unlock(struct mtx *mutex);
Bob 的互斥锁
void
mutex_init(kmutex_t *mtx, kmutex_type_t type, int ipl);
void
mutex_destroy(kmutex_t *mtx);
void
mutex_enter(kmutex_t *mtx);
void
mutex_exit(kmutex_t *mtx);
我甚至不会深入探讨“谁先到那里?”这个问题,但无论谁先到那里,或许,可能,Alice 和 Bob 合作并为 API 使用相似的名称可能是一个好主意。具有讽刺意味的是——等等,不是讽刺,而是令人愤怒——所有这一切,甚至这里列出的四个 API 中三个的参数列表都是相同的。
现在,就因为我们玩得这么开心,让我们比较一下各个手册页对这些函数的说明
mtx_lock()
函数代表当前正在运行的内核线程获取 MTX_DEF
互斥锁。如果另一个内核线程持有互斥锁,则调用者将与 CPU 断开连接,直到互斥锁可用(即,它将阻塞)。
获取互斥锁。如果互斥锁已被持有,则调用者将阻塞,直到获取互斥锁才返回。
我本打算重新排列这些语句,使其更难猜测哪一行来自哪个系统,但今晚我感觉稍微有点仁慈,喝了一杯双份 Vesper,并将它们保持了匹配的顺序。
“啊,但是等等!” 我听到你喊道。“也许 Alice 的互斥锁比 Bob 的更好!” 反之亦然。底层的性能特征实际上并不重要。我们正在谈论记住同一事物的两个名称的语义负担,谁想要在整个代码库中散布额外的认知负担呢?KV 不想!如果玫瑰换个名字闻起来仍然一样香甜,那么互斥锁换个名字仍然是一个基本的锁定原语,不需要命名两次。
更糟糕的是,同一个代码库的第三个分支也有自己唯一命名的一组互斥锁函数,但现在太晚了,我不想再将更多烦人的代码复制粘贴到这个缓冲区中。我只想告诫所有读者在编码之前要三思而后行,不要用九十亿个名称来淹没世界,无论是互斥锁还是任何其他 API。
KV
George V. Neville-Neil 为乐趣和利润从事网络和操作系统代码的工作。他还教授有关编程各个主题的课程。他的兴趣领域是计算机安全、操作系统、网络、时间协议以及大型代码库的维护和管理。他是 The Kollected Kode Vicious 的作者,并与 Marshall Kirk McKusick 和 Robert N. M. Watson 合著了 The Design and Implementation of the FreeBSD Operating System(《FreeBSD 操作系统设计与实现》)。近 20 年来,他一直是以 Kode Vicious 而闻名的专栏作家。自 2014 年以来,他一直是剑桥大学的工业访问学者,在那里他参与了多个与计算机安全相关的项目。他获得了马萨诸塞州波士顿东北大学的计算机科学学士学位,并且是 、Usenix 协会和 IEEE 的成员。他的软件不仅在地球上运行,而且还作为 VxWorks 的一部分部署在 NASA 的火星任务中。他是一位狂热的自行车爱好者和旅行者,目前居住在纽约市。
版权所有 © 2024 归所有者/作者所有。出版权已授权给 。
最初发表于 Queue 第 22 卷,第 1 期—
在 数字图书馆 中评论本文
Amanda Casari, Julia Ferraioli, Juniper Lovato - 超越存储库
关于开源的现有研究大多选择研究软件存储库而不是生态系统。开源存储库最常指版本控制系统中记录的工件,偶尔包括围绕存储库本身的交互。开源生态系统指的是存储库的集合、社区、它们的交互、激励机制、行为规范和文化。开源的去中心化性质使得对生态系统进行整体分析成为一项艰巨的任务,社区和身份以有机和不断发展的方式相互交叉。尽管存在这些复杂性,但对软件安全和供应链日益增加的审查使得在执行关于开源的研究时采取基于生态系统的方法至关重要。
Guenever Aldrich, Danny Tsang, Jason McKenney - 给那些还不明白的项目经理的三部曲
本文探讨了系统采购工具箱中的三种工具,它们可以加速开发和采购,同时降低项目风险:OSS、开放标准和 Agile/Scrum 软件开发流程都是 DoD 采购项目管理工具箱的强大补充。
Jessie Frazelle - 开源固件
开源固件可以通过使固件的操作更加可见且不太可能造成危害,从而帮助将计算带到一个更安全的地方。本文的目标是使读者感到有权要求供应商提供更多帮助,以推动这种改变。
Marshall Kirk McKusick, George V. Neville-Neil - FreeBSD 5.2 中的线程调度
繁忙的系统每秒会做出数千个调度决策,因此做出调度决策的速度对于整个系统的性能至关重要。本文 - 摘自即将出版的书籍《FreeBSD 操作系统设计与实现》 - 使用开源 FreeBSD 系统的示例来帮助我们理解线程调度。最初的 FreeBSD 调度程序是在 20 世纪 80 年代为大型单处理器系统设计的。尽管它今天在那种环境中仍然运行良好,但新的 ULE 调度程序是专门为优化多处理器和多线程环境而设计的。本文首先研究了原始的 FreeBSD 调度程序,然后描述了新的 ULE 调度程序。