41 lines
2.0 KiB
Markdown
41 lines
2.0 KiB
Markdown
# Linux 下能不能替换运行中的程序
|
||
|
||
今天被朋友问及“Linux 下可以替换运行中的程序么?”,以前依稀记得 Linux 下是可以的(而 Windows 就不让),于是随口答道“OK”。结果朋友发来一个执行结果:(test 正在运行中)
|
||
|
||
```bash
|
||
cp test2 test
|
||
cp: cannot create regular file `test': Text file busy
|
||
```
|
||
|
||
看起来是程序被占用,无法覆盖。于是自己又再做了几个实验:
|
||
|
||
1. 先 rm 删除正在运行的 test,然后 cp test2 test 就没有错误了。
|
||
2. 先 mv 改名正在运行的 test,然后 cp test2 test 也没有问题。
|
||
|
||
查了查资料并动手分析了一下,找到了比较满意的解释。cp 并不改变目标文件的 inode,事实上它的实现是这样的:
|
||
|
||
```cpp
|
||
# strace cp test2 test 2>&1 | grep open.*test
|
||
open("test2", O_RDONLY|O_LARGEFILE) = 3
|
||
open("test", O_WRONLY|O_TRUNC|O_LARGEFILE) = 4
|
||
```
|
||
|
||
我原以为 cp 的实现是“rm + open(O_CREAT)”,不过现在想想上面的实现方式才是最可靠的(保证了时序安全和目标文件的属性)。这也可以解释为什么 cp 的目标文件会继承被覆盖文件的属性而非源文件。
|
||
|
||
Linux 由于 Demand Paging 机制的关系,必须确保正在运行中的程序镜像(注意,并非文件本身)不被意外修改,因此内核在启动程序后会锁定这个程序镜像的 inode。这就是为什么 cp 在用“O_WRONLY|O_TRUNC”模式 open 目标文件时会失败。而先 rm 再 cp 的话,新文件的 inode 其实已经改变了,原 inode 并没有被真正删除,直到内核释放对它的引用。同理,mv 只是改变了文件名,其 inode 不变,新文件使用了新的 inode。
|
||
|
||
问题到这里已经水落石出,不过刨根究底的个性驱使我再做了以下一组实验,没想到结果完全出乎我意料之外!
|
||
|
||
写了一个简单的测试程序:
|
||
|
||
```cpp
|
||
#include
|
||
|
||
int main(int argc, char * argv[])
|
||
{
|
||
foo(); // An export function by libtest.so.
|
||
sleep(1000);
|
||
return 0;
|
||
}foo()
|
||
```
|