我想知道...当我启动一个使用共享库A的程序X,并且在程序运行时,我修改了磁盘上的共享库,并运行另一个依赖于相同共享的程序Y图书馆。该程序是否会使用共享库的已有内存版本,或者是否会加载具有后续修改的共享库的不同实例?共享库何时被认为是共享的“相同”?
如何确定是否共享加载的库或从磁盘重新加载它?
我想知道...当我启动一个使用共享库A的程序X,并且在程序运行时,我修改了磁盘上的共享库,并运行另一个依赖于相同共享的程序Y图书馆。该程序是否会使用共享库的已有内存版本,或者是否会加载具有后续修改的共享库的不同实例?共享库何时被认为是共享的“相同”?
如何确定是否共享加载的库或从磁盘重新加载它?
动态加载程序只是做普通的旧open(2)
和mmap(2)
电话,以及存储器映射颠簸的inode引用计数相同的方法,开放FD一样。因此,如果您为库执行通常的原子文件替换技巧,请在文件的新副本中写下更改,然后将其替换为旧的名称,在该点之后开始的任何内容都将拾取新的inode,并且新内容,但正在运行的程序将继续使用旧的inode和旧内容。
如果您修改了该库,那么在write
调用之后启动的任何程序自然都会提取您的更改。更有趣的问题是已经映射的进程发生了什么。答案可能是“系统不会让你这样做”或“未指定,取决于页面缓存实现的细节”。在Linux执行过程中(这是我不得不手动)轻松地进行的:glibc动态加载程序对其所有共享库地图使用MAP_DENYWRITE
,但没有记录,但听起来像,它的意思是“在映射存在时使该文件不可修改” 。然而,我在内核源代码中找不到任何东西可以使MAP_DENYWRITE
做;它可能是一个历史遗迹或其他类似的东西。它也使用MAP_PRIVATE
。 http://pubs.opengroup.org/onlinepubs/7908799/xsh/mmap.html表示“未确定MAP_PRIVATE映射建立后对底层对象所做的修改是否通过MAP_PRIVATE映射可见”。因此,您可能会也可能无法修改正在运行的进程下的共享库映像,具体取决于页面缓存实施的细节。
动态加载器使用mmap(2)
来加载共享库,所以所有的魔法真的在mmap(2)
。
在Linux中的特定情况下,文件映射调用特定的FS-mmap()
操作,这通常是有线mm/filemap.c:generic_file_mmap()
,这台vm_ops.fault
的文件映射到mm/filemap.c:filemap_fault()
,所以魔术被延迟到页面故障时间。 filemap_fault()
尝试使用find_lock_page()
找到页面缓存中的页面。
mmap() → fs_file_ops.mmap() → generic_file_mmap() → file_vm_ops.fault = filemap_fault()
page fault → filemap_fault() → find_lock_page()
这实际上并没有回答问题 – zwol