少于 1 分钟阅读 次阅读

概要:通过一个调用 exec 的示例程序,分析 exec 系统调用的使用方法与流程:exec 用新程序替换当前进程的内存与寄存器,失败时才会返回。

1 程序结构分析

代码如下:

// exec.c: replace a process with an executable file

#include "kernel/types.h"
#include "user/user.h"

int
main()
{
    char *argv[] = { "echo", "this", "is", "echo", 0 };

    exec("echo", argv);

    printf("exec failed!\n");

    exit(0);
}

演示 exec() 如何用一个新的可执行文件替换当前进程的内存映像。

也就是说:

  • 不是创建新进程(那是 fork
  • 而是把“当前进程”变成另一个程序

1.1 构造参数数组

char *argv[] = { "echo", "this", "is", "echo", 0 };

这是传给 exec() 的参数数组。

非常重要:

在 UNIX 系统中:

argv[0] = 程序名
argv[1...] = 参数
argv 最后必须是 0 (NULL)

1.2 exec调用

exec("echo", argv);

它的作用是:

用 echo 这个可执行文件替换当前进程

发生了什么?

  1. 当前进程的代码段被销毁
  2. 数据段被销毁
  3. 栈被销毁
  4. 加载 echo 程序
  5. 把 argv 传给新程序
  6. 从 echo 的 main() 开始执行

⚠️ 注意:

  • exec 成功时 不会返回
  • 只有失败才会继续往下执行

1.3 失败处理

printf("exec failed!\n");

如果看到这句话,说明:

  • echo 没找到
  • 或加载失败

2 执行流程图

main()
   ↓
构造 argv
   ↓
exec("echo", argv)
   ↓
[内核加载 echo]
   ↓
当前进程变成 echo
   ↓
echo main()
   ↓
打印:
this is echo

3 理解进程替换机制

很多人误以为:

exec 是创建新进程

其实真正流程是:

fork() → 创建子进程
exec() → 子进程变成另一个程序

shell 的运行机制:

父进程(shell)
    |
    └── fork()
           |
           └── 子进程
                   |
                   └── exec(ls)

留下评论