您的位置首页>企业动态>

Linux内核特性之VDSO

导读大家好,我是极客范的本期栏目编辑小友,现在为大家讲解Linux内核特性之VDSO问题。这段时间在看Linux内核源代码的时候,经常会遇到vdso(比

大家好,我是极客范的本期栏目编辑小友,现在为大家讲解Linux内核特性之VDSO问题。

这段时间在看Linux内核源代码的时候,经常会遇到vdso(比如在Feature-fix中获得时间),在网上搜索后才知道意思。原来这是Linux为了解决与glibc的兼容性问题而想出来的一个独特的小把戏。以下来自Fedora中文邮件列表,想和大家分享一下。

通常,一个函数被添加到内核中,glibc使用它需要很长时间。本来linux已经为这个功能是否进入内核争论了很久,而glibc又要为是否使用这个内核的新特性争论很久(glibc并不是Linux的专属,所以我们要考虑BSD(虽然人们不用glibc)、SysV Windows(诶,没有办法)、sun的垂死的solaris,以及我们自己的Hurd。那么,一句话,这个新功能是可以接受的。太慢了。

在离家更近的地方,fnotify glibc还没有相应的包装功能,futex和NPTL花了很长时间才进入主流。Libc是app和内核之间的桥梁,libc要快速跟上内核的接口变化,但是glibc和内核不是一起开发的,所以只是比较理想。Glibc必须兼容不同版本的内核!

内核必须兼容不同版本的glibc。双方都背负了太多的历史包袱。Glibc至今保留了兼容2.4版本的Linux Threads的古老内核。Linux没有用,甚至有bug的系统调用(由于接口问题,有些bug是必须的)也必须保留。谁知道用户会用哪个版本的glibc?尽管新的glibc将使用新的调用,但它提供了与旧调用一致的API以实现兼容性。但是,经常会出现用户只升级内核而不升级glibc的情况。就算升级了glibc,你的新版本glibc肯定会用内核的新接口?让我们再等几年,直到glibc开发者之间的争吵结束。

结果,Linux的大牛们再次使用了他们独特的伎俩:将libc变成VDSO并进入内核。

在这里普及一下VDSO的小知识。知道的可以跳过,不知道的可以看:VDSO是虚拟动态共享对象,是虚拟的。所以由内核提供。这个。所以文件不在磁盘上,而是在内核中。映射包含某个。所以在内核进入它的内存空间的时候程序就启动了,而相应的程序就可以把它里面的功能当成普通的使用。所以。例如,函数syscall()在linux-vdso.so.1中,但磁盘上没有相应的文件。您可以通过ldd/bin/bash进行检查。

这样,与内核一起分发的libc被唯一地绑定到内核的特定版本。注意,VDSO只随内核分布,不在内核空间运行,不会导致内核膨胀。这样,内核和libc都不需要编写太多的代码来兼容不同的版本,引入了太多的bug。

当然,libc不仅有到内核的接口,还有很多常用的功能,不需要专门为不同版本的内核编写。所以我估计Linux上会有两个libc,一个在内核中,只是一个系统调用的包,另一个是一个普通的libc,但是这个libc不再需要花费精力去配合这么多内核了。

让我们只调用一个kernellibc和一个glibc:printf(),这些仍然在glibc中。Open()、read()、write()、socket()不再是glibc的了,它们在kernellibc中。

Linux下传统的系统调用是通过软中断(0x80)实现的。在Kernel.org的电子邮件列表中,有一封电子邮件讨论了“‘英特尔P6 vs p7系统调用性能’”。最后得出结论,使用int0x80的传统系统调用会浪费大量时间。而sysenter/sysexit可以弥补这个缺点,所以最终决定在linux内核中使用后替换前者(这个功能最终在内核2.6版本中加入,也就是采用了sysenter/sysexit)。

如何用替换的sysenter/sysexit替换以前的int0x80?Linux的Kenerl需要考虑这一点:有些机器不支持sysenter/sysexit,所以和glibc做了一个很好的交易,“以后你调用系统的时候,会从我给你的地址调用它,这个地址指向的内容要么是int0x80调用模式,要么是sysenter/sysexit调用模式,我会根据机器选择一个”(内核和glibc的配合是那么默契),这个地址就是vsyscall。

你可以把vdso想象成一个共享的objdec。

t file(这个文件实际上不存在),内核将其映射到某个地址空间,被所有程序所共享。(我觉得这里用到了一个技术:多个虚拟页面映射到同一个物理页面。即内核把vdso映射到某个物理页面上,然后所有程序都会有一个页表项指向它,以此来共享,这样每个程序的vdso地址就可以不相同了)

“快速系统调用指令”比起中断指令来说,其消耗时间必然会少一些,但是随着 CPU 设计的发展,将来应该不会再出现类似 Intel PenTIum4 这样悬殊的差距。而"快速系统调用指令"比起中断方式的系统调用方式,还存在一定局限,例如无法在一个系统调用处理过程中再通过"快速系统调用指令"调用别的系统调用。因此,并不一定每个系统调用都需要通过"快速系统调用指令"来实现。比如,对于复杂的系统调用例如 fork,两种系统调用方式的时间差和系统调用本身运行消耗的时间来比,可以忽略不计,此处采取"快速系统调用指令"方式没有什么必要。而真正应该使用"快速系统调用指令"方式的,是那些本身运行时间很短,对时间精确性要求高的系统调用,例如 getuid、getTImeofday 等等。因此,采取灵活的手段,针对不同的系统调用采取不同的方式,才能得到最优化的性能和实现最完美的功能。  

 

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。