稳定的_linux_api_毫无意义

2023-10-29 12:38
文章标签 linux api 稳定 毫无意义

本文主要是介绍稳定的_linux_api_毫无意义,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

英文版维护者: Greg Kroah-Hartman <greg@kroah.com>
中文版维护者: 钟宇 TripleX Chung <zhongyu@18mail.cn>
中文版翻译者: 钟宇 TripleX Chung <zhongyu@18mail.cn>
中文版校译者: 李阳 Li Yang <leoli@freescale.com>
以下为正文
---------------------------------------------------------------------

写作本文档的目的,是为了解释为什么Linux既没有二进制内核接口,也没有稳定
的内核接口。这里所说的内核接口,是指内核里的接口,而不是内核和用户空间
的接口。内核到用户空间的接口,是提供给应用程序使用的系统调用,系统调用
在历史上几乎没有过变化,将来也不会有变化。我有一些老应用程序是在0.9版本
或者更早版本的内核上编译的,在使用2.6版本内核的Linux发布上依然用得很好
。用户和应用程序作者可以将这个接口看成是稳定的。

 

执行纲要
--------

你也许以为自己想要稳定的内核接口,但是你不清楚你要的实际上不是它。你需
要的其实是稳定的驱动程序,而你只有将驱动程序放到公版内核的源代码树里,
才有可能达到这个目的。而且这样做还有很多其它好处,正是因为这些好处使得
Linux能成为强壮,稳定,成熟的操作系统,这也是你最开始选择Linux的原因。


入门
-----

只有那些写驱动程序的"怪人"才会担心内核接口的改变,对广大用户来说,既
看不到内核接口,也不需要去关心它。

首先,我不打算讨论关于任何非GPL许可的内核驱动的法律问题,这些非GPL许可
的驱动程序包括不公开源代码,隐藏源代码,二进制或者是用源代码包装,或者
是其它任何形式的不能以GPL许可公开源代码的驱动程序。如果有法律问题,请咨
询律师,我只是一个程序员,所以我只打算探讨技术问题(不是小看法律问题,
法律问题很实际,并且需要一直关注)。

既然只谈技术问题,我们就有了下面两个主题:二进制内核接口和稳定的内核源
代码接口。这两个问题是互相关联的,让我们先解决掉二进制接口的问题。


二进制内核接口
--------------
假如我们有一个稳定的内核源代码接口,那么自然而然的,我们就拥有了稳定的
二进制接口,是这样的吗?错。让我们看看关于Linux内核的几点事实:
- 取决于所用的C编译器的版本,不同的内核数据结构里的结构体的对齐方
式会有差别,代码中不同函数的表现形式也不一样(函数是不是被inline编译取
决于编译器行为)。不同的函数的表现形式并不重要,但是数据结构内部的对齐
方式很关键。
- 取决于内核的配置选项,不同的选项会让内核的很多东西发生改变:
- 同一个结构体可能包含不同的成员变量
- 有的函数可能根本不会被实现(比如编译的时候没有选择SMP支持
,一些锁函数就会被定义成空函数)。
- 内核使用的内存会以不同的方式对齐,这取决于不同的内核配置选
项。
- Linux可以在很多的不同体系结构的处理器上运行。在某个体系结构上编
译好的二进制驱动程序,不可能在另外一个体系结构上正确的运行。

对于一个特定的内核,满足这些条件并不难,使用同一个C编译器和同样的内核配
置选项来编译驱动程序模块就可以了。这对于给一个特定Linux发布的特定版本提
供驱动程序,是完全可以满足需求的。但是如果你要给不同发布的不同版本都发
布一个驱动程序,就需要在每个发布上用不同的内核设置参数都编译一次内核,
这简直跟噩梦一样。而且还要注意到,每个Linux发布还提供不同的Linux内核,
这些内核都针对不同的硬件类型进行了优化(有很多种不同的处理器,还有不同
的内核设置选项)。所以每发布一次驱动程序,都需要提供很多不同版本的内核
模块。

相信我,如果你真的要采取这种发布方式,一定会慢慢疯掉,我很久以前就有过
深刻的教训...


稳定的内核源代码接口
--------------------

如果有人不将他的内核驱动程序,放入公版内核的源代码树,而又想让驱动程序
一直保持在最新的内核中可用,那么这个话题将会变得没完没了。
内核开发是持续而且快节奏的,从来都不会慢下来。内核开发人员在当前接口中
找到bug,或者找到更好的实现方式。一旦发现这些,他们就很快会去修改当前的
接口。修改接口意味着,函数名可能会改变,结构体可能被扩充或者删减,函数
的参数也可能发生改变。一旦接口被修改,内核中使用这些接口的地方需要同时
修正,这样才能保证所有的东西继续工作。

举一个例子,内核的USB驱动程序接口在USB子系统的整个生命周期中,至少经历
了三次重写。这些重写解决以下问题:
- 把数据流从同步模式改成非同步模式,这个改动减少了一些驱动程序的
复杂度,提高了所有USB驱动程序的吞吐率,这样几乎所有的USB设备都能以最大
速率工作了。
- 修改了USB核心代码中为USB驱动分配数据包内存的方式,所有的驱动都
需要提供更多的参数给USB核心,以修正了很多已经被记录在案的死锁。

这和一些封闭源代码的操作系统形成鲜明的对比,在那些操作系统上,不得不额
外的维护旧的USB接口。这导致了一个可能性,新的开发者依然会不小心使用旧的
接口,以不恰当的方式编写代码,进而影响到操作系统的稳定性。
在上面的例子中,所有的开发者都同意这些重要的改动,在这样的情况下修改代
价很低。如果Linux保持一个稳定的内核源代码接口,那么就得创建一个新的接口
;旧的,有问题的接口必须一直维护,给Linux USB开发者带来额外的工作。既然
所有的Linux USB驱动的作者都是利用自己的时间工作,那么要求他们去做毫无意
义的免费额外工作,是不可能的。
安全问题对Linux来说十分重要。一个安全问题被发现,就会在短时间内得到修
正。在很多情况下,这将导致Linux内核中的一些接口被重写,以从根本上避免安
全问题。一旦接口被重写,所有使用这些接口的驱动程序,必须同时得到修正,
以确定安全问题已经得到修复并且不可能在未来还有同样的安全问题。如果内核
内部接口不允许改变,那么就不可能修复这样的安全问题,也不可能确认这样的
安全问题以后不会发生。
开发者一直在清理内核接口。如果一个接口没有人在使用了,它就会被删除。这
样可以确保内核尽可能的小,而且所有潜在的接口都会得到尽可能完整的测试
(没有人使用的接口是不可能得到良好的测试的)。


要做什么
-------

如果你写了一个Linux内核驱动,但是它还不在Linux源代码树里,作为一个开发
者,你应该怎么做?为每个发布的每个版本提供一个二进制驱动,那简直是一个
噩梦,要跟上永远处于变化之中的内核接口,也是一件辛苦活。
很简单,让你的驱动进入内核源代码树(要记得我们在谈论的是以GPL许可发行
的驱动,如果你的代码不符合GPL,那么祝你好运,你只能自己解决这个问题了,
你这个吸血鬼<把Andrew和Linus对吸血鬼的定义链接到这里>)。当你的代码加入
公版内核源代码树之后,如果一个内核接口改变,你的驱动会直接被修改接口的
那个人修改。保证你的驱动永远都可以编译通过,并且一直工作,你几乎不需要
做什么事情。

把驱动放到内核源代码树里会有很多的好处:
- 驱动的质量会提升,而维护成本(对原始作者来说)会下降。
- 其他人会给驱动添加新特性。
- 其他人会找到驱动中的bug并修复。
- 其他人会在驱动中找到性能优化的机会。
- 当外部的接口的改变需要修改驱动程序的时候,其他人会修改驱动程序

- 不需要联系任何发行商,这个驱动会自动的随着所有的Linux发布一起发
布。

和别的操作系统相比,Linux为更多不同的设备提供现成的驱动,而且能在更多不
同体系结构的处理器上支持这些设备。这个经过考验的开发模式,必然是错不了
的 :)

-------------
感谢 Randy Dunlap, Andrew Morton, David Brownell, Hanna Linder,
Robert Love, and Nishanth Aravamudan 对于本文档早期版本的评审和建议。

英文版维护者: Greg Kroah-Hartman <greg@kroah.com>

 

这篇关于稳定的_linux_api_毫无意义的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/300701

相关文章

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法

《ElasticSearch+Kibana通过Docker部署到Linux服务器中操作方法》本文介绍了Elasticsearch的基本概念,包括文档和字段、索引和映射,还详细描述了如何通过Docker... 目录1、ElasticSearch概念2、ElasticSearch、Kibana和IK分词器部署

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Linux流媒体服务器部署流程

《Linux流媒体服务器部署流程》文章详细介绍了流媒体服务器的部署步骤,包括更新系统、安装依赖组件、编译安装Nginx和RTMP模块、配置Nginx和FFmpeg,以及测试流媒体服务器的搭建... 目录流媒体服务器部署部署安装1.更新系统2.安装依赖组件3.解压4.编译安装(添加RTMP和openssl模块

linux下多个硬盘划分到同一挂载点问题

《linux下多个硬盘划分到同一挂载点问题》在Linux系统中,将多个硬盘划分到同一挂载点需要通过逻辑卷管理(LVM)来实现,首先,需要将物理存储设备(如硬盘分区)创建为物理卷,然后,将这些物理卷组成... 目录linux下多个硬盘划分到同一挂载点需要明确的几个概念硬盘插上默认的是非lvm总结Linux下多

Deepseek R1模型本地化部署+API接口调用详细教程(释放AI生产力)

《DeepseekR1模型本地化部署+API接口调用详细教程(释放AI生产力)》本文介绍了本地部署DeepSeekR1模型和通过API调用将其集成到VSCode中的过程,作者详细步骤展示了如何下载和... 目录前言一、deepseek R1模型与chatGPT o1系列模型对比二、本地部署步骤1.安装oll

浅析如何使用Swagger生成带权限控制的API文档

《浅析如何使用Swagger生成带权限控制的API文档》当涉及到权限控制时,如何生成既安全又详细的API文档就成了一个关键问题,所以这篇文章小编就来和大家好好聊聊如何用Swagger来生成带有... 目录准备工作配置 Swagger权限控制给 API 加上权限注解查看文档注意事项在咱们的开发工作里,API

linux进程D状态的解决思路分享

《linux进程D状态的解决思路分享》在Linux系统中,进程在内核模式下等待I/O完成时会进入不间断睡眠状态(D状态),这种状态下,进程无法通过普通方式被杀死,本文通过实验模拟了这种状态,并分析了如... 目录1. 问题描述2. 问题分析3. 实验模拟3.1 使用losetup创建一个卷作为pv的磁盘3.

一分钟带你上手Python调用DeepSeek的API

《一分钟带你上手Python调用DeepSeek的API》最近DeepSeek非常火,作为一枚对前言技术非常关注的程序员来说,自然都想对接DeepSeek的API来体验一把,下面小编就来为大家介绍一下... 目录前言免费体验API-Key申请首次调用API基本概念最小单元推理模型智能体自定义界面总结前言最

JAVA调用Deepseek的api完成基本对话简单代码示例

《JAVA调用Deepseek的api完成基本对话简单代码示例》:本文主要介绍JAVA调用Deepseek的api完成基本对话的相关资料,文中详细讲解了如何获取DeepSeekAPI密钥、添加H... 获取API密钥首先,从DeepSeek平台获取API密钥,用于身份验证。添加HTTP客户端依赖使用Jav