Loading...
Loading...
Loading...
Loading...
版权所有 © 1995-2023 The FreeBSD Documentation Project
摘要
这是 FreeBSD 的常见问题解答(FAQ)。我们已尽一切努力使此 FAQ 尽可能信息丰富。
欢迎来到 FreeBSD 的世界!在本部分中,我们提供了 FreeBSD 是什么、其起源、目标、用例以及支持它的社区的综合概述。
探索其名称背后的原因,了解如何为该项目做贡献,并在开源操作系统的背景下探索 FreeBSD 丰富的生态系统。
FreeBSD 是一款多才多艺的开源类 UNIX® 操作系统,以其出色的稳定性、安全性和性能而闻名。由一群热心的志愿者社区开发,它基于伯克利软件发行版(BSD)UNIX 操作系统。
FreeBSD 提供了一个功能强大且可定制的环境,适用于各种应用,从服务器和嵌入式系统到桌面和网络设备。其对开源原则的承诺确保了一个透明和协作的开发过程,使 FreeBSD 成为那些寻求可靠且高度适应性操作系统的可信选择。
名称“FreeBSD”源自它在伯克利软件发行(BSD)UNIX 操作系统中的根源,该操作系统以其在开源软件世界中的贡献而闻名。“Free”中的“自由”代表了其对自由和开源软件原则的承诺,这些原则赋予用户研究、修改和分发代码的自由。
值得指出的是,这里使用了“Free”一词两种不同的含义:一种是指“没花费”,另一种是指“随你喜欢做任何事情”。
FreeBSD 项目有一个明确而坚定的目标:提供一个在性能、安全性和稳定性方面表现卓越的高质量、开源的类 UNIX 操作系统。
它旨在提供一个多功能平台,适用于各种计算需求,从服务器和工作站到嵌入式系统等各种领域。FreeBSD 秉承开源原则,致力于打造一个协作环境,在这里来自全球开发者社区的贡献帮助塑造和完善操作系统。这种对质量、自由和可靠性的承诺是 FreeBSD 的独特之处,也推动着它作为开源项目不断取得成功。
FreeBSD 是一个多功能操作系统,在各种使用场景中表现出色。它特别适用于服务器环境,在那里其稳定性和性能使其成为 Web 托管、数据库和网络应用的热门选择。FreeBSD 强大的安全功能也使其成为防火墙和安全设备部署的强有力候选。除了服务器,FreeBSD 还可以定制以在专业环境中运行,包括嵌入式系统和游戏主机设备。其适应性、可靠性和开源特性使 FreeBSD 成为各种计算需求的引人选择。
FreeBSD 是一个以社区驱动的开源项目,具有分散的结构。它的开发和维护是由全球一群奉献的志愿者、开发人员和组织共同合作来增强和扩展这个操作系统。
有关 FreeBSD 项目的关键决定,如项目的总体方向或谁被允许向源代码树添加代码,是由一个由九个人组成的选举产生的核心团队做出的。
这种协作和社区驱动的方式对于 FreeBSD 作为可靠且强大的类 UNIX 操作系统的成功和长期发展至关重要。
我们接受各种类型的贡献:文档、代码,甚至艺术作品。请参阅有关如何进行贡献的文章,以获取具体建议。
并感谢您的想法!
FreeBSD 基于 BSD 许可证发布,以其宽松性著称。
此许可证对您如何使用 FreeBSD 几乎没有任何限制:
不要声称您编写了此内容。
如果出现故障,请不要起诉我们。
不要删除或修改许可证。
许可证意味着您可以自由修改、分发甚至出售 FreeBSD,而无需将您的修改作为开源发布。但是,在分发 FreeBSD 时,仍需保留原始版权声明和免责声明等一些最低限度的条件。总体而言,BSD 许可证提供了高度的自由和灵活性,使 FreeBSD 成为各种应用和项目的吸引人选择。
我们源代码树中受 GNU 通用公共许可证(GPL)或 GNU 库通用公共许可证(LGPL)约束的代码,虽然在强制访问方面略微受限,但至少不同于通常的相反情况。
对于许多用户和管理员来说,是的。但这个问题并不是那么简单明了。
FreeBSD 是一个强大而多才多艺的操作系统,可以取代或与许多其他操作系统共存,这取决于用户和管理员的特定需求。然而,FreeBSD 能否取代您当前的操作系统取决于诸如您的硬件、软件需求和对 FreeBSD 的熟悉程度等因素。
尽管它提供了一个强大且功能丰富的替代方案,但在转换之前,评估您的特定用例和兼容性要求是至关重要的。
如果一个应用程序只在一个操作系统上可用,那么该操作系统不能被替换。
从另一个类 UNIX 环境迁移到 FreeBSD 的用户会发现 FreeBSD 很相似。像 Windows® 用户这样的非 UNIX 用户应该准备投入一些额外的时间来了解 UNIX 的运作方式。
是的,FreeBSD 非常适合运行流行的开源软件。其与各种应用程序和库的兼容性使其成为那些希望部署和使用开源软件包的人的首选。FreeBSD 提供了一个强大稳定的环境,支持各种编程语言、数据库、Web 服务器和其他在开源社区中常用的软件。其 ports 和软件包系统简化了这些软件的安装和管理,确保用户可以轻松访问并在 FreeBSD 上运行他们喜爱的开源工具和应用程序,减少麻烦。
FreeBSD 提供多种软件安装方法。最常见的方法之一是使用内置的 pkg(8)包管理器,它通过获取和安装预构建的二进制软件包简化了该过程。另一种方法是使用 ports(7)集合从源代码编译和安装软件,提供了一种灵活且可定制的安装软件方式。
FreeBSD 的文档详细介绍了这两种方法,确保用户可以轻松地通过所需的软件扩展其系统的功能。
FreeBSD、NetBSD、OpenBSD 和 DragonFly BSD 都是开源 BSD 家族的一部分,共享共同的类 UNIX 基础,但每个项目都有自己独特的重点和优先事项。这些差异反映了每个项目的独特目标,虽然它们有相似之处,但它们的具体优势和重点满足了 BSD 生态系统中不同的用例和偏好。
不,FreeBSD 不是 Linux 发行版。
虽然 FreeBSD 和 Linux 都是类 UNIX 操作系统,共享许多相似之处,但它们有各自独特的内核。Linux 使用 Linux 内核,而 FreeBSD 使用基于伯克利软件发行(BSD)UNIX 操作系统的 FreeBSD 内核。
FreeBSD 和 Linux 各自拥有其独特的开发社区、发布周期和系统架构,使它们成为独立的操作系统。
FreeBSD 提供了自己一套优势,包括不同的许可模型、系统设计和用户态工具与 Linux 发行版相比。
是的,FreeBSD 提供了一个被称为 linuxulator(linux(4))的兼容层,允许许多 Linux 程序在 FreeBSD 上运行。该功能可以在没有专用 Linux 环境的情况下执行广泛范围的 Linux 二进制文件。
尽管如此,值得注意的是,许多广泛使用的开源软件通过 ports 和软件包系统在 FreeBSD 上有原生版本可用。
安装 FreeBSD 是利用这个强大的开源操作系统的初始步骤。本节提供了关于在哪里获取 FreeBSD、详细的安装说明以及有关 FreeBSD-CURRENT 和 FreeBSD-STABLE 等概念的基本信息。还深入探讨了发布和快照时间表、安装后配置工具、软件包搜索方法,并解答了关于软件包更新的常见问题。
FreeBSD 可从官方 FreeBSD 网站免费下载。
此外,FreeBSD 也可以通过各种镜像站点获得,确保全球用户可以访问。官方网站是获取最新 FreeBSD 版本和更新的主要且最可靠的来源,是开始 FreeBSD 之旅的理想起点。
安装说明可在手册的安装 FreeBSD 章节中找到。
FreeBSD-CURRENT 代表 FreeBSD 操作系统的开发分支。这是 FreeBSD 的最前沿版本,是活跃开发的地方。
虽然它包含了最新的特性、改进和实验性变化,但它并不总是像 FreeBSD-STABLE 或发布版本那样稳定。
FreeBSD-CURRENT 作为开发人员和爱好者的平台,他们希望为 FreeBSD 的未来做出贡献,并始终保持在其发展的前沿,尽管它偶尔会经历重大变化,不建议用于生产系统。
FreeBSD-STABLE 分支是一个比 CURRENT 更稳定的开发分支。它包含正在进行进一步测试和完善的代码,然后才会合并到 RELEASE 分支中。对于那些想要跟踪 FreeBSD 开发但更喜欢比 CURRENT 更稳定的环境的人来说,STABLE 是一个不错的选择。
发行工程团队re@FreeBSD.org大约每 18 个月发布一个新的 FreeBSD 主要版本,每 8 个月发布一个新的次要版本,平均而言。发布日期会提前宣布,这样系统上工作的人就知道他们的项目需要在何时完成和测试。每次发布之前都会有一个测试期,以确保新功能的添加不会影响发布的稳定性。
FreeBSD 快照通常定期生成,涵盖所有正在积极开发的分支。这些快照捕获了 FreeBSD 源代码和相关二进制软件包的某一时刻。这些快照的频率可能有所不同,但通常每周或每两周进行一次。这些快照为用户提供了访问 FreeBSD 最新发展和变化的机会,帮助他们保持与项目进展同步。
是的。bsdconfig(8)提供了一个很好的界面,用于配置 FreeBSD 安装后的设置。
通过 pkg(8)软件包管理器和 pkg search 命令,可以轻松地搜索要在 FreeBSD 中安装的软件。
用户可以使用此命令使用关键字、软件包名称或描述搜索可用软件包。此功能帮助用户快速在庞大的 FreeBSD ports 软件包集合中定位他们需要的软件,简化向其 FreeBSD 系统添加新应用程序和工具的过程。
FreeBSD 中最新软件包的可用性受多种因素影响,包括软件包仓库的更新频率和使用的具体 FreeBSD 版本。
还应该添加的是,FreeBSD ports 有两个分支。最新的称为 latest ,最稳定的称为 quarterly 。要使用最新的软件包,需要配置 latest 分支。有关如何配置分支的信息,请参阅手册的 Ports 章节。
硬件部分探讨了 FreeBSD 与各种硬件配置的兼容性。涵盖了一系列主题,包括支持的架构,最大内存容量,处理器可扩展性,显卡兼容性,Wi-Fi 卡支持,以及包括 10 千兆以太网网络卡支持。无论是计划在服务器、工作站还是专用硬件上部署 FreeBSD,本节提供了有关 FreeBSD 能力和限制的见解,提供有关硬件选择和配置的信息。
FreeBSD 支持多种架构,使其成为适用于各种硬件环境的灵活选择。其兼容性扩展到诸如 amd64 、 arm64 、 riscv 等架构。
支持架构的完整列表可以在平台页面找到。
作为一个操作系统,FreeBSD 通常支持与其运行的平台相同的物理内存(RAM)。请记住,不同的平台对内存有不同的限制。
例如, amd64 平台支持高达 4TB 的物理内存。
FreeBSD 的处理器支持因不同架构而异。在 amd64 和 arm64 系统上,FreeBSD 可以高效地利用多达 1024 个处理器的性能。对于基于 powerpc 的系统,FreeBSD 支持多达 256 个处理器,而在 risc-v 系统上,它可以有效地利用多达 16 个处理器。
类似 Intel®、AMD® 或 NVIDIA® 这样的热门图形供应商得到了良好的支持。
可在 FreeBSD Wiki 中找到对 Intel 和 AMD 支持的图形卡列表。
发现 FreeBSD 与各种 Wi-Fi 卡的兼容性,使得将系统连接到无线网络变得容易。
以下是在 FreeBSD 上已知工作良好的 USB Wi-Fi 设备列表:
RT5370 USB 设备(支持 hostap 模式)
TP-Link TL-WDN3200(RT5592,if_run(4))
TP-Link TL-WN725N v2(RTL8188EU,rtwn(4))
TP-Link Archer T4U(RTL8812AU,rtwn(4))
D-Link DWA-131(RTL8192CU,rtwn(4))
D-Link DWA-171 rev A1(RTL8821AU,rtwn(4))
ASUS USB-N10 NANO(RTL8188CUS,rtwn(4))
在 FreeBSD 上已知工作良好的 Mini PCIe Wi-Fi 设备列表:
Realtek RTL8188CE Mini PCIe
FreeBSD 为 10 千兆以太网网络卡提供强大支持,使其成为高速网络环境的可行选择。FreeBSD 内核包含来自各种制造商的广泛范围的 10 千兆以太网适配器的驱动程序,确保无缝集成和最佳网络性能。
更多信息可在 FreeBSD Wiki 上获得。
本节为那些希望深入了解 FreeBSD 的人提供了宝贵的资源。它涵盖了一系列主题,包括学习 FreeBSD 推荐的书籍,商业培训和支持途径,了解 FreeBSD 内部工作原理的见解,以及在 FreeBSD 社区内寻求帮助的地方。
FreeBSD 爱好者和学习者可以探索一系列致力于该操作系统的信息书籍。这些书籍涵盖了从 FreeBSD 基础知识到高级系统管理和开发的各种主题。
一些值得注意的标题包括迈克尔·W·卢卡斯(Michael W. Lucas)著的《绝对 FreeBSD:FreeBSD 完全指南》,以及迈克尔·W·卢卡斯(Michael W. Lucas)著的《FreeBSD 掌握系列》,等等。这些资源提供有价值的见解和知识,帮助用户各个级别的用户掌握 FreeBSD 并最大程度地发挥其潜力。
除了图书以外,FreeBSD 项目还制作了各种广泛的文档,可在线在文档门户中获取。
对于那些寻求 FreeBSD 专业培训和支持的人,有几家商业提供商提供定制服务。FreeBSD 项目维护着一个可以请求支持的公司列表。
对于想深入了解 FreeBSD 内部运行机制的人来说,可以探索《FreeBSD 操作系统设计与实现》等资源。FreeBSD 架构手册是另一个宝贵的资源,提供了有关 FreeBSD 架构、系统组织和设计原则的详细信息。
此外,审阅 FreeBSD 源代码,可通过 FreeBSD 源代码存储库获得,可为操作系统的核心组件提供宝贵的见解。
在 FreeBSD 系统中获取帮助非常简单。FreeBSD 提供丰富的内置文档,可通过 man(1)命令访问,该命令提供有关各种命令和系统组件的全面信息。
另外,FreeBSD 手册在系统上可在线获取,也作为深入指导的宝贵资源。
如果出现特定问题,通过邮件列表、论坛或 IRC 寻求 FreeBSD 社区的帮助可以提供及时的解决方案,并获得经验丰富的 FreeBSD 用户和开发人员的见解。
探索此部分,以发现与 FreeBSD 社区互动的方式。
了解有关 FreeBSD IRC 频道的实时讨论,用于分享见解的基于 Web 的论坛,以及用于深入讨论和新闻更新的 FreeBSD 邮件列表和新闻组。
是的,大多数主要的 IRC 网络都设有一个 FreeBSD 聊天频道,而 FreeBSD 维基上有一个最新的 IRC 频道列表。
这些频道各不相同,彼此之间没有连接。由于它们的聊天风格不同,请尝试每一个找到适合您聊天风格的频道。
官方的 FreeBSD 论坛位于 FreeBSD 论坛主页。
公共邮件列表可以在 FreeBSD 邮件列表找到。
探索有关 FreeBSD 的各种有趣和实用的查询,涵盖从 shell 选择到系统怪癖,甚至是 FreeBSD 宠物的名字。
很多人需要编写 shell 脚本,这些脚本需要在许多系统上可移植。这就是为什么 POSIX® 详细规定了 shell 和实用程序命令。大多数脚本都是用 Bourne shell(sh(1))编写的,因为规定了使用 Bourne shell 解释命令的几个重要编程接口。由于 Bourne shell 经常被广泛使用,因此它启动迅速、行为确定性并且具有较小的内存占用量非常重要。
现有的实现是我们尽最大努力同时满足尽可能多的这些要求。为了保持 /bin/sh 小,我们没有提供其他 shells 通常具有的许多便利功能。
这就是为什么其他更加功能丰富的 shells 像 bash 、 scsh 、tcsh(1)和 zsh 都是可用的。
对于 Bourne Shell,请将以下行添加到~/.shrc 中:
对于 C Shell,请将以下行添加到~/.cshrc 中:
不要惊慌!重新启动系统,在 Boot: 提示符下输入 boot -s 以进入单用户模式。在询问要使用的 shell 时,按 Enter 键,屏幕将显示 # 提示符。输入 mount -urw / 重新挂载根文件系统为读写,然后运行 mount -a 重新挂载所有文件系统。运行 passwd root 更改 root 密码,然后运行 exit(1) 继续引导。
在加载程序提示符处使用 boot -s 重新启动系统以进入单用户模式。在提示输入 shell 路径名时,按 Enter 并运行 mount -urw / 以将根文件系统重新挂载为读/写模式。您可能还需要运行 mount -a -t ufs 以挂载定义您喜爱编辑器的文件系统。如果该编辑器位于网络文件系统上,则在挂载网络文件系统之前手动配置网络,或者使用位于本地文件系统上的编辑器,例如 ed(1)。
为了使用诸如 vi(1)或 emacs(1)等全屏编辑器,请运行 export TERM=xterm ,以便这些编辑器可以从 termcap(5)数据库中加载正确的数据。
执行这些步骤后,编辑/etc/rc.conf 以修复语法错误。内核引导消息之后立即显示的错误消息应指出错误文件中出错的行号。
有几种"空闲内存"。最常见的是立即可用的内存量,而无需重新获取已经在使用的内存。这是空闲页面队列的大小加上一些其他保留页面。这个数量由 vm.stats.vm.v_free_count sysctl(8)导出,例如,由 top(1)显示。另一种"空闲内存"是可供用户空间进程使用的虚拟内存总量,这取决于交换空间和可用内存的总和。还有其他可能的"空闲内存"描述,但定义这些描述相对无用,更重要的是确保页面交换率保持低水平,并避免耗尽交换空间。
使用 tzsetup(8)。
FreeBSD 会主动将完全空闲未使用的主内存页面移动到交换空间中,以便为活动使用提供更多的主内存。这种大量使用交换空间的行为是通过使用额外的空闲内存进行缓存来平衡的。
请注意,虽然 FreeBSD 在这方面是积极主动的,但它并不会在系统真正空闲时任意决定交换页面。因此,将系统保持空闲过夜后不会全部分页出。
简单的答案是,空闲内存是浪费的内存。
程序没有主动分配的任何内存都被用作 FreeBSD 内核中的磁盘缓存。 top(1)显示的标记为 Inact 和 Laundry 的值是不同老化级别的缓存数据。 这些缓存数据意味着系统不必再次访问慢速磁盘以获取最近访问过的数据,从而提高整体性能。 通常情况下,在 top(1)中显示的 Free 内存的低值是好的,前提是不是很低。
他没有名字,只被称为“BSD 守护程序”。如果你坚持要给他起个名字,请叫他“比斯蒂”。请注意,“比斯蒂”是按照“BSD”的发音来念的。
更多关于 BSD 守护程序的信息,请访问他的主页。
或许。BSD 守护进程的版权归 Marshall Kirk McKusick 所有。请查看他关于 BSD 守护进程图像使用条款的声明以获取详细信息。
简而言之,该图像可以在个人使用时以得体的方式使用,只要给予适当的授信。在商业上使用该标志之前,请联系 Kirk McKusick mckusick@FreeBSD.org 以获得许可。有关 BSD 守护进程主页的更多详细信息,请访问主页。
确实非常简短的答案是你不应该在意。稍微长一点的答案是,只是因为你有能力建造一个车棚,并不意味着你应该阻止他人建造一个,只是因为你不喜欢他们计划油漆的颜色。这只是一个比喻,表明你不需要为每一个小特性争论,只因为你知道足够这样做。有些人评论说,一个变化产生的噪音量与变化的复杂性成反比。
更长而完整的答案是,在经过一场关于 sleep(1)是否应该接受小数秒参数的争论后,Poul-Henning Kamp < phk@FreeBSD.org> 发表了一封长长的帖子,标题为任意颜色的车棚......
从技术细节中休息一下,深入了解 FreeBSD 的有趣一面。
有人在运行 FreeBSD 时做过温度测试吗? 不,但我们对被蒙上眼睛并事先服用了 250 微克 LSD-25 的志愿者进行了大量口味测试。35%的志愿者说 FreeBSD 尝起来有点橙色,而 GNU/Linux® 尝起来像紫雾。两组都没有提到任何明显的温度变化。
严肃地说,FreeBSD 使用 ACPI(高级配置和电源接口),因此 FreeBSD 可以将 CPU 置于低功耗模式。
它进入 CPU 中的特殊数据汇聚处,转化为热量,通过散热器/风扇组件排出。这就是为什么 CPU 冷却变得越来越重要;随着人们习惯于更快的处理器,他们对数据变得更加粗心,越来越多的数据最终进入 /dev/null,使 CPU 过热。
如果删除 /dev/null(实际上是禁用 CPU 数据汇聚),你的 CPU 可能会运行得更凉爽,但你的系统很快会因为所有多余的数据而变得混乱,并开始表现异常。
如果你有一个快速的网络连接,你可以通过从 /dev/random 读取数据并发送到其他地方来降低 CPU 温度;然而,你会面临过热网络连接的风险,或者激怒你的 ISP,因为大部分数据最终会被他们的设备转化为热量,但他们通常有良好的冷却,所以如果不过度使用,你应该没问题。
安装 games/sl 并等待他们将 ls 误输入为 sl 。
这个常见问题解答已经在过去几十年里经历了无数次的修订和改进,由不同背景的贡献者组成的群体共同完成。
本项目包含对以下书籍的翻译:
A project model for the FreeBSD Project 《FreeBSD 项目模型》
Frequently Asked Questions for FreeBSD 《FreeBSD 常见问题解答》
The Design and Implementation of the 4.4BSD Operating System 《4.4BSD 操作系统设计与实现》
译者提示
《4.4BSD 操作系统设计与实现》为节选本,完整版本在国内已经出版,但是均已绝版。
中文版:
机械工业出版社 ISBN: 9787111366478
人民邮电出版社 ISBN: 9787508315089
英文版影印版:
人民邮电出版社 ISBN: 9787115103482
FreeBSD 手册
FreeBSD Port 开发者手册
FreeBSD 官方文章
《FreeBSD 项目模型》、《FreeBSD 常见问题解答》、《4.4BSD 操作系统设计与实现》
FreeBSD 架构手册
FreeBSD 开发者手册
FreeBSD 发行说明
FreeBSD 状态报告
版权 © 1996 Addison-Wesley Longman,Inc
4.4BSD 内核提供四个基本功能:进程、文件系统、通信和系统启动。本节概述了这四个基本服务在本书中的描述位置。
进程构成地址空间中的控制线程。有关创建、终止和其他控制进程的机制,请参阅第 4 章。系统为每个进程多路复用单独的虚拟地址空间;这种内存管理在第 5 章中讨论。
文件系统和设备的用户界面是相似的;共同之处在第 6 章中进行了讨论。文件系统是一组具有名称的文件,以目录树形式组织,以及操作来操作它们,如第 7 章所述。文件驻留在诸如磁盘之类的物理介质上。4.4BSD 支持在磁盘上的数据的几种组织形式,如第 8 章所述。访问远程机器上的文件是第 9 章的主题。终端用于访问系统;它们的操作是第 10 章的主题。
传统 UNIX 系统提供的通信机制包括相关进程之间的可靠的单向字节流(见管道,第 11.1 节),以及异常事件的通知(见信号,第 4.7 节)。4.4BSD 还具有一般的进程间通信设施。该设施在第 11 章中描述,使用与文件系统不同的访问机制,但是一旦建立连接,进程可以像使用管道一样访问它。有一个一般的网络框架,如第 12 章所述,通常被用作 IPC 设施的底层层。第 13 章详细描述了一种特定的网络实现。
任何真正的操作系统都有操作上的问题,比如如何启动它运行。启动和操作问题在第 14 章中描述。
第 2.3 节到第 2.14 节介绍了与第 3 章到第 14 章相关的入门材料。我们将定义术语,提及基本系统调用,并探讨历史发展。最后,我们将阐明许多重要设计决策的原因。
内核是系统中在受保护模式下运行的部分,调解所有用户程序对底层硬件(例如 CPU、磁盘、终端、网络链接)和软件构造(例如文件系统、网络协议)的访问。内核提供基本的系统设施;它创建和管理进程,并提供访问文件系统和通信设施的功能。这些功能被称为系统调用,对用户进程而言,它们看起来像是库子程序。这些系统调用是进程与这些设施之间唯一的接口。系统调用机制的详细信息在第 3 章中给出,描述了几个内核机制,这些机制不是作为进程执行系统调用的直接结果而执行的。
传统操作系统术语中的内核是提供实现额外操作系统服务所需的最小功能的软件小核心。在当代研究操作系统中- 诸如 Chorus [Rozier et al, 1988],Mach [Accetta et al, 1986],Tunis [Ewens et al, 1985]和 V Kernel [Cheriton, 1988] - 这种功能的划分不仅仅是一个逻辑划分。文件系统和网络协议等服务作为内核或核心的客户端应用程序来实现。
4.4BSD 内核未分成多个进程。这个基本设计决策是在 UNIX 的最早版本中做出的。Ken Thompson 的前两次实现没有内存映射,因此在用户和内核空间之间没有硬件强制区别。消息传递系统可以像实际实现的内核和用户进程模型一样容易实现。选择了单片内核是为了简单性和性能。早期的内核很小;将网络等设施包含到内核中已经增加了其大小。操作系统研究的当前趋势是通过将这些服务放在用户空间来减小内核大小。
用户通常通过一个命令语言解释器(称为shell)和可能通过其他用户应用程序与系统交互。这类程序和shell是通过进程实现的。这类程序的详细信息不在本书的范围内,本书几乎完全集中在内核上。
第 2.3 节和 2.4 节描述了 4.4BSD 内核提供的服务,并概述了后者的设计。后面的章节描述了这些服务的详细设计和实现,就像它们出现在 4.4BSD 中一样。
在本节中,我们以两种方式查看 4.4BSD 内核的组织方式:
作为一种静态软件主体,通过构成内核的模块所提供的功能进行分类
通过其动态操作,根据提供给用户的服务进行分类
内核的最大部分实现了应用程序通过系统调用访问的系统服务。在 4.4BSD 中,这个软件根据以下方式进行了组织:
基本内核设施:定时器和系统时钟处理,描述符管理和进程管理
内存管理支持:分页和交换
通用系统接口:在描述符上执行的 I/O、控制和多路复用操作
文件系统:文件、目录、路径名转换、文件锁定和 I/O 缓冲区管理
终端处理支持:终端接口驱动程序和终端线规则
进程间通信设施:套接字
支持网络通信:通信协议和通用网络设施,如路由
表 1. 4.4BSD 内核中的机器无关软件
头文件
9,393
4.6
初始化
1,107
0.6
内核设施
8,793
4.4
通用接口
4,782
2.4
进程间通信
4,540
2.2
终端处理
3,911
1.9
虚拟内存
11,813
5.8
vnode 管理
7,954
3.9
文件系统命名
6,550
3.2
快速文件存储
4,365
2.2
日志结构文件存储
4,337
2.1
基于内存的文件存储
645
0.3
cd9660 文件系统
4,177
2.1
杂项文件系统(10)
12,695
6.3
网络文件系统
17,199
8.5
网络通信
8,630
4.3
互联网协议
11,984
5.9
ISO 协议
23,924
11.8
X.25 协议
10,626
5.3
XNS 协议
5,192
2.6
这些类别中的大多数软件是与机器无关的,并且可以在不同的硬件架构之间移植。
内核的与机器有关的方面与主流代码隔离开来。特别是,与特定架构的条件代码没有包含在与机器无关的代码中。当需要特定于架构的操作时,与机器无关的代码调用位于与机器有关的代码中的特定于架构的函数。与机器相关的软件包括
低级系统启动操作
陷阱和故障处理
进程运行时环境的低级操作
配置和初始化硬件设备
I/O 设备的运行时支持
表 2. HP300 机器相关软件在 4.4BSD 内核中的分类
|代码行数|内核百分比| | -------------------------------------------------| ---------------| ----------------------| |机器相关头文件|1,562|0.8| |设备驱动头文件|3,495|1.7| |设备驱动源代码|17,506|8.7| |虚拟内存|3,087|1.5| |其他机器相关|6,287|3.1| |汇编语言例程|3,014|1.5| |HP/UX 兼容性|4,683|2.3|
4.4BSD 内核中的机器无关软件概述了构成 HP300 的 4.4BSD 内核的机器无关软件。第二列中的数字是 C 源代码、头文件和汇编语言的代码行数。几乎所有内核软件都是用 C 编程语言编写的;用汇编语言编写的不到 2%。如 4.4BSD 内核中 HP300 的机器相关软件中的统计数据所示,除去 HP/UX 和设备支持,机器相关软件仅占内核的 6.9%。
内核中只有一小部分用于初始化系统。这些代码在系统启动时使用,负责设置内核的硬件和软件环境(见第 14 章)。一些操作系统(尤其是那些物理内存有限的操作系统)在执行这些功能后,会丢弃或覆盖执行这些功能的软件。4.4BSD 内核不会回收启动代码使用的内存,因为在典型机器上,这部分内存资源仅占内核资源的 0.5%。此外,启动代码不会集中出现在内核的某一个地方——它分散在整个内核中,通常出现在与被初始化内容逻辑相关的位置。
内核级和用户级代码之间的边界由底层硬件提供的硬件保护设施强制执行。内核在一个对用户进程不可访问的单独地址空间中运行。特权操作(如启动 I/O 和停止中央处理单元(CPU))仅对内核可用。应用程序通过系统调用从内核请求服务。系统调用用于导致内核执行复杂操作,如将数据写入二级存储,以及简单操作,如返回当前时间。所有系统调用对应用程序都是同步的:应用程序在内核执行与系统调用相关的操作时不运行。内核可能在返回后完成与系统调用相关的一些操作。例如,写入系统调用将在进程等待时将要写入的数据从用户进程复制到内核缓冲区,但通常会在内核缓冲区写入磁盘之前从系统调用返回。
系统调用通常被实现为改变 CPU 执行模式和当前地址空间映射的硬件陷阱。系统调用中由用户提供的参数在被使用之前会被内核验证。这样的检查确保了系统的完整性。所有传递到内核的参数都会被复制到内核的地址空间中,以确保经过验证的参数不会在系统调用的副作用中被更改。系统调用的结果由内核返回,可以通过硬件寄存器或将它们的值复制到用户指定的内存地址来返回。与传递到内核的参数类似,用于返回结果的地址必须经过验证,以确保它们是应用程序地址空间的一部分。如果内核在处理系统调用时遇到错误,它会向用户返回错误代码。对于 C 编程语言,此错误代码存储在全局变量 errno 中,并且执行系统调用的函数返回值为 -1。
用户应用程序和内核相互独立运行。4.4BSD 不会将 I/O 控制块或其他操作系统相关的数据结构存储在应用程序的地址空间中。每个用户级应用程序都在其执行的独立地址空间中提供。内核会使大多数状态更改,例如在另一个进程运行时挂起进程,对涉及的进程不可见。
4.4BSD 支持多任务环境。每个任务或执行线程称为一个进程。4.4BSD 进程的上下文包括用户级状态,包括其地址空间的内容和运行时环境,以及内核级状态,其中包括调度参数、资源控制和标识信息。上下文包括内核在为进程提供服务时使用的所有内容。用户可以创建进程,控制进程的执行,并在进程的执行状态发生变化时接收通知。每个进程被分配一个唯一值,称为进程标识符(PID)。内核在向用户报告状态更改时使用此值来标识进程,并且用户在系统调用中引用进程时也使用该值。
内核通过复制另一个进程的上下文来创建进程。新进程称为原始父进程的子进程。进程创建中复制的上下文包括进程的用户级执行状态和内核管理的进程系统状态。内核状态的重要组件在第 4 章中描述。
进程生命周期
进程生命周期使用进程生命周期中描述的。一个进程可以使用 fork 系统调用创建一个与原始进程相同的新进程。fork 调用两次返回:一次在父进程中,其中返回值是子进程的进程标识符,一次在子进程中,其中返回值是 0。父子关系在系统中的一组进程上引入了一个分层结构。新进程共享其父进程的所有资源,如文件描述符、信号处理状态和内存布局。
尽管有时新进程被设计为父进程的副本,但加载和执行不同程序是一种更有用和典型的操作。一个进程可以用 execve 系统调用将自己覆盖另一个程序的内存映像,传递一组参数给新创建的映像。其中一个参数是一个文件的名称,该文件的内容以系统识别的格式存在——要么是一个二进制可执行文件,要么是一个导致执行指定解释程序处理其内容的文件。
一个进程可以通过执行 exit 系统调用终止,向其父进程发送 8 位退出状态。如果一个进程想要与其父进程通信超过一个字节的信息,它必须设置一个使用管道或套接字的进程间通信通道,或使用一个中间文件。进程间通信在第 11 章中有详细讨论。
一个进程可以使用 wait 系统调用暂停执行,直到其任何子进程终止。该系统调用返回终止的子进程的 PID 和退出状态。父进程可以安排在子进程退出或异常终止时通过信号通知。使用 wait4 系统调用,父进程可以检索导致子进程终止的事件信息以及进程在其生命周期中消耗的资源信息。如果一个进程变成孤儿,因为其父进程在其完成之前退出,那么内核会安排将子进程的退出状态传递回一个特殊的系统进程 init:参见第 3.1 节和第 14.6 节。
内核如何创建和销毁进程的详细信息在第 5 章中给出。
进程根据进程优先级参数进行调度执行。这个优先级由基于内核的调度算法管理。用户可以通过指定一个参数(nice)来影响进程的调度,该参数权衡了整体调度优先级,但仍然需要根据内核的调度策略共享底层 CPU 资源。
系统定义了一组可能传递给进程的信号。4.4BSD 中的信号是模拟硬件中断的。进程可以指定一个用户级子程序作为信号的处理程序,信号应该传递到该处理程序。当信号生成时,在信号被处理程序捕获时,它会被阻止再次发生。捕获信号涉及保存当前进程上下文并构建一个新的上下文来运行处理程序。然后将信号传递给处理程序,处理程序可以中止进程或返回到执行进程(也许在设置全局变量后)。如果处理程序返回,信号将被解除阻止,可以再次生成(和捕获)。
或者,进程可以指定忽略信号,或者采取由内核确定的默认操作。某些信号的默认操作是终止进程。此终止可能伴随着创建包含进程当前内存映像的核心文件,用于事后调试。
有些信号无法被捕获或忽略。这些信号包括 SIGKILL,用于终止无法控制的进程,以及作业控制信号 SIGSTOP。
进程可以选择在特殊堆栈上接收信号,以便进行复杂的软件堆栈操作。例如,支持协程的语言需要为每个协程提供一个堆栈。语言运行时系统可以通过将 4.4BSD 提供的单个堆栈分配给这些堆栈来分配这些堆栈。如果内核不支持单独的信号堆栈,则必须通过扩展为每个协程分配的空间来捕获信号所需的空间。
所有信号具有相同的优先级。如果多个信号同时待处理,信号传递给进程的顺序是由实现指定的。信号处理程序执行时被阻止的信号引起其调用,但其他信号可能会发生。提供机制以便进程可以保护代码的关键部分免受指定信号的发生。
信号的详细设计和实现在第 4.7 节中描述。
进程被组织成进程组。进程组用于控制对终端的访问,并提供一种将信号分发给相关进程集合的方法。进程从其父进程继承其进程组。内核提供机制允许进程更改其进程组或其后代的进程组。创建新的进程组很容易;新进程组的值通常是创建进程的进程标识符。
进程组中的一组进程有时被称为作业,并由高级系统软件(如shell)操纵。shell创建的一种常见作业是由多个进程通过管道连接而成的管道,使得第一个进程的输出成为第二个进程的输入,第二个进程的输出成为第三个进程的输入,依此类推。shell通过为管道的每个阶段复制一个进程,然后将所有这些进程放入单独的进程组来创建这样的作业。
用户进程可以向进程组中的每个进程发送信号,也可以向单个进程发送信号。特定进程组中的进程可能会接收影响该组的软件中断,导致该组暂停或恢复执行,或者被中断或终止。
终端分配了一个进程组标识符。该标识符通常设置为与终端关联的进程组的标识符。作业控制shell可能会创建与同一终端关联的多个进程组;终端是这些组中每个进程的控制终端。如果进程的控制终端描述符与进程的进程组标识符不匹配,则进程只能从其控制终端读取。如果标识符不匹配,则进程尝试从终端读取时将被阻止。通过更改终端的进程组标识符,shell可以在几个不同的作业之间仲裁终端。这种仲裁称为作业控制,并在第 4.8 节中描述了进程组。
就像一组相关的进程可以被收集到一个进程组中一样,一组进程组可以被收集到一个会话中。会话的主要用途是为守护进程及其子进程创建一个与外部隔离的环境,并集中存放用户登录shell和shell生成的作业。
每个进程有自己的私有地址空间。地址空间最初被划分为三个逻辑段:文本、数据和栈。文本段是只读的,包含程序的机器指令。数据和栈段既可读又可写。数据段包含程序的已初始化和未初始化数据部分,而栈段保存应用程序的运行时栈。在大多数机器上,随着进程的执行,内核会自动扩展栈段。一个进程可以通过系统调用扩展或收缩其数据段,而一个进程只能在段的内容与来自文件系统的数据重叠,或进行调试时改变其文本段的大小。子进程的段的初始内容是父进程段的副本。
执行进程不需要整个进程地址空间都驻留在内存中。如果一个进程引用了其地址空间中未驻留在主存中的部分,系统会将必要的信息分页到内存中。当系统资源紧张时,系统采用两级方法来维护可用资源。如果有适量的内存可用,系统会从进程中取走内存资源,如果这些资源最近没有被使用。如果资源严重短缺,系统将会将进程的整个上下文换入到辅助存储器。系统进行的需求分页和换页对进程来说是透明的。然而,一个进程可以告知系统关于未来预期内存利用的信息,以提高性能。
4.2BSD 要求支持大型稀疏地址空间、映射文件和共享内存。制定了一个被称为 mmap 的接口,允许不相关的进程请求将文件映射到它们的地址空间中。如果多个进程将同一文件映射到它们的地址空间中,一个进程对文件部分地址空间的更改将反映在其他进程的映射区域,以及文件本身中。最终,4.2BSD 没有使用 mmap 接口进行发布,因为要使其他功能(如网络)可用而受到压力。
进一步发展了 mmap 接口,这一工作在 4.3BSD 的开发过程中继续进行。超过 40 家公司和研究团体参与了讨论,导致了在伯克利软件体系结构手册中描述的修订架构 [McKusick 等,1994 年]。其中一些公司已经实现了修订后的接口 [Gingell 等,1987 年]。
再次,时间紧迫,使得 4.3BSD 无法提供接口的实现。尽管后者可以构建到现有的 4.3BSD 虚拟内存系统中,但开发人员决定不这样做,因为该实现已接近 10 年。此外,原始虚拟内存设计是基于计算机内存较小、昂贵,而磁盘连接本地、快速、大型且廉价的假设。因此,虚拟内存系统被设计为在使用内存时节俭,以换取产生额外的磁盘流量。此外,4.3BSD 实现中存在大量依赖于 VAX 内存管理硬件的问题,这阻碍了其在其他计算机架构上的可移植性。最后,虚拟内存系统并不是为了支持日益普遍和重要的紧密耦合多处理器而设计的。
尝试逐步改进旧实现似乎注定失败。另一方面,完全新的设计可以利用大容量内存,节省磁盘传输,并有潜力在多处理器上运行。因此,在 4.4BSD 中完全替换了虚拟内存系统。4.4BSD 虚拟内存系统基于 Mach 2.0 VM 系统[Tevanian, 1987],并从 Mach 2.5 和 Mach 3.0 进行了更新。它具有有效的共享支持,清晰地分离了机器无关和机器相关的特性,以及(目前未使用的)多处理器支持。进程可以在其地址空间中的任何位置映射文件。它们可以通过对同一文件进行共享映射来共享其地址空间的部分。一个进程所做的更改在另一个进程的地址空间中可见,并且也会写回到文件本身。进程还可以请求文件的私有映射,这可以防止它们所做的任何更改对映射文件的其他进程可见或写回到文件本身。
虚拟内存系统的另一个问题是在进行系统调用时将信息传递到内核的方式。4.4BSD 总是将数据从进程地址空间复制到内核中的缓冲区。对于传输大量数据的读取或写入操作,进行复制可能是耗时的。进行复制的替代方法是将进程内存重新映射到内核。4.4BSD 内核总是复制数据有几个原因:
通常,用户数据未对齐页,并且不是硬件页长度的倍数。
如果页面从进程中被取走,它将无法再引用该页面。一些程序依赖于数据即使在被写入后仍然保留在缓冲区中。
如果允许进程保留页面的副本(如当前 4.4BSD 语义中一样),则页面必须设置为写时复制。写时复制页面是通过设置为只读来保护不被写入的页面。如果进程试图修改该页面,内核会收到写入错误。然后内核会制作一个进程可以修改的页面副本。不幸的是,典型的进程会立即尝试将新数据写入其输出缓冲区,从而迫使数据无论如何都要被复制。
当页面重新映射到新的虚拟内存地址时,大多数内存管理硬件要求选择性地清除硬件地址转换缓存。缓存清除通常很慢。净效应是对于小于 4 到 8 K 字节的数据块,重新映射比复制更慢。
访问大文件和在进程之间传递大量数据的最大动机是内存映射。mmap 接口提供了一种在不复制数据的情况下完成这两项任务的方法。
内核通常会为仅在单个系统调用期间需要的内存进行分配。在用户进程中,这种短期内存会在运行时堆栈上分配。由于内核具有有限的运行时堆栈,因此在其上分配中等大小的内存块是不可行的。因此,这样的内存必须通过更动态的机制进行分配。例如,当系统必须翻译路径名时,它必须分配一个 1K 字节的缓冲区来保存名称。其他内存块必须比单个系统调用更持久,因此即使有空间也不应在堆栈上分配。一个例子是在网络连接的整个持续时间内保持的协议控制块。
内核中对动态内存分配的需求随着更多服务的添加而增加。通用内存分配器降低了内核内部编写代码的复杂性。因此,4.4BSD 内核具有一个可以被系统中任何部分使用的单一内存分配器。它具有类似于 C 库例程 malloc 和 free 的接口,为应用程序提供内存分配[McKusick&Karels,1988]。与 C 库接口类似,分配例程接受指定所需内存大小的参数。内存请求的大小范围不受限制;但是,分配的是物理内存,而不是分页。free 例程接受指向被释放存储的指针,但不需要被释放的内存块的大小。
UNIX I/O 系统的基本模型是一个可以随机或顺序访问的字节序列。在典型的 UNIX 用户进程中,没有访问方法和控制块。
不同的程序期望不同级别的结构,但内核不会对 I/O 施加结构。例如,文本文件的约定是由 ASCII 字符组成的行,由单个换行符(ASCII 换行符)分隔,但内核对这种约定一无所知。对于大多数程序来说,模型进一步简化为数据字节流,或者 I/O 流。正是这种单一的通用数据形式使得特征 UNIX 工具为基础的方法起作用[Kernighan&Pike,1984]。一个程序的 I/O 流可以作为输入馈送到几乎任何其他程序中。(这种传统 UNIX I/O 流不应与第八版流 I/O 系统或 System V,Release 3 STREAMS 混淆,这两者都可以作为传统 I/O 流访问。)
UNIX 进程使用描述符引用 I/O 流。描述符是从 open 和 socket 系统调用中获得的小的无符号整数。open 系统调用的参数是文件名和权限模式,用于指定文件是应该用于读取还是写入,或者两者兼而有之。这个系统调用还可以用于创建一个新的空文件。可以对描述符应用读取或写入系统调用来传输数据。close 系统调用可用于释放任何描述符。
描述符代表内核支持的基础对象,并由特定于对象类型的系统调用创建。在 4.4BSD 中,描述符可以表示三种对象:文件、管道和套接字。
文件是具有至少一个名称的字节线性数组。文件存在直到其所有名称都被显式删除,并且没有进程持有其描述符。进程通过使用 open 系统调用打开文件的名称来获取文件的描述符。I/O 设备被视为文件。
管道是字节线性数组,与文件相同,但仅用作 I/O 流,是单向的。它也没有名称,因此无法使用 open 打开。相反,它是通过 pipe 系统调用创建的,该调用返回两个描述符,其中一个接受输入,可可靠地将其发送到另一个描述符,无重复且有序。系统还支持命名管道或 FIFO。FIFO 具有与管道相同的属性,只是它出现在文件系统中;因此,可以使用 open 系统调用打开它。希望通信的两个进程各自打开 FIFO:一个用于读取,另一个用于写入。
套接字是一个瞬时对象,用于进程间通信;它只存在于某个进程持有指向它的描述符的时间。套接字是通过套接字系统调用创建的,该调用返回一个描述符。有不同类型的套接字,支持各种通信语义,如可靠传递数据,保留消息顺序和保留消息边界。
在 4.2BSD 之前的系统中,使用文件系统实现了管道;当在 4.2BSD 中引入套接字时,管道被重新实现为套接字。
内核为每个进程保留一个描述符表,这是内核用于将描述符的外部表示转换为内部表示的表。(描述符仅仅是这个表中的一个索引。)进程的描述符表是从该进程的父进程继承而来的,因此对描述符引用的对象的访问也是继承的。进程可以获取描述符的主要方式是通过打开或创建对象,并通过从父进程继承。此外,套接字 IPC 允许在同一台机器上的不相关进程之间在消息中传递描述符。
每个有效的描述符都有与对象开头的字节偏移量相关联。读写操作从该偏移量开始,每次数据传输后更新。对于允许随机访问的对象,还可以使用 lseek 系统调用设置文件偏移量。普通文件允许随机访问,有些设备也允许。管道和套接字则不允许。
当进程终止时,内核会回收该进程使用的所有描述符。如果进程持有对象的最后一个引用,对象的管理器会收到通知,以便执行任何必要的清理操作,例如最终删除文件或释放套接字。
大多数进程在启动运行时都希望已经打开了三个描述符。这些描述符分别是 0、1、2,更常被称为标准输入、标准输出和标准错误。通常,所有三个描述符都由登录进程(见第 14.6 节)与用户终端相关联,并通过用户运行的进程通过复制和执行继承。因此,程序可以通过读取标准输入来读取用户输入内容,程序可以通过写入标准输出将输出发送到用户屏幕。标准错误描述符也是打开的用于写入,并用于错误输出,而标准输出用于普通输出。
这些(以及其他)描述符可以映射到终端以外的对象;这种映射称为 I/O 重定向,所有标准shells允许用户执行此操作。shell可以通过关闭描述符 1(标准输出)并打开所需的输出文件来将程序的输出定向到文件,以生成新的描述符 1。它可以类似地将标准输入重定向为来自文件,方法是关闭描述符 0 并打开文件。
管道允许一个程序的输出成为另一个程序的输入,而无需重写或甚至重新链接任何一个程序。源程序的描述符 1(标准输出)不是设置为写入终端,而是设置为管道的输入描述符。类似地,接收程序的描述符 0(标准输入)被设置为引用管道的输出,而不是终端键盘。由此产生的两个进程及连接的管道集合被称为管道。管道可以是由管道连接的任意长的一系列进程。
open、pipe 和 socket 系统调用会产生具有可用于描述符的最低未使用编号的新描述符。为了使管道正常工作,必须提供某种机制来将这些描述符映射到 0 和 1。dup 系统调用会创建一个指向相同文件表项的描述符副本。新描述符也是最低未使用的描述符,但如果首先关闭了期望的描述符,则可以使用 dup 来执行所需的映射。但是需要注意:如果期望的是描述符 1,并且描述符 0 也已关闭,那么描述符 0 将是结果。为了避免这个问题,系统提供了 dup2 系统调用;它类似于 dup,但它接受一个额外的参数,指定所需描述符的编号(如果所需描述符已经打开,dup2 在重用之前会将其关闭)。
硬件设备有文件名,并且用户可以通过与常规文件相同的系统调用访问它们。内核可以区分设备特殊文件或特殊文件,并且可以确定它指向哪个设备,但大多数进程不需要做出这种确定。终端、打印机和磁带驱动器都可以像 4.4BSD 磁盘文件一样访问,即被视为字节流。因此,设备的依赖关系和特殊性尽可能地保留在内核中,即使在内核中,大多数特殊性都被隔离在设备驱动程序中。
硬件设备可以被归类为结构化或非结构化;它们分别被称为块设备或字符设备。进程通常通过文件系统中的特殊文件访问设备。对这些文件的 I/O 操作由内核驻留软件模块处理,称为设备驱动程序。大多数网络通信硬件设备只能通过进程间通信设施访问,并且在文件系统名称空间中没有特殊文件,因为原始套接字接口提供比特殊文件更自然的接口。
结构化或块设备的典型代表是磁盘和磁带,包括大多数随机访问设备。内核支持对面向块的结构化设备进行读取-修改-写入类型的缓冲操作,以允许后者以完全随机的字节寻址方式进行读取和写入,就像常规文件一样。文件系统是在块设备上创建的。
非结构化设备是那些不支持块结构的设备。熟悉的非结构化设备包括通信线路、光栅绘图仪和未缓冲的磁带和磁盘。非结构化设备通常支持大块 I/O 传输。
非结构化文件被称为字符设备,因为最早实现的是终端设备驱动程序。内核与这些设备的驱动程序的接口方便了其他非块结构设备的实现。
设备特殊文件是通过 mknod 系统调用创建的。还有一个额外的系统调用 ioctl,用于操作特殊文件的底层设备参数。可以针对每个设备执行不同的操作。这个系统调用允许访问设备的特殊特性,而不是过度使用其他系统调用的语义。例如,磁带驱动器上有一个 ioctl 用于写入磁带结束标记,而不是有一个特殊或修改过的写入版本。
4.2BSD 内核引入了一种 IPC 机制,比管道更灵活,基于套接字。套接字是通信的端点,由描述符引用,就像文件或管道一样。两个进程可以分别创建套接字,然后连接这两个端点以生成可靠的字节流。一旦连接,套接字的描述符可以被进程读取或写入,就像后者使用管道一样。套接字的透明性允许内核将一个进程的输出重定向到另一台机器上的另一个进程的输入。管道和套接字之间的一个主要区别是,管道需要一个共同的父进程来建立通信通道。套接字之间的连接可以由两个不相关的进程建立,可能驻留在不同的机器上。
System V 通过 FIFO(也称为命名管道)提供本地进程间通信。FIFO 在文件系统中显示为一个对象,不相关的进程可以打开并通过它发送数据,就像它们通过管道进行通信一样。因此,FIFO 不需要一个共同的父进程来设置它们;它们可以在一对进程启动并运行后连接。与套接字不同,FIFO 只能在本地机器上使用;它们不能用于在不同机器上的进程之间通信。FIFO 仅在 4.4BSD 中实现,因为它们是 POSIX.1 标准所要求的。它们的功能是套接字接口的一个子集。
套接字机制需要对传统的 UNIX I/O 系统调用进行扩展,以提供相关的命名和连接语义。开发人员没有过度使用现有接口,而是在现有接口能够正常工作的情况下使用它们,并设计了新的接口来处理新增的语义。读取和写入系统调用用于字节流类型的连接,但是还添加了六个新的系统调用,以允许发送和接收带有地址的消息,例如网络数据报。用于编写消息的系统调用包括 send、sendto 和 sendmsg。用于读取消息的系统调用包括 recv、recvfrom 和 recvmsg。回顾起来,每个类中的前两个都是其他系统调用的特例;recvfrom 和 sendto 可能应该作为 recvmsg 和 sendmsg 的库接口添加。
除了传统的读取和写入系统调用外,4.2BSD 还引入了分散/聚集 I/O 的功能。分散输入使用 readv 系统调用,允许将单个读取放置在几个不同的缓冲区中。相反,writev 系统调用允许在单个原子写入中写入几个不同的缓冲区。与使用 read 和 write 时传递单个缓冲区和长度参数不同,进程传递一个指向缓冲区和长度数组的指针,以及描述数组大小的计数。
该功能允许在进程地址空间的不同部分中原子地写入缓冲区,无需将它们复制到单个连续缓冲区。在底层抽象基于记录时,原子写入是必要的,例如磁带驱动器在每个写入请求上输出一个磁带块的情况。能够将单个请求读取到几个不同的缓冲区中也很方便(例如将记录头读取到一个地方,数据读取到另一个地方)。尽管应用程序可以通过将数据读入大缓冲区然后将片段复制到其预定目的地来模拟分散数据的能力,但在这种情况下,内存到内存的复制成本通常会将受影响的应用程序的运行时间加倍以上。
正如 send 和 recv 可以实现为对 sendto 和 recvfrom 的库接口一样,也有可能用 readv 和 writev 来模拟 read 和 write。然而,read 和 write 使用频率要高得多,模拟它们所需的额外成本并不值得。
随着网络计算的扩展,支持本地和远程文件系统变得可取。为了简化对多个文件系统的支持,开发人员向内核添加了一个新的虚拟节点或 vnode 接口。从 vnode 接口导出的操作集看起来很像先前由本地文件系统支持的文件系统操作。但是,它们可以由各种文件系统类型支持:
基于本地磁盘的文件系统
使用各种远程文件系统协议导入的文件
只读 CD-ROM 文件系统
提供特殊接口的文件系统 — 例如, /proc 文件系统
4.4BSD 的一些变体(例如 FreeBSD)允许在文件系统首次被挂载系统调用引用时动态加载文件系统。VNode 接口在第 6.5 节中描述;它的辅助支持例程在第 6.6 节中描述;几个特殊目的的文件系统在第 6.7 节中描述。
常规文件是一组线性字节数组,可以从文件中的任意字节开始进行读取和写入。内核在常规文件中不区分记录边界,尽管许多程序将换行符视为区分行尾的字符,而其他程序可能会施加其他结构。文件本身没有关于文件的与系统相关的信息,但文件系统会随每个文件存储少量所有权、保护和使用信息。
文件名组件是一个长达 255 个字符的字符串。这些文件名存储在称为目录的文件类型中。关于文件的目录中的信息称为目录条目,除了文件名外,还包括指向文件本身的指针。目录条目可能会指向其他目录,也可能指向普通文件。因此形成目录和文件的层次结构,称为文件系统。
一个小的文件系统
一个小的文件系统中显示了一个。目录可以包含子目录,并且目录嵌套的深度没有固有限制。为了保护文件系统的一致性,内核不允许进程直接写入目录。文件系统不仅可以包括普通文件和目录,还可以包括对其他对象的引用,如设备和套接字。
文件系统形成一棵树,其开始是根目录,有时候被称为斜杠,用单个斜杠字符(/)拼写。根目录包含文件;在我们的示例中,在图 2.2 中,它包含 vmunix ,一个内核可执行对象文件的副本。它还包含目录;在这个示例中,它包含 usr 目录。在 usr 目录中是 bin 目录,其中主要包含可执行程序的可执行对象代码,例如文件 ls 和 vi 。
一个进程通过指定文件的路径名来标识文件,该路径名是由零个或多个文件名组成,这些文件名之间用斜杠(/)字符分隔的字符串。内核为每个进程关联两个目录,用于解释路径名。进程的根目录是进程可以访问的文件系统中最顶层的点;通常设置为整个文件系统的根目录。以斜杠开头的路径名称为绝对路径名,并由内核从进程的根目录开始解释。
不以斜杠开头的路径名称为相对路径名,并相对于进程的当前工作目录进行解释。(这个目录也被称为更短的名称当前目录或工作目录。)当前目录本身可以直接用点的名称引用,用单个句点拼写( . )。文件名点点( .. )指的是目录的父目录。根目录是其自身的父目录。
进程可以使用 chroot 系统调用设置其根目录,并使用 chdir 系统调用设置其当前目录。任何进程都可以随时执行 chdir,但只有具有超级用户特权的进程才允许执行 chroot。Chroot 通常用于设置对系统的受限访问。
使用图 2.2 中显示的文件系统,如果进程将文件系统的根目录作为其根目录,并且将 /usr 作为其当前目录,则它可以从根目录使用绝对路径名 /usr/bin/vi 引用文件 vi ,或者从其当前目录使用相对路径名 bin/vi 引用。
系统实用程序和数据库保存在某些众所周知的目录中。定义明确的层次结构的一部分包括一个目录,该目录包含每个用户的主目录——例如,图 2.2 中的 /usr/staff/mckusick 和 /usr/staff/karels 。当用户登录时,其shell的当前工作目录被设置为主目录。在他们的主目录中,用户可以像创建常规文件一样轻松地创建目录。因此,用户可以构建任意复杂的子层次结构。
用户通常只知道一个文件系统,但系统可能知道这个虚拟文件系统实际上由几个物理文件系统组成,每个物理文件系统都在不同的设备上。物理文件系统不能跨多个硬件设备。由于大多数物理磁盘设备被划分为多个逻辑设备,每个物理设备可能有多个文件系统,但每个逻辑设备不会有多个文件系统。有一个文件系统——锚定所有绝对路径名的文件系统——称为根文件系统,并且始终可用。其他文件系统可以挂载;也就是说,它们可以集成到根文件系统的目录层次结构中。对挂载了文件系统的目录的引用会被内核透明地转换为对挂载文件系统的根目录的引用。
链接系统调用将现有文件的名称和另一个要为该文件创建的名称传入。成功链接后,文件可以通过任一文件名访问。可以使用取消链接系统调用来删除文件名。当文件的最终名称被删除(并且拥有该文件打开的最终进程关闭它时),文件将被删除。
文件在目录中按层次方式组织。目录是一种文件类型,但与常规文件不同,系统对目录施加了结构。进程可以像普通文件一样读取目录,但只有内核可以修改目录。目录是通过 mkdir 系统调用创建的,并通过 rmdir 系统调用删除。在 4.2BSD 之前,mkdir 和 rmdir 系统调用是通过一系列链接和取消链接系统调用来实现的。添加系统调用专门用于创建和删除目录有三个原因:
此操作可以变为原子。如果系统崩溃,目录将不会像使用一系列链接操作时可能发生的那样留下一半构建的状态。
当运行网络文件系统时,需要原子地指定文件和目录的创建和删除,以便它们可以被串行化。
当支持非 UNIX 文件系统(例如 MS-DOS 文件系统)在磁盘的另一个分区上时,其他文件系统可能不支持链接操作。尽管其他文件系统可能支持目录的概念,但它们可能不会像 UNIX 文件系统那样使用链接来创建和删除目录。因此,它们只能在提供显式目录创建和删除请求时创建和删除目录。
chown 系统调用设置文件的所有者和组,chmod 更改保护属性。应用于文件名的 stat 可用于读取文件的这些属性。fchown、fchmod 和 fstat 系统调用应用于描述符,而不是文件名,以执行相同的操作。rename 系统调用可用于在文件系统中为文件指定新名称,替换文件的旧名称之一。与目录创建和目录删除操作一样,rename 系统调用被添加到 4.2BSD 中,以在本地文件系统中为名称更改提供原子性。后来,它被证明可以将重命名操作明确地导出到外部文件系统和网络上。
4.2BSD 添加了截断系统调用,允许文件被缩短到任意偏移量。该调用主要是为了支持 Fortran 运行时库而添加的,该库的语义是随机访问文件的末尾被设置为程序最近访问该文件的位置。如果没有截断系统调用,缩短文件的唯一方法是将所需部分复制到新文件中,删除旧文件,然后将副本重命名为原始名称。除了这种算法速度慢之外,库在满文件系统上可能会失败。
一旦文件系统具有缩短文件的能力,内核就利用该能力来缩短大型空目录。缩短空目录的优势在于减少内核在创建或删除名称时搜索它们所花费的时间。
新创建的文件被分配给创建它们的进程的用户标识符和创建它们的目录的组标识符。为了保护文件提供了三级访问控制机制。这三个级别指定了文件对用户、组和其他用户的可访问性。
拥有文件的用户
拥有文件的组
其他所有人
每个访问级别都有单独的指示器,用于读取权限,写入权限和执行权限。
文件创建时长度为零,当写入时可能会增长。当文件打开时,系统会保持指向文件的指针,指示与描述符关联的文件中的当前位置。该指针可以以随机访问方式在文件中移动。通过 fork 或 dup 系统调用共享文件描述符的进程共享当前位置指针。通过独立的打开系统调用创建的描述符具有单独的当前位置指针。文件中可能有空洞。空洞是文件线性范围中的空白区域,从未写入数据。进程可以通过将指针定位到当前文件末尾并写入来创建这些空洞。在读取时,系统将空洞视为零值字节。
早期的 UNIX 系统每个文件名组件的限制为 14 个字符。这种限制通常是一个问题。例如,除了用户希望为文件提供长描述性名称的自然愿望外,形成文件名的常见方式是 basename.extension ,其中扩展名(表示文件类型,例如 C 源文件的 .c 或中间二进制对象的 .o )为一到三个字符,为基本名称留下 10 到 12 个字符。源代码控制系统和编辑器通常占用另外两个字符,作为前缀或后缀,用于它们的目的,剩下八到十个字符。很容易使用一个英文单词的 10 到 12 个字符作为基本名称(例如, multiplexer )。
在这些限制范围内保持是可能的,但是不方便甚至危险,因为其他 UNIX 系统在创建文件时接受超过限制的字符串,然后截断到限制。一个名为 multiplexer.c (已有 13 个字符)的 C 语言源文件可能有一个源代码控制文件,其中包含 s. ,生成一个与 multiplexer.ms 中包含 troff C 程序文档的源代码控制文件不可区分的文件名 s.multiplexer 。这两个原始文件的内容很容易混淆,源代码控制系统不会发出任何警告。仔细编码可以检测到这个问题,但 4.2BSD 中首次引入的长文件名几乎消除了这个问题。
为本地文件系统定义的操作分为两部分。所有本地文件系统共有的特性包括分层命名、锁定、配额、属性管理和保护。这些特性与数据存储方式无关。4.4BSD 有一个单一的实现来提供这些语义。
本地文件系统的另一部分是对存储介质上数据的组织和管理。在存储介质上布置文件内容是文件存储的责任。4.4BSD 支持三种不同的文件存储布局:
传统的伯克利快速文件系统
基于 Sprite 操作系统设计[Rosenblum&Ousterhout,1992]的日志结构文件系统
基于内存的文件系统
尽管这些文件存储的组织完全不同,但对于使用文件存储的进程来说,这些差异是无法区分的。
快速文件系统将数据组织成柱面组。根据文件系统层次结构中它们的位置,可能会一起访问的文件存储在同一个柱面组中。不太可能一起访问的文件被移动到不同的柱面组中。因此,同时写入的文件可能会被放置在磁盘的不同位置。
日志结构化文件系统将数据组织为日志。任何时候所写入的所有数据都会被聚集在一起,并写入相同的磁盘位置。数据永远不会被覆盖;而是写入一个替换旧文件的新副本。当文件系统变满且需要额外的空闲空间时,将通过垃圾回收进程来回收旧文件。
基于内存的文件系统旨在将数据存储在虚拟内存中。它用于需要支持快速但临时数据的文件系统,比如 /tmp 。基于内存的文件系统的目标是尽可能紧凑地保持存储,以最小化虚拟内存资源的使用。
最初,网络用于在一台机器与另一台机器之间传输数据。后来,它发展到允许用户远程登录到另一台机器。下一个合乎逻辑的步骤是将数据带给用户,而不是让用户去找数据 - 网络文件系统就此诞生。本地工作的用户在每次按键时不会遇到网络延迟,因此他们拥有更加响应迅捷的环境。
将文件系统带到本地计算机是最重要的主要客户端 - 服务器应用程序之一。服务器是远程机器,导出其一个或多个文件系统。客户端是导入这些文件系统的本地机器。从本地客户端的角度来看,远程挂载的文件系统会出现在文件树命名空间中,就像任何其他本地挂载的文件系统一样。本地客户端可以切换到远程文件系统中的目录,并可以读取、写入和执行该远程文件系统中的二进制文件,方式与他们在本地文件系统上执行这些操作的方式完全相同。
当本地客户端在远程文件系统上执行操作时,请求被打包并发送到服务器。服务器执行所请求的操作,并返回已请求的信息或指示请求被拒绝的错误。为了获得合理的性能,客户端必须缓存频繁访问的数据。远程文件系统的复杂性在于维护服务器及其众多客户端之间的缓存一致性。
多年来,虽然开发了许多远程文件系统协议,但在 UNIX 系统中最普遍使用的协议是网络文件系统(NFS),其协议和最广泛使用的实现是由 Sun Microsystems 完成的。4.4BSD 内核支持 NFS 协议,尽管该实现是独立于协议规范完成的[Macklem, 1994]。NFS 协议在第 9 章中描述。
终端支持标准系统 I/O 操作,以及一系列特定于终端的操作,用于控制输入字符编辑和输出延迟。最底层是控制硬件终端ports的终端设备驱动程序。终端输入根据底层通信特性处理,比如波特率,和一组软件可控参数,比如奇偶校验。
位于终端设备驱动程序之上的是提供各种程度字符处理的线路纪律。当用于交互式登录时,将选择默认行纪律。行纪律以规范模式运行;输入经过处理以提供标准的面向行的编辑功能,并且将输入逐行呈现给进程。
屏幕编辑器和与其他计算机通信的程序通常以非规范模式运行(也常称为原始模式或逐字符模式)。在此模式下,输入立即传递给读取进程且不进行解释。所有特殊字符输入处理被禁用,不执行擦除或其他行编辑处理,并且所有字符都传递给从终端读取的程序。
可以在这两个极端之间的数千种组合中配置终端。例如,一个希望异步接收用户中断的屏幕编辑器可能会启用生成信号的特殊字符并启用输出流控制,但否则运行在非规范模式;所有其他字符将会未经解释地传递到进程。
输出时,终端处理程序提供简单的格式化服务,包括
将换行符字符转换为两个字符的回车换行序列
在某些标准控制字符后插入延迟
扩展制表符
将回显的非图形 ASCII 字符显示为形式为 ^C 的两个字符序列(即 ASCII 插入符字符后跟 ASCII 字符,该字符是与 ASCII @ 字符的值偏移的字符)。
通过控制请求,这些格式化服务中的每一个都可以被进程单独禁用。
FreeBSD 中的进程间通信是通过通信域进行组织的。目前支持的域包括本地域,用于在同一台机器上执行的进程之间的通信;互联网域,用于使用 TCP/IP 协议套件进行进程之间的通信(可能在 Internet 内);ISO/OSI 协议族,用于需要运行它们的站点之间的通信;以及 XNS 域,用于使用 XEROX Network Systems(XNS)协议进行进程之间的通信。
在一个域内,通信发生在被称为套接字的通信端点之间。如第 2.6 节所述,套接字系统调用创建一个套接字并返回一个描述符;其他 IPC 系统调用在第 11 章中描述。每个套接字都有一个定义其通信语义的类型;这些语义包括可靠性、排序和防止消息重复等属性。
每个套接字都与通信协议相关联。该协议根据套接字的类型提供后者所需的语义。应用程序在创建套接字时可以请求特定协议,也可以允许系统选择适合正在创建的套接字类型的协议。
套接字可能绑定地址。套接字地址的形式和含义取决于创建套接字的通信域。在本地域中将名称绑定到套接字会导致在文件系统中创建文件。
通过套接字传输和接收的普通数据是无类型的。数据表示问题是建立在进程间通信设施之上的库的责任。除了传输普通数据外,通信域还可以支持传输和接收特殊类型的数据,称为访问权限。例如,本地域使用此功能在进程之间传递描述符。
UNIX 4.2BSD 之前的 UNIX 上的网络实现通常是通过对字符设备接口进行重载来实现的。套接字接口的一个目标是使得天真的程序能够在流式连接上无需改变即可工作。如果读取和写入系统调用未更改,则此类程序可以正常工作。因此,原始接口保持不变,并被设计成适用于流类型套接字。为更复杂的套接字增加了一个新接口,例如那些用于发送数据报的套接字,在每个发送调用中必须提供目标地址。
另一个好处是新接口非常易于移植。在伯克利提供了测试版本后不久,UNIX 供应商将套接字接口移植到了 System III(尽管 AT&T 直到 System V Release 4 发布时才支持套接字接口,而决定使用第八版流机制)。套接字接口还被移植到了许多以太网板上,如 Excelan 和 Interlan 这样的供应商,它们在 PC 市场上销售,在那些机器上网络功能过于庞大,无法在主处理器上运行。最近,套接字接口被用作微软 Windows 的 Winsock 网络接口的基础。
套接字 IPC 机制支持的一些通信领域提供对网络协议的访问。这些协议作为内核中逻辑上位于套接字软件之下的单独软件层实现。内核提供许多辅助服务,如缓冲区管理,消息路由,协议的标准化接口,以及用于各种网络协议的网络接口驱动程序的接口。
在实施 4.2BSD 时,有许多正在使用或正在开发的网络协议,每种协议都有其优势和劣势。没有明显优越的协议或协议套件。通过支持多种协议,4.2BSD 可以在伯克利环境中提供互操作性和资源共享,因为那时有各种各样的计算机。多协议支持还为未来的变化提供了可能性。今天设计用于 10 到 100 兆位每秒以太网的协议可能不足以满足明天设计用于 1 到 10 吉位每秒光纤网络的需求。因此,网络通信层被设计为支持多种协议。新协议可以添加到内核中,而不会影响对旧协议的支持。旧应用程序可以继续使用旧协议在与运行新网络协议的应用程序相同的物理网络上运行。
在 4.2BSD 中实施的第一个协议套件是 DARPA 的传输控制协议/互联网协议(TCP/IP)。CSRG 选择 TCP/IP 作为首个集成到套接字 IPC 框架中的网络,因为基于 4.1BSD 的实现可以从 DARPA 赞助的项目(Bolt,Beranek 和 Newman(BBN))中公开获得。那是一个有影响力的选择:4.2BSD 实现是这个协议套件被广泛使用的主要原因。对 TCP/IP 实现的后续性能和功能改进也被广泛采纳。 TCP/IP 实现在第 13 章中有详细描述。
4.3BSD 的发布添加了施乐网络系统(XNS)协议套件,部分建立在马里兰大学和康奈尔大学进行的工作基础上。需要此套件来连接无法使用 TCP/IP 进行通信的孤立机器。
4.4BSD 的发布添加了 ISO 协议套件,因为在美国境内外后者越来越可见。由于 ISO 协议定义了略有不同的语义,因此需要对套接字接口进行一些微小的更改以适应这些语义。这些更改是如此之处,以至于对其他现有协议的客户端是不可见的。ISO 协议还需要对 4.3BSD 内核提供的两级路由表进行广泛添加。4.4BSD 的大大扩展的路由功能包括具有可变长度地址和网络掩码的任意级别的路由。
引导机制用于启动系统运行。首先,必须将 4.4BSD 内核加载到处理器的主内存中。一旦加载完成,它必须经过初始化阶段将硬件设置为已知状态。接下来,内核必须进行自动配置,一个过程,找到并配置连接到处理器的外围设备。系统在单用户模式下开始运行,同时启动脚本进行磁盘检查并启动会计和配额检查。最后,启动脚本启动一般系统服务,将系统带到完全的多用户操作。
在多用户操作期间,进程在配置为用户访问的终端线路和网络ports上等待登录请求。当检测到登录请求时,将生成一个登录进程并进行用户验证。当登录验证成功时,将从中创建一个登录shell,用户可以从中运行其他进程。
Accetta 等人,1986 年 Mach:UNIX 开发的新内核基础" M.Accetta R.Baron W.Bolosky D.Golub R.Rashid A.Tevanian M.Young 93-113 USENIX 协会会议论文集 USENIX 协会 1986 年 6 月
Cheriton,1988 年 V 分布式系统 D. R.Cheriton 314-333 Comm ACM,31,3 1988 年 3 月
Ewens 等,1985 年突尼斯:分布式多处理器操作系统 P.Ewens D.R.Blythe M.Funkenhauser R.C.Holt 247-254 USENIX Association Conference Proceedings USENIX Association 1985 年 6 月
Gingell 等,1987 年 SunOS 中的虚拟内存体系结构 R.Gingell J.Moran W.Shannon 81-94 USENIX Association Conference Proceedings USENIX Association 1987 年 6 月
Kernighan&Pike,1984 年 UNIX 编程环境 B.W.Kernighan R.Pike Prentice-Hall Englewood Cliffs NJ 1984
Macklem,1994 年 4.4BSD NFS 实现 R.Macklem 6:1-14 4.4BSD 系统管理手册 O’Reilly&Associates,Inc. Sebastopol CA 1994
McKusick&Karels,1988 年为 4.3BSD UNIX 内核设计通用内存分配器 M. K.McKusick M. J.Karels 295-304 USENIX 协会会议论文集 USENIX 协会 1998 年 6 月
McKusick 等人,1994 年伯克利软件架构手册,4.4BSD 版 M. K.McKusick M. J.Karels S. J.Leffler W. N.Joy R. S.Faber 5:1-42 4.4BSD 程序员补充文档 O’Reilly&Associates,Inc. Sebastopol CA 1994
里奇,1988 年早期内核设计私人通信 D.M.Ritchie 1988 年 3 月
Rosenblum&Ousterhout,1992 年一种基于日志结构的文件系统的设计和实现 M.Rosenblum K.Ousterhout 26-52 ACM 计算机系统交易,10,1 计算机协会协会 1992 年 2 月
Rozier 等,1988 年 Chorus 分布式操作系统 M.Rozier V.Abrossimov F.Armand I.Boule M.Gien M.Guillemont F.Herrmann C.Kaiser S.Langlois P.Leonard W.Neuhauser 305-370 USENIX 计算系统,1,4 1988 年秋季
Tevanian, 1987 并行和分布式环境中的架构无关虚拟内存管理:Mach 方法 技术报告 CMU-CS-88-106,A.Tevanian 计算机科学系,卡内基梅隆大学,匹兹堡 PA,1987 年 12 月
FreeBSD 项目的项目模型
版权 © 2002-2005 Niklas Saers
前言
到目前为止,FreeBSD 项目已发布了许多描述不同工作部分的技术。然而,由于项目成员数量不断增加,需要一个总结项目结构的项目模型。^[1]^ 本文将提供这样一个项目模型,并捐赠给 FreeBSD 文档项目,以便与项目一起发展,从而随时反映项目的工作方式。它基于[ Saers,2003]。
我想感谢以下的人,他们花时间为我解释不清楚的事情,并校对文件。
Andrey A. Chernov ache@freebsd.org
Bruce A. Mah bmah@freebsd.org
Dag-Erling Smørgrav des@freebsd.org
Giorgos Keramidas keramida@freebsd.org
Ingvil Hovig ingvil.hovig@skatteetaten.no
Jesper Holck jeh.inf@cbs.dk
John Baldwin jhb@freebsd.org
John Polstra jdp@freebsd.org
Kirk McKusick mckusick@freebsd.org
Mark Linimon linimon@freebsd.org
Marleen Devos
Niels Jørgenssen nielsj@ruc.dk
Nik Clayton nik@freebsd.org
Poul-Henning Kamp phk@freebsd.org
Simon L. Nielsen simon@freebsd.org
项目模型是减少项目中的沟通开销的一种手段。正如[Brooks, 1995]所示,增加项目参与者的数量会呈指数级增加项目中的沟通。在过去几年中,FreeBSD 的活跃用户和提交者数量都在增加,项目中的沟通也相应增加。该项目模型将通过提供项目的最新描述来减少这种开销。
在 2002 年的 Core 选举中,Mark Murray 表示“我反对一部冗长的规则书,因为那满足了律师的倾向,与项目非常需要的技术中心相悖。”[FreeBSD, 2002B]。这个项目模型并不是为了为开发人员创造强制性规定的工具,而是作为促进协调的工具。它旨在描述项目,概述不同流程的执行方式。它是对 FreeBSD 项目如何运作的介绍。
自 2004 年 7 月 1 日起,将描述 FreeBSD 项目模型。基于 Niels Jørgensen 的论文[Jørgensen,2001],FreeBSD 的官方文件,FreeBSD 邮件列表上的讨论以及与开发人员的采访。
在提供使用术语的定义后,本文将概述组织结构(包括角色描述和沟通线路),讨论方法论模型,并在介绍用于过程控制的工具后,将呈现定义的过程。最后,它将概述 FreeBSD 项目的主要子项目。
[自由贝获得, 2002A] 第 1.2 节和 1.3 节提供了项目的愿景和架构指南。愿景是“以最大限度地尊重原始软件工具意识形态以及可用性、性能和稳定性为目标,生产可能的最佳类 UNIX 操作系统软件包。”架构指南有助于确定某个希望解决的问题是否属于项目的范围。
"活动"是项目过程中执行的工作要素[PMI,2000]。它具有输出并导向结果。这样的输出可以是另一个活动的输入,也可以是流程交付的一部分。
"过程"是一系列导向特定结果的活动。一个过程可以包含一个或多个子过程。过程的一个例子是软件设计。
“帽子”是角色的同义词。帽子在一个过程中具有一定的责任和结果。帽子执行活动。项目成员和项目外部的人应联系帽子处理哪些问题是明确规定的。
一个“结果”是流程的最终输出。这与可交付成果同义,被定义为“任何可衡量、可触及、可验证的结果、成果或项目,必须生产以完成项目或项目的一部分。通常更狭义地用于指外部可交付成果,即受项目发起人或客户批准的可交付成果” [ PMI,2000]。结果的例子包括软件、决策或报告的撰写。
当说到“FreeBSD”时,我们指的是 BSD 衍生的类 UNIX 操作系统 FreeBSD,而当说到“FreeBSD 项目”时,我们指的是项目组织。
虽然没有人拥有 FreeBSD,但 FreeBSD 组织分为核心、提交者和贡献者,并且是围绕它生活的 FreeBSD 社区的一部分。
FreeBSD 项目的结构(按降序权限排列)
核心成员
9
贡献者
318
贡献者
~3000
通过查阅 2004 年 1 月 1 日至 2004 年 12 月 31 日的 CVS 日志,已确定贡献人数;通过查阅贡献清单和问题报告,已确定贡献者人数。
FreeBSD 社区中的主要资源是其开发人员:提交者和贡献者。正是凭借他们的贡献,项目才能向前发展。常规开发人员被称为贡献者。截至 2003 年 1 月 1 日,估计有 5500 名贡献者参与该项目。
提交者是具有提交更改权限的开发人员。这些通常是最活跃的开发人员,他们愿意花时间不仅集成自己的代码,还集成那些没有此权限的开发人员提交的代码。他们还是选举核心团队的开发人员,并且可以访问封闭讨论。
该项目可以分为四个明确的独立部分,大多数开发人员将专注于 FreeBSD 的一个部分。这四个部分分别是内核开发,用户空间开发,ports 和文档。在提到基本系统时,内核和用户空间都是指的。
这个拆分会使我们的表格变成这样:
FreeBSD 项目的结构和类别中的合作者
核心成员
9
提交者
Base
164
Docs
45
Ports
166
总数
374
贡献者
~3000
每个区域的 Committer 数量是通过查看从 2004 年 1 月 1 日到 2004 年 12 月 31 日的 CVS 日志进行确定的。请注意,许多 Committer 在多个区域工作,使得实际 Committer 数量比实际 Committer 数量要高。2022 年 6 月活跃的独特 Committer 总数为 317。
Committers 分为三组:只关注项目的一个区域(例如文件系统)的 Committer,只涉及一个子项目的 Committer,以及向代码不同部分(包括子项目)进行提交的 Committer。由于一些 Committer 在不同部分工作,因此表中 Committer 部分的总数比上表中的要高。
内核是 FreeBSD 的主要构建模块。虽然用户态应用程序受到其他用户态应用程序中的错误的保护,但整个系统对内核中的错误是脆弱的。这与内核中大量的依赖项以及不容易看到内核更改的所有后果相结合,要求开发人员对内核有相对全面的理解。内核中的多个开发工作还需要比用户态应用程序更紧密的协调。
用户空间提供了被称为用户界面的核心实用工具,识别 FreeBSD 的接口,包括用户界面、共享库和外部接口,用于连接客户端。目前,有 162 人参与用户空间的开发和维护,其中许多人是自己代码部分的维护者。维护将在维护部分讨论。
文档由 FreeBSD 文档项目处理,包括围绕 FreeBSD 项目的所有文档,包括网页。在 2004 年,有 101 人向 FreeBSD 文档项目提交了内容。
Ports 是在 FreeBSD 上使软件包正确构建所需的元数据集合。一个 port 的示例是 Web 浏览器 Mozilla 的 port。它包含关于从哪里获取源代码、应用哪些修补程序以及如何在系统上安装软件包的信息。这使得自动化工具可以获取、构建和安装软件包。截至本文撰写时,有超过 12600 个 ports 可用,其中涵盖了从 Web 服务器到游戏、编程语言以及现代计算机上使用的大多数应用类型。Ports 将在“Ports 子项目”部分进一步讨论。
FreeBSD 中写代码的人没有定义的模型。然而,Niels Jørgenssen 提出了一个关于如何将编写的代码整合到项目中的模型。
Jørgenssen 的变革整合模型
代码
审查
复查
预提交测试
代码
预提交测试
发布版本开发
代码
开发版本发布
并行调试
代码
并行调试
生产发布
代码
生产发布
代码
“开发版本”是 FreeBSD-CURRENT(“-CURRENT”)分支,“生产版本”是 FreeBSD-STABLE 分支(“-STABLE”)[Jørgensen,2001]。
这是一个关于变更的模型,显示了在编码后,开发人员寻求社区审查并尝试将其与自己的系统集成。在将变更集成到名为 FreeBSD-CURRENT 的开发版本后,它会被 FreeBSD 社区中的许多用户和开发人员测试。经过足够的测试后,它将被合并到名为 FreeBSD-STABLE 的生产版本中。除非每个阶段都成功完成,开发人员需要返回并在代码中进行修改,然后重新启动流程。将变更与-CURRENT 或-STABLE 集成称为提交。
Jørgensen 发现大多数 FreeBSD 开发人员是独立工作的,这意味着许多开发人员在不同的正在进行的开发工作中并行使用这个模型。开发人员也可以同时处理多个变更,因此当他们在等待审查或其他人测试他们的一个或多个变更时,他们可能正在编写另一个变更。
每个提交代表一个增量,这是一个大规模的增量模型。实际上,提交是如此频繁,以至于在一年内^[ 3]^,共进行了 85427 次提交,平均每天 233 次提交。
在 Jørgensen 模型中的 "code" 范围内,每个程序员都有自己的工作方式,并遵循自己的开发模型。这个范围完全可以称为 "development",因为它包括需求收集与分析、系统和详细设计、实施和验证。然而,这些阶段的唯一输出是源代码或系统文档。
从分步模型(如瀑布模型)的角度来看,其他范围可以看作是进一步的验证和系统集成。这个系统集成对于查看社区是否接受变更也很重要。在代码提交之前,开发人员可以自由选择与项目其他部分沟通的程度。为了使 -CURRENT 作为缓冲区(这样可以撤销那些有未发现缺陷的好主意),在合并到 -STABLE 之前,提交在 -CURRENT 中的最短时间应为 3 天。这样的合并称为 MFC(从 CURRENT 合并)。
需要注意的是 "change" 一词。大多数提交不包含根本性的新增功能,而是维护更新。
该模型的唯一例外是针对安全修复和在当前分支中已弃用的功能所做的更改。在这些情况下,更改可以直接提交到稳定分支。
除了许多参与该项目的人之外,FreeBSD 项目还有许多相关项目。这些项目要么是开发全新功能的项目,要么是子项目,或者是项目的成果被整合到 FreeBSD 中^[ 4]^。这些项目与 FreeBSD 项目的关系与常规开发工作类似:它们生成的代码会与 FreeBSD 项目集成。然而,其中一些项目(如 Ports 和文档)有特权直接适用于当前分支和稳定分支。
关于设计的标准并不存在,设计也没有集中存储在一个仓库中。主要设计是 4.4BSD 的设计^[ 5]^。由于设计属于 Jørgenssen 模型中的"代码"部分,每个开发人员或子项目可以自行决定如何进行设计。即使设计应该存储在中央仓库中,设计阶段的输出也将用处有限,因为各种方法的差异将使它们很少甚至根本无法互操作。对于项目的整体设计,项目依赖于子项目之间协商适当接口,而不是强行规定接口。
FreeBSD 的发布最好通过一棵树来说明,其中有许多分支,每个主要分支代表一个主要版本。次要版本由主要分支的分支代表。
在下面的发布树中,沿特定方向依次跟随的箭头表示一个分支。具有实线和菱形的框表示官方发布。具有虚线的框表示该时期的开发分支。安全分支由椭圆形表示。 菱形不同于框,因为它们代表一个分岔口,表示一个分支分成两个分支的地方,其中一个分支变成子分支。 例如,在 4.0-RELEASE 时,4.0-CURRENT 分支分成 4-STABLE 和 5.0-CURRENT。 在 4.5-RELEASE 时,该分支分叉出一个名为 RELENG_4_5 的安全分支。
图 1. FreeBSD 发行树
…
3.0 当前(开发分支)
Releng 3 branches: 3.0 Release to 3.5 Release, leading to 3.5.1 Release and the subsequent 3 Stable branch
4.0 Current (development branch)
3.1 Release
Releng 4 branches: 4.1 Release to 4.6 Release (and 4.6.2 Release), then 4.7 Release to 4.11 Release (all starting at 4.3 Release also leading to a Releng_4_n branch), and the subsequent 4 Release branch
5.0 Current (development branch)
4.0 Release
Releng 5 branches: 5.0 发布到 5.4 发布(除了 5.0 和 5.3 之外,还导致 Releng_5_n 分支),以及随后的 5 发布分支
6.0 当前(开发分支)
5.3 发布
…
最新的-CURRENT 版本始终被称为-CURRENT,而最新的-STABLE 版本始终被称为-STABLE。在这个图中,-STABLE 指的是 4-STABLE,而-CURRENT 指的是 5.0-CURRENT,接下来是 5.0-RELEASE。【FreeBSD,2002E】
“主要版本”总是从-CURRENT 分支制作。然而,-CURRENT 分支在那个时候不需要分叉,而可以专注于稳定。一个例子是,在 3.0-RELEASE 之后,3.1-RELEASE 也是-CURRENT 分支的延续,并且直到这个版本发布和 3-STABLE 分支被分叉之前,-CURRENT 才不会成为真正的开发分支。当-CURRENT 重新变成开发分支时,只能接下来是一个主要版本。预计 5-STABLE 将在 5.3-RELEASE 左右从 5.0-CURRENT 分叉。直到 5-STABLE 被分叉,开发分支才会被标记为 6.0-CURRENT。
从主要版本发布后的-CURRENT 分支或者-STABLE 分支制作一个"次要版本"。
从 4.3-RELEASE^[ 6]^开始,当制作了一个次要版本后,它就变成了一个"安全分支"。这是为那些不想跟随-STABLE 分支及其可能提供的新功能/更改,而是需要一个绝对稳定的环境,只更新以实施安全更新的组织而设立的。^[ 7]^
对安全分支的每次更新称为"补丁级别"。对于每项安全增强措施,补丁级别编号都会增加,这样跟踪该分支的人就可以看到他们已经实施了哪些安全增强措施。在存在特别严重的安全漏洞的情况下,可以从安全分支制作一个全新的发布版本。一个例子是 4.6.2-RELEASE。
总之,FreeBSD 的开发模型可以被看作是以下树:
图 2. 总体开发模型
FreeBSD 开发的树,其中进行持续的开发工作和持续集成。
该树象征着发布的版本,其中主要版本衍生出新的主分支,次要版本是主分支的版本。顶部分支是-CURRENT 分支,所有新开发都集成在这里,-STABLE 分支是直接在其下面的分支。在-STABLE 分支下面是旧的、不受支持的版本。
开发工作的云彩笼罩着项目,开发人员使用他们认为合适的开发模型。他们的工作成果随后被集成到-CURRENT 中,在那里进行并行调试,最终从-CURRENT 合并到-STABLE。安全修复程序从-STABLE 合并到安全分支。
许多提交者都有特定的责任领域。这些角色被称为帽子。这些帽子可以是项目角色,比如公共关系官,或者是某个代码区域的维护者。因为这是一个人们自愿投入业余时间的项目,担任帽子角色的人并不总是可用的。因此,他们必须任命一名代理人,在他们不在时可以执行帽子的角色。另一种选择是由一个团队担任该角色。
这些帽子中许多并没有正式化。正式化的帽子有一份宪章,说明帽子的确切目的以及其特权和责任。编写这些宪章是项目的一个新部分,因此尚未为所有帽子完成。这些帽子描述并不是这样的正式化,而是该角色的摘要,其中包含到可用的宪章和联系地址的链接。
贡献者以开发者、作者、发送问题报告或以其他方式促进项目进展的形式为 FreeBSD 项目做出贡献。贡献者在 FreeBSD 项目中没有特权。[FreeBSD,2002F]
具备必要权限向存储库添加其代码或文档的人。过去 12 个月内曾提交过的许可者。[ FreeBSD,2000A] 活跃的许可者是在那段时间内平均每月提交一次的许可者。
值得注意的是,从技术上讲,没有任何障碍可以阻止某人一旦获得对主项目或子项目的提交权限,就在该项目源代码的部分中进行提交,即使许可者没有明确获得修改权限的这些部分。然而,当想要对许可者以前未涉足的部分进行修改时,他们应该阅读日志以查看此领域发生了什么,并且还应该阅读 MAINTAINERS 文件,看看此部分的维护人员是否对代码的更改有任何特殊要求。
核心团队由提交者从提交者池中选举产生,并担任 FreeBSD 项目的董事会。它将积极贡献者晋升为提交者,分配人员到明确定义的职责,并是涉及项目发展方向的决策的最终仲裁者。截至 2004 年 7 月 1 日,核心团队由 9 名成员组成。选举每两年举行一次。
维护者负责确定允许输入代码的范围,并在出现关于代码的分歧时拥有最终决定权。这涉及积极的工作,旨在激发贡献,并在审查提交时进行反应性工作。
FreeBSD 源代码附带一个 MAINTAINERS 文件,其中包含每个维护者希望如何进行贡献的一句总结。拥有这些通知和联系信息使开发人员可以专注于开发工作,而不必被卡在一段时间内维护者不可用的缓慢通讯中。
如果维护者长时间不可用,并且其他人做了大量工作,则可能会在未经维护者批准的情况下更改维护者身份。这是基于维护者身份应该得到证明,而不是宣布的立场。
代码的维护者不是作为一个团体来承担的角色。
FreeBSD 项目中的官方角色更多或少是正式的并且主要是管理角色。他们对自己的领域有权威和责任。以下列表显示了责任线,并提供了每个角色的描述,包括持有者。
FreeBSD 文档项目架构师负责为文档项目中的提交者定义和跟踪文档目标,并监督他们。
由 DocEng 团队 doceng@FreeBSD.org 担任的帽子。 DocEng 宪章。
邮件管理员负责将邮件正确发送到提交者的电子邮件地址。他们还负责确保邮件列表正常工作,并应采取措施防止可能的邮件中断,如设置垃圾邮件、垃圾邮件和病毒过滤器。
目前由邮件管理员团队 postmaster@FreeBSD.org 担任。
发布工程团队的责任是
为官方发布设置、发布和遵循发布时间表
记录和规范发布工程流程
创建和维护代码分支
与 Ports 和文档团队协调,确保更新的软件包和文档随新版本一起发布
与安全团队协调,以确保未完成的发布不受最近披露的漏洞影响。
有关开发过程的更多信息,请参阅发布工程部分。
帽子由:发布工程团队 re@FreeBSD.org 担任。发布工程宪章。
公共关系与公司联络的职责是:
当发生对 FreeBSD 项目重要的事情时,发布新闻声明。
作为与 FreeBSD 项目密切合作的公司的官方联系人。
采取措施在开源社区和企业界内推广 FreeBSD。
处理“freebsd-advocacy”邮件列表。
这顶帽子目前没有人佩戴。
安全官员的主要责任是协调与安全社区和 FreeBSD 项目中其他人员的信息交流。安全官员还负责在报告安全问题时采取行动,并在涉及安全时促进积极的开发行为。
由于担心漏洞信息在补丁发布之前泄露给恶意人士,只有安全官员,包括一名官员,一名副手和两名核心团队成员才能接收有关安全问题的敏感信息。但是,为了创建或实施补丁,安全官员依靠安全官员团队 security-team@FreeBSD.org 来协助完成工作。
源代码库管理器是唯一被允许直接修改存储库而不使用 Git 工具的人。他们有责任确保存储库中出现的技术问题得到迅速解决。源代码库管理器有权回滚提交,以解决 Git 技术问题。
由 FreeBSD.org 的 Source Repository Manager clusteradm 持有的帽子。
选举管理器负责核心选举过程。该管理器负责运行和维护选举系统,并且在选举过程中发生较小的意外事件时是最终权威。对于重大意外事件,必须与核心团队讨论。
只在选举期间佩戴的帽子。
网站管理帽子负责协调在全球镜像站点上更新网页的推出,为主要网站的整体结构以及运行在其上的系统。管理人员需要与 FreeBSD 文档项目协调内容,并充当“www”树的维护者。
由 FreeBSD 网站管理员 www@FreeBSD.org 所持有的帽子。
Ports 管理员充当 The Ports 子项目与核心项目之间的联络人,所有项目请求都应发送给 ports 管理员。
由 FreeBSD.org 的 portmgr@管理团队持有的帽子。 Portmgr 宪章。
负责确保 FreeBSD 遵守其承诺的标准,跟踪这些标准的发展并通知 FreeBSD 开发人员重要变化,使他们能够积极参与并减少标准更新与 FreeBSD 合规性之间的时间。
目前由 Garrett Wollman wollman@FreeBSD.org 持有的帽子。
核心秘书的主要责任是撰写草案并发布最终的核心报告。秘书还保留核心议程,从而确保没有问题悬而未决。
目前由 René Ladan rene@FreeBSD.org持有的帽子。
缺陷管理员负责确保维护数据库正常运行,条目被正确分类,并且没有无效条目。他们监督缺陷猎手。
目前由 Bugmeister 团队 bugmeister@FreeBSD.org 持有的帽子。
捐赠联络官的任务是将开发人员的需求与愿意捐赠的个人或组织匹配起来。
由 FreeBSD.org 的捐赠联络办公室捐赠的帽子。捐赠联络宪章。
(也称为“FreeBSD 集群管理员”)
管理团队由负责管理项目所依赖的计算机以便其分布式工作和沟通同步的人员组成。主要由那些可以接触服务器的人员组成。
Hat 由:管理员团队 admin@FreeBSD.org 持有。
最初负责提交问题报告的人。
一个人,要么找到合适的人解决问题,要么关闭 PR,如果它是一个重复的或者其他方面不是一个有趣的。
导师是一个 committer,他自己介绍一个新的 committer 加入项目,无论是确保新的 committer 的设置是有效的,这位新的 committer 知道他们工作所需的可用工具,还是这位新的 committer 知道他们在行为方面期望他们做什么。
外部代码来自的个人或组织,以及发送补丁的对象。
邮件列表上发布了审查请求的人。
以下部分将描述定义的项目流程。这些流程未涉及的问题将根据类似情况的惯例进行临时处理。
核心团队有责任向贡献者授予和移除提交权限。这只能通过核心邮件列表上的投票来完成。ports 和文档子项目可以向在这些项目上工作的人授予提交权限,但迄今为止尚未取消此类权限。
通常,贡献者由提交者推荐给核心。贡献者或外部人员联系核心要求成为提交者并不被认可,通常会被拒绝。
如果开发人员的特定兴趣领域可能与其他提交者的维护领域重叠,那么将征求这些维护者的意见。然而,通常是这位提交者推荐这位开发人员。
给予贡献者提交者身份时,他们会被分配一位导师。一般情况下,推荐新提交者的提交者会自愿成为新提交者的导师。
当贡献者获得他们的提交权限时,要求核心秘书、Ports 管理员或 nik@freebsd.org 发送一封通过 Pretty Good Privacy 签名的电子邮件至 admins@freebsd.org、分配的导师、新提交者和核心,确认新账户的批准。然后,导师会收集新提交者的密码行、Secure Shell 公钥和 PGP 密钥,并将它们发送给管理员。当新账户被创建时,导师会激活提交权限,并指导新提交者完成初始流程的其余部分。
图 3. 过程摘要:添加新的提交者
当贡献者发送一段代码时,接收提交者可以选择推荐给予贡献者提交权限。如果他们向核心推荐此事,核心将对此推荐进行投票。如果投票结果为赞成,导师将被指定为新的提交者,并且新的提交者必须将其详细信息发送给管理员以创建帐户。之后,新的提交者就可以进行第一次提交了。按照传统,这是通过将他们的姓名添加到提交者列表来完成的。
请记住,提交者被视为在过去 12 个月内提交过代码的人。然而,只有在 18 个月的不活动之后,提交权限才有资格被撤销。[FreeBSD,2002 年] 然而,没有自动程序来执行此操作。有关不是由时间触发的提交权限的反应,请参见第 1.5.8 节。
图 4. 过程概述:移除提交者
当 Core 决定清理提交者列表时,他们会检查过去 18 个月内没有进行提交的人员。没有提交的提交者会被撤销提交权限,并由管理员删除其账户。
提交者也可以请求撤销其提交权限,如果他们由于某种原因不再积极参与项目。在这种情况下,如果提交者提出要求,Core 也可以在以后恢复其提交权限。
这个过程中的角色:
[ 自由的 BSD,2000A ] [ 自由的 BSD,2002H ] [ 自由的 BSD,2002I ]
提交新代码或修改过的代码是 FreeBSD 项目中最常见的过程之一,通常会发生多次。提交代码只能由“committer”完成。Committer 可以提交自己编写的代码、提交给他们的代码,或通过问题报告提交的代码。
当开发人员编写的代码不太简单时,他们应该向社区寻求代码审查。这是通过发送电子邮件到相关列表请求审查来完成的。在将代码提交审查之前,他们应确保它与整个代码树编译正确,并且所有相关的测试都运行。这被称为“预提交测试”。收到贡献的代码后,应由提交者审查并以同样的方式进行测试。
当对来自外部供应商贡献的源代码进行更改时,维护者应确保将补丁贡献回供应商。这符合开源哲学,使得与外部项目保持同步变得更容易,因为补丁不必每次发布新版本时重新应用。
在代码已经可以审查并且不需要进一步更改之后,代码将提交到开发分支-CURRENT。如果更改也适用于-STABLE 分支或其他分支,则提交者会设置一个“从当前合并”(“MFC”)倒计时。在提交者设置 MFC 时选择的天数过后,将自动向提交者发送一封电子邮件,提醒他们将其提交到-STABLE 分支(可能也适用于安全分支)。只有安全关键更改才应合并到安全分支。
延迟提交到 -STABLE 和其他分支,可以进行“并行调试”,其中提交的代码在各种配置上进行测试。这使得对 -STABLE 的更改包含更少的错误,从而赋予分支其名称。
图 5. 流程摘要:提交者提交代码
当一名提交者编写了一段代码并希望提交它时,他们首先需要确定它是否足够简单,可以在没有事先审查的情况下提交,还是应该先由开发者社区审查。如果代码很简单或已经经过审查,并且提交者不是维护者,则在继续之前应该咨询维护者。如果代码是由外部供应商贡献的,则维护者应创建一个发送回供应商的补丁。然后提交代码,由用户部署。如果他们发现代码有问题,这将被报告,提交者可以继续编写补丁。如果供应商受到影响,他们可以选择实施或忽略该补丁。
图 6. 过程摘要: 贡献者提交代码
当贡献者进行代码贡献时的区别在于他们通过 Bugzilla 接口提交代码。维护者会审查代码并进行提交。
此过程中包括的帽子有:
[FreeBSD, 2001] [Jørgensen, 2001]
核心选举至少每两年举行。^[8]^ 选举产生九名核心成员。如果核心成员人数低于七人,将进行新的选举。如果至少 1/3 的活跃提交者要求,也可以进行新的选举。
当选举即将进行时,核心至少提前 6 周宣布,并任命选举经理负责选举工作。
只有提交者可以被选入核心。候选人需要在选举开始前至少一周提交他们的候选资格,但可以在投票开始前完善自己的陈述。他们将列在候选人名单中。在撰写选举声明时,候选人必须回答选举经理提出的几个标准问题。
在选举期间,严格遵循提交者必须在过去 12 个月内提交过的规定。只有这些提交者有资格投票。
在投票时,提交者可以支持最多九名候选人中的一人。投票在四周内进行,提醒将发布在“developers”邮件列表上,该列表对所有提交者开放。
选举结果将在选举结束后一周公布,新核心团队将在结果发布后一周上任。
如果投票出现平局,将由新选举产生的核心成员来解决。
投票结果和候选人声明会被归档,但这些档案不会公开。
图 7。流程摘要:核心选举
核心团队宣布选举并选出一位选举经理,后者准备选举,准备就绪后,候选人可以通过提交自己的声明来宣布自己的候选资格。然后提交者进行投票。投票结束后,选举结果将被宣布,新的核心团队将上任。
核心选举中的帽子有:
[FreeBSD, 2000A] [FreeBSD, 2002B] [FreeBSD, 2002G]
在项目中,有正在开发新功能的子项目。这些项目通常由一个人完成[Jørgensen, 2001]。每个项目可以自由组织开发方式。然而,当项目合并到-CURRENT 分支时,必须遵循项目指南。当代码在-CURRENT 分支中经过充分测试并被认为足够稳定且与-STABLE 分支相关时,它将被合并到-STABLE 分支。
项目的需求由开发人员的愿望、社区的直接请求(通过邮件、问题报告)、用于功能开发的商业资助或科学界的贡献确定。属于开发人员责任范围的愿望将交给该开发人员,他们在请求和愿望之间优化自己的时间。一个常见的做法是通过项目维护一个 TODO 列表。除非有人自愿承担责任,否则所有不属于某人责任范围的请求都会被收集在 TODO 列表上。所有请求、它们的分发和后续处理都由 Bugzilla 工具处理。
需求分析以两种方式进行。讨论进来的请求在邮件列表中进行,既在主项目内部,也在请求所属的子项目或由请求引发的子项目中进行。此外,子项目上的个人开发人员将评估请求的可行性,并确定它们之间的优先级。除了讨论的存档外,此阶段没有创造出合并到主项目的结果。
由于个体开发人员根据他们发现的有趣、必要或资助开发的基础对请求进行优先级排序,因此没有整体策略或优先考虑哪些请求作为需求,并跟踪其正确实施。但是,大多数开发人员对哪些问题更重要具有一些共享的愿景,并且他们可以向发布工程团队寻求指导。
项目的验证阶段是双重的。在将代码提交给当前分支之前,开发人员请求同行审查其代码。这种审查在很大程度上是通过功能测试进行的,但代码审查也很重要。当代码提交到分支时,将进行更广泛的功能测试,这可能会触发进一步的代码审查和调试,应代码行为与预期不符。这第二种验证形式可以被视为结构验证。虽然子项目本身可以编写形式测试,如单元测试,但这些测试通常不会被主项目收集,并且通常在将代码提交到当前分支之前被删除。 ^ [9] ^
对于项目来说,最好是对源代码的每个领域都至少有一个了解该领域的人。 代码的某些部分有指定的维护者。 其他部分有事实上的维护者,系统的某些部分没有维护者。 维护者通常是来自编写和集成代码的子项目的人,或者是将其从为其编写的平台迁移过来的人。 维护者的工作是确保代码与代码所来自的项目同步,如果它是贡献的代码,那么应用社区提交的补丁或编写修复已发现的问题。
放入 FreeBSD 项目的主要工作量是维护。 [Jørgensen, 2001] 绘制了一个显示变更生命周期的图。
乔根森的变革整合模型
代码
审查
复习
预提交测试
代码
预提交测试
开发发布
代码
开发版本
并行调试
代码
并行调试
产品发布
代码
生产发布
代码
这里“开发发布”指的是-CURRENT 分支,而“生产发布”指的是-STABLE 分支。“预提交测试”是指在同事开发人员受邀进行功能测试或尝试代码以确定子项目状态时进行的测试。“并行调试”是指在-CURRENT 分支中包含代码时可以触发更多审查和调试的功能测试。
在撰写本文时,该项目有 269 位贡献者。当他们向一个分支提交更改时,这构成了一个新版本。社区中的用户通常会跟踪特定分支。新版本的立即存在使得变更立即广泛可用,并允许社区快速反馈。这也使得社区对他们重要的问题有了他们期望的响应时间。这使得社区更加投入,从而获得更多和更好的反馈,进而促进更多的维护,最终应该创造出一个更好的产品。
在对树的某些部分进行更改之前,如果该部分的历史对于提交者来说是未知的,提交者需要阅读提交日志,了解为什么某些功能实现的方式是这样的,以免犯以前已经考虑过或解决过的错误。
在 FreeBSD 10 之前,FreeBSD 包含一个名为 send-pr 的问题报告工具。问题包括 bug 报告、功能请求、功能增强以及通知项目中包含的外部软件的新版本。尽管 send-pr 可用,但鼓励用户和开发人员使用我们的问题报告表单提交问题。
问题报告被发送到一个电子邮件地址,然后插入到问题报告维护数据库中。Bugbuster 对问题进行分类,并将其发送到项目内的正确组或维护者。一旦有人对报告负责,报告就会被分析。这个分析包括验证问题并为问题想出解决方案。通常需要从报告发起者或甚至从 FreeBSD 社区获得反馈。一旦为问题制作了补丁,可能会要求发起者尝试。最后,工作中的补丁被集成到项目中,并在适用的情况下进行文档化。然后,它按照维护部分中描述的常规维护周期进行。问题报告可能处于以下状态之一:打开、分析、反馈、已打补丁、暂停和关闭。暂停状态是指由于缺乏信息或由于任务需要太多工作而目前没有人在处理时无法进展。
图 8. 过程摘要:问题报告
报告发起者报告问题。然后由错误修复者对问题进行分类,并交给正确的维护者。他们验证问题,并与报告发起者讨论问题,直到他们获得足够的信息来创建一个可行的补丁。然后提交此补丁,并关闭问题报告。
此过程中包括的角色有:
[ FreeBSD,2002 年 C ]。[ FreeBSD,2002 年 D ]
自 2001 年起,FreeBSD 确立了一系列开发者应遵守的规则。然而,规则偶尔会被违反。以下规定旨在针对不当行为做出反应。它们明确了会导致开发者提交权限暂时中止多长时间的行为。
未经发布工程团队批准在代码冻结期间提交代码 - 2 天
在未经批准的情况下承诺到安全分支 - 2 天
提交战争 - 所有参与方需 5 天
无礼或不当行为 - 5 天
【Lehey,2002】
为了让停职生效,任何单个核心成员都可以在在“核心”邮件列表上讨论之前实施停职。在核心成员经过 2/3 的投票通过之后,惯犯可能会受到更严厉的惩罚,包括永久取消提交权限。(然而,后者总是被视为最后的选择,因为它固有地会引起争议。)所有的停职都会发布到“开发者”邮件列表上,这是一个只开放给提交者的列表。
很重要的是,您不能因为技术错误而被停职。所有的惩罚都来源于违反社交礼仪。
在这个过程中涉及到的帽子:
FreeBSD 项目设有一个发布工程团队,一个主要的发布工程师负责创建能够通过网络提供给用户社区或在零售店销售的 FreeBSD 版本。由于 FreeBSD 在多个平台上都可用,并且针对不同架构的发布同时可用,因此该团队每个架构都有一个负责人。此外,团队中还有负责协调质量保证工作、构建软件包集以及更新文档集的角色。在提到发布工程师时,指的是发布工程团队的代表。
当一个版本发布即将到来时,FreeBSD 项目会有所变化。制定包含功能冻结和代码冻结、发布临时版本以及最终版本的发布时间表。功能冻结意味着不允许在未经发布工程师明确同意的情况下提交新功能到分支。代码冻结意味着不允许在未经发布工程师明确同意的情况下提交代码更改(例如修复错误)。这种功能冻结和代码冻结被称为稳定阶段。在发布过程中,发布工程师有完全的权限将代码回滚到旧版本,从而“撤消”变更,如果发现这些变更不适合包含在发布中。
有三种不同类型的发布:
.0 发布是主要版本的第一个发布。这些是 CURRENT 分支的分支,由于 CURRENT 分支的不稳定性,具有显着更长的发布工程周期
.X 发布是 STABLE 分支的发布。它们计划每 4 个月发布一次。
.X.Y 发行版是遵循 .X 分支的安全发布版。只有在自上一个分支发布以来合并了足够的安全修复时才会发布。很少包含新功能,安全团队在这方面比常规发布更加参与。
对于 -STABLE- 分支的发布,发布过程在预期发布日期前的 45 天开始。在第一阶段,即前 15 天,开发人员将他们在 -CURRENT 中想要包含在发布版中的更改合并到发布分支中。当此期间结束时,代码进入为期 15 天的代码冻结阶段,在此阶段只允许进行错误修复、文档更新、与安全相关的修复和较小的设备驱动程序更改。这些更改必须事先获得发布工程师的批准。在最后 15 天期间开始时,将创建一个发布候选版供广泛测试。在此期间不太可能允许更新,除非是重要的错误修复和安全更新。在这最后阶段,所有发布都被视为发布候选版。在发布过程结束时,将创建一个带有新版本号的发布版,包括网站上的二进制发行版和 CD-ROM 镜像的创建。但是,在发送到邮件列表 freebsd-announce 的 Pretty Good Privacy 签名消息之前,发布不被视为“真正发布”;在发送 PGP 签名消息之前,任何标记为“发布”的内容可能仍在进行中,并可能在发送 PGP 签名消息之前发生变化。 ^[ 11]^。
-CURRENT-分支的发布(即以".0"结尾的所有发布)非常相似,但时间跨度是原来的两倍长。发布前 8 周开始公布发布时间表。进入发布流程两周后,启动功能冻结,性能调整应保持最低限度。发布前四周,官方的测试版发布。发布前两周,代码正式分支为新版本。该版本被赋予发布候选状态,与-STABLE 的发布工程一样,发布候选的代码冻结是加固的。然而,主开发分支上的开发可以继续。除了这些差异,发布工程流程是相似的。
.0 版本进入自己的分支,主要面向早期采用者。然后该分支经历稳定期,直到发布工程团队决定满足了稳定性要求,该分支才变为-STABLE,而-CURRENT 则针对下一个主要版本。尽管大多数情况下是.1 版本,但这并非必须。
大多数发布是在被认为距离上一个发布足够长的日期时进行的。设定每 18 个月进行一次主要发布和每 4 个月进行一次次要发布的目标。用户社区已经非常明确地表示,安全性和稳定性不能被自我设定的截止日期和目标发布日期所牺牲。为了避免时间滞后对安全性和稳定性问题造成过长影响,提交更改到-STABLE 时需要额外的纪律。
制定发布时间表
功能冻结
代码冻结
制作分支
发布候选版
稳定发布(根据需要反复执行上一步骤;当发布被认为稳定时,继续下一步)
构建软件包
警告镜像
发布版本
[FreeBSD,2002 年]
用于支持开发过程的主要支持工具包括 Bugzilla、Mailman 和 OpenSSH。这些是外部开发的工具,通常在开源世界中被广泛使用。
Git 是处理多个文本文件版本和跟踪谁提交了什么更改以及为什么的系统。一个项目位于一个“仓库”中,不同的版本被视为不同的“分支”。
Bugzilla 是一个维护数据库,由一组工具组成,用于在中央站点跟踪错误。它支持发送和处理错误的错误跟踪过程,以及查询和更新数据库和编辑错误报告。该项目使用其 Web 界面将“问题报告”发送到项目的中央 Bugzilla 服务器。提交者还拥有 Web 和命令行客户端。
Mailman 是一个自动化邮件列表管理程序。FreeBSD 项目使用它来运行 16 个通用列表,60 个技术列表,4 个限制列表和 5 个包含 Git 提交日志的列表。它还用于 FreeBSD 社区中其他人和项目设置和使用的许多邮件列表。通用列表是面向公众的列表,技术列表主要用于特定兴趣领域的开发,封闭列表用于内部沟通,不面向公众。项目中大部分通信都通过这 85 个列表进行[FreeBSD,2003A,附录 C]。
相当好的隐私保护,更为人熟知的是 PGP,是一种使用公钥架构的加密系统,允许人们进行数字签名和/或加密信息,以确保两方之间的安全通信。在发送信息给多个接收者时,会使用签名,这样他们可以在接收之前验证信息没有被篡改。在 FreeBSD 项目中,这是确保信息由声称撰写的人而非在传输过程中被更改的主要手段。
安全 Shell 是一种用于安全登录到远程系统并在远程系统上执行命令的标准。它允许建立和保护两个涉及系统之间的其他连接,称为隧道。这个标准有两个主要版本,只有版本二被用于 FreeBSD 项目。该标准最常见的实现是 OpenSSH,它是项目主要发行版的一部分。由于其源代码更新的频率比 FreeBSD 发行版更快,最新版本也可以在 ports 树中找到。
子项目是为了减少协调开发人员组的沟通量而形成的。当一个问题领域被充分隔离时,大多数沟通将在致力于问题的小组内部进行,相较于未被隔离的组,与他们交流的沟通会更少。
一个 "port" 是一组元数据和补丁,它们需要在 FreeBSD 系统上正确获取、编译和安装外部软件。 ports 的数量以惊人的速度增长,如下图所示。
1995 年至 2022 年间新增的 ports 数量
镜像::portsstatus.svg
[fig-ports]显示了 1995 年至 2022 年间 FreeBSD 可用的 ports 数量。看起来曲线首先呈指数增长,然后从 2001 年中期到 2007 年中期以每年约 2000 个 ports 的速度线性增长,然后增长速度变慢。
由于 port 描述的外部软件经常在持续开发中,维护 ports 所需的工作量已经很大,并且正在增加。这导致 FreeBSD 项目的 ports 部分拥有更加强大的结构,并且越来越成为 FreeBSD 项目的一个子项目。
Ports 有自己的核心团队,由 Ports 经理领导,该团队可以任命提交者,无需经过 FreeBSD 核心团队的批准。与 FreeBSD 项目不同,ports 子项目包含许多活跃的维护者,他们并非提交者,因此很多维护工作并不一定会获得提交权限。
与主项目不同,ports 树没有分支。FreeBSD 的每个发布版本都遵循当前 ports 集合,因此提供了关于程序位置和构建方法的最新信息。然而,这意味着对系统有依赖的 port 可能需要根据运行的 FreeBSD 版本的不同而有所变化。
由于 ports 存储库没有分支,无法保证任何 port 能在除了-CURRENT 和-STABLE 之外的其他版本上运行,尤其是旧的次要发布版本。既没有基础设施,也没有志愿者时间来保证这一点。
为了沟通的效率,依赖于 Ports 的团队,如发布工程团队,拥有他们自己的 ports 联络人。
FreeBSD 文档项目始于 1995 年 1 月。从最初的一个项目负责人、四名团队领导和 16 名成员,现在他们一共有 44 名提交者。文档邮件列表的成员数刚好不到 300 人,表明围绕它有一个相当大的社区。
文档项目的目标是为 FreeBSD 项目提供良好且有用的文档,从而使新用户更容易熟悉该系统,并为用户详细介绍高级功能。
文档项目的主要任务是在“FreeBSD 文档集”中处理当前项目,并将文档翻译成其他语言。
像 FreeBSD 项目一样,文档也分为相同的分支。这样做是为了保持每个版本的文档始终更新。只有文档错误才在安全分支中得到纠正。
像 ports 子项目一样,文档项目可以在没有 FreeBSD 核心批准的情况下任命文档委员。[ FreeBSD,2003B]。
文档项目有一个入门指南。这既用于向新项目成员介绍标准工具和语法,也用作在项目上工作时的参考。
[布鲁克斯,1995]弗雷德里克 P.布鲁克斯。版权 ©1975 年,1995 年皮尔逊教育有限公司。0201835959。Addison-Wesley Pub Co.神话般的人月。软件工程专题(第二版)。
[Saers,2003]尼克拉斯·萨尔斯。版权 ©2003 年。FreeBSD 项目的项目模型。科学学位论文。http://niklas.saers.com/thesis。
[Jørgensen,2001]Niels Jørgensen。版权 ©2001 年。把一切都放在后备箱里。FreeBSD 开源项目中的增量软件开发。http://www.dat.ruc.dk/~nielsj/research/papers/freebsd.pdf。
[PMI,2000] 项目管理学会。版权所有 ©1996 年,2000 年项目管理学会。1-880410-23-0。项目管理学会。美国宾夕法尼亚纽镇。PMBOK 指南。项目管理知识体系指南,2000 年版。
[FreeBSD,2000A] 版权所有 ©2002 年 FreeBSD 项目。核心章程。https://www.freebsd.org/internal/bylaws/。
[FreeBSD,2002A] 版权所有 ©2002 年 FreeBSD 文档项目。FreeBSD 开发者手册。开发者手册。
[FreeBSD, 2002B] 版权 © 2002 FreeBSD 项目. 核心团队选举 2002. http://election.uk.freebsd.org/candidates.html.
[FreeBSD, 2002C] Dag-Erling Smørgrav 和 Hiten Pandya. 版权 © 2002 FreeBSD 文档项目. FreeBSD 文档项目. 问题报告处理指南. 问题报告处理指南.
[FreeBSD, 2002D] Dag-Erling Smørgrav. 版权 © 2002 FreeBSD 文档项目. FreeBSD 文档项目. 编写 FreeBSD 问题报告. 编写 FreeBSD 问题报告.
[FreeBSD,2001] 版权 © 2001 年 FreeBSD 文档项目。FreeBSD 文档项目。Committer 指南。Committers 指南。
[FreeBSD,2002E] Murray Stokely。版权 © 2002 年 FreeBSD 文档项目。FreeBSD 文档项目。FreeBSD 发布工程。FreeBSD 发布工程。
[FreeBSD,2003A] FreeBSD 文档项目。FreeBSD 手册。FreeBSD 手册。
[FreeBSD, 2002F] 版权 © 2002 FreeBSD 文档项目。FreeBSD 文档项目。FreeBSD 的贡献者。FreeBSD 的贡献者。
[FreeBSD, 2002G] 版权 © 2002 FreeBSD 项目。FreeBSD 项目。核心团队选举 2002。http://election.uk.freebsd.org。
[FreeBSD, 2002H] 版权 © 2002 FreeBSD 项目。FreeBSD 项目。Commit 权限过期政策。2002/04/06 15:35:30。https://www.freebsd.org/internal/expire-bits/。
[FreeBSD,2002I] 版权所有 © 2002 FreeBSD 项目。FreeBSD 项目。新帐户创建流程。2002/08/19 17:11:27。https://www.freebsd.org/internal/new-account/。
[FreeBSD,2003B] 版权所有 © 2002 FreeBSD 文档项目。FreeBSD 文档项目。FreeBSD DocEng 团队宪章。2003/03/16 12:17。https://www.freebsd.org/internal/doceng/。
[Lehey,2002] Greg Lehey。版权所有 © 2002 Greg Lehey。Greg Lehey。在战壕中度过的两年。软件项目的演变。http://www.lemis.com/grog/In-the-trenches.pdf。
这与布鲁克斯定律相辅相成,即向一个已经延迟的项目添加另一个人会使项目变得更晚,因为这将增加沟通需求。项目模型是一种减少沟通需求的工具。
统计数据是通过计算截至 2005 年 4 月 1 日通过 portsdb 获取的文件中条目的数量而生成的。portsdb 是 port sysutils/portupgrade 的一部分。
为了找到这个数字,研究了 2004 年 1 月 1 日至 2004 年 12 月 31 日的时期。
例如,蓝牙堆栈的开发始于一个子项目,直到被认为足够稳定,才合并到 -CURRENT 分支中。现在它是 FreeBSD 核心系统的一部分。
根据 Kirk McKusick 的说法,在开发 UNIX 操作系统 20 年后,接口在很大程度上已经确定。因此,没有太多设计的必要。然而,系统的新应用和新硬件导致一些实现比过去更有益。一个例子是引入了网络浏览,使正常的 TCP/IP 连接成为短时间内的数据突发,而不是在较长时间内的稳定流。
这实际上发生的第一个版本是 4.5-RELEASE,但同时也为 4.3-RELEASE 和 4.4-RELEASE 创建了安全分支。
有一个术语上的重叠,涉及到“稳定”一词,这导致了一些混淆。-STABLE 分支仍然是一个开发分支,其目标是对大多数人有用。如果一个系统接受不能在部署时宣布的更改,则应该运行一个安全分支。
第一次核心选举在 2000 年 9 月举行
当构建系统(make world)时会执行越来越多的测试。然而,这些测试是一个非常新的补充,尚未为这些测试创建系统框架。
sendmail 和 named 是已合并自其他平台的代码的示例。
许多商业供应商使用这些镜像创建光盘,这些光盘在零售店销售。