C 在不重新启动进程的情况下更新共享库

C 在不重新启动进程的情况下更新共享库,c,linux,dll,shared-libraries,C,Linux,Dll,Shared Libraries,如果我的进程正在加载.so库,并且库的新版本可用,是否可以在不重新启动进程的情况下切换到新库?或者,答案取决于库中某个现有函数的参数是否更改 我在一个相当大的系统中工作,它运行100个进程,每个进程加载10个库。这些库提供特定的功能,并由单独的团队提供。所以,当其中一个库发生更改时(比如说,对于bug修复),理想的做法是在不影响运行过程的情况下将其公开发布。可能吗 编辑谢谢!在我的例子中,当一个新库可用时,所有正在运行的进程都必须开始使用它。它不能让它们与旧版本一起运行,以后再使用新版本。因此,

如果我的进程正在加载.so库,并且库的新版本可用,是否可以在不重新启动进程的情况下切换到新库?或者,答案取决于库中某个现有函数的参数是否更改

我在一个相当大的系统中工作,它运行100个进程,每个进程加载10个库。这些库提供特定的功能,并由单独的团队提供。所以,当其中一个库发生更改时(比如说,对于bug修复),理想的做法是在不影响运行过程的情况下将其公开发布。可能吗


编辑谢谢!在我的例子中,当一个新库可用时,所有正在运行的进程都必须开始使用它。它不能让它们与旧版本一起运行,以后再使用新版本。因此,看起来更安全的选择是只重新加载进程。

ldd进程的二进制文件是找到答案的一种方法。尽管理论上是可能的,但不建议修补正在运行的进程,尽管我确信存在一些实用程序,比如ksplice,可以修补正在运行的linux内核


您可以简单地升级,运行过程将继续使用旧版本,并在重新启动时选择新版本,前提是您的软件包管理系统良好,并且知道什么是可兼容安装的。

您可能希望了解共享库版本控制和ld
-h
选项

一种使用方法如下:

在生成系统中维护版本计数器。您可以使用以下内容构建共享库:

ld ..... -h mylibrary.so.$VERSION
但是,您可以将它作为普通的
mylibrary.so
放在开发树的lib中。(还有一个黑客将整个.so放入一个.a文件)


现在,在运行时,使用库的进程会查找完全版本化的名称。要推出新版本,只需将新版本添加到图片中。运行与旧版本链接的程序将继续使用它。当程序重新链接并根据新程序进行测试时,您将推出新的可执行文件。

在进程运行的情况下,您无法动态升级链接库。 您甚至可以尝试,但如果成功了(并且不会出现“text file is use”(文本文件正在使用)错误消息,则必须重新启动该过程,使其将新库映射到内存中

可以使用lsof命令检查链接到的库(运行时或链接时间):

lsof-p | grep'mem'

有时您可以升级正在使用的。因此,有时您不能。这主要取决于您如何尝试这样做,但也取决于您运行的内核的安全保证

不要这样做: 猫新.so>旧.so …因为最终,您的流程可能会尝试要求页面上的某些内容,并发现它不再位于正确的位置。这是一个问题,因为事物的地址可能会改变,它仍然是相同的inode;您只是在覆盖文件中的字节

但是,如果您: mv new.so old.so 在大多数系统上都可以,因为您运行的进程可以保留旧库的一个现在尚未命名的inode,而新的进程调用将获得新文件。
但是,有些内核不喜欢让您使用mv。因此,也许出于谨慎,也许出于其自身的简单性。

如果您希望库定期更改,并且 你期望保持正常的时间,我认为你的系统 应该重新设计这样的库,使其真正成为 松散耦合的组件(例如服务)

话虽如此,我对这个问题的回答是肯定的:在某些情况下 在这种情况下,更新共享库不需要 重新启动进程。在大多数情况下,我认为这是不可能的, 例如,当库的API发生更改时 当库发生变化时,数据段的排列会发生变化 维护内部线程。名单很长

对于代码中非常小的bug修复,您仍然可以使用 写入进程内存空间的,以及从 有什么重做在动态方面
链接。老实说,这是一项极其复杂的活动。

一项有趣的技术,尽管在检查点恢复步骤中有点容易失败,但它是执行不可见的重新启动

您的服务器进程或其他进程将其所有必要信息保存到磁盘文件中。包括文件描述符编号和当前状态。然后,服务器进程执行
exec
系统调用以执行自身,替换自身的当前版本。然后,它从磁盘文件读取其状态,并继续为其文件描述符提供服务,就好像什么都没发生一样


如果一切顺利,重新启动是不可见的,新进程正在使用所有更新的库。

至少,您必须确保库的接口在版本之间不会更改。如果这是肯定的,那么我将尝试使用dlopen/dlsym动态加载库,看看dlclose是否允许您重新加载


我自己从来没有这样做过,但这是我首先要走的道路。如果您这样做,您能发布结果吗?

Linux提供了几个动态加载程序接口,进程可以在运行时加载动态库。linux提供的dlopen和dlsysm可能会解决您的问题。

除非您控制所有可执行文件,否则热更新文件是不可能的,如果没有像ptracing进程这样的丑陋的黑客攻击。另外,linux不使用dll。我不认为“cat new.so>old.so”对正在运行的程序有任何影响。由于内核知道内存中的代码段被映射到old.so所在的存储器,它要么拒绝写入(“文本忙”),要么甚至继续将扇区放在一边,直到程序完成。您也可以使用
pldd
,而不是
lsof-p
。它是今年3月才添加到glibc的。您的发行版可能还没有包括它。
lsof -p <process_pid> | grep ' mem '