• Linux内核之进程和系统调用


    一.fork和execl

      我们先尝试编写创建两个程序,来理解Linux创建新进程的过程:

     1 #include <sys/systypes.h>
     2 #include <unistd.h>
     3 
     4 int main()
     5 {
     6     if (fork() == 0) {
     7         print("Child process!\n");
     8     } else {
     9         print("Parent process!\n");
    10     }
    11     return 0;
    12 }

      运行结果为:

    Child process!
    Parent process!

      代码二

     1 #include <sys/types.h>
     2 #include <unistd.h>
     3 #include <stdio.h>
     4 
     5 int main()
     6 {
     7     execl("./hello_world", NULL, NULL);
     8     printf("execl failed!");
     9     return 0;
    10 }

      运行结果

    Hello World!

      通过上面的对比,可以看错:fork实际上是复制了一个“自己”,在fork之后有两个自己在运行。子进程和父进程是依靠fork的返回值是否为0来决定执行流。返回值为0则是子进程。返回值不是0则是父进程。

      execl则是将执行的内容完全替换掉。在execl之后,执行的完全是一个新的进程。就进程不复存在。

      可以将fork看作是复制,而execl则是替换。

      linux就是这样创建进程的:fork一个进程,在用execl加载新的执行程序,替换新建的进程的执行内容。比如ls:bash通过fork一个新的bash,再execl("ls")来创建一个ls进程。

    二.系统调用的过程

      想要详细定位fork和execl在内核中的实现需要了解linux系统调用的处理流程。我们以fork为例子。我们可以通过下面的代码调用fork:

    #include <memory.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    int  main()
    {
        pid_t pid;
    
        // pid = fork();
        asm volatile(
            "mov $0x2, %%eax\n\t" // 将fork的系统调用号2存到eax寄存器  
            "int $0x80\n\t"       // 产生int 0x80中断
            "mov %%eax,%0\n\t"    // 将结果存入pid中
            : "=m" (pid) 
        );
        
        if (pid == 0) {
            printf("Child process\n");
        } else if (pid > 0) {
            printf("Parent process\n");
        }
    
        return 0;
    }

      这样就能通过内核调用fork了。可以看到我们是通过int 0x80这条指令实现的。实际上,这是一个中断。我们通过128号中断调用内核的中断服务例程,调用fork的。

      在系统调用的过程中,我们需要记住两张表。

      一、中断向量表:在内核启动时初始化,然后当有中断发生时,内核就会根据中断向量号(如:0x80),查找对应的中断处理服务程序。

      二、系统调用表:在编译内核时就已经卸载内核中,系统调用处理程序会根据系统调用号处理对应的系统调用程序。

      

      例如,上图的getpid函数,然后进入getuid系统调用。getuid进入system_call系统中断服务例程,system_call再去调用sys_getuid16运行服务例程。

    三. 查找对应的内核服务例程

      通过上面的理解,我们就可以很快的使用source insight来查找fork和execl对应的内核服务例程了。

      fork对应的是:kernel/fork.c中的sys_fork函数

      execl对应的是:fs/exec.c中的sys_execl函数。

      这些函数太过复杂,需要非常好的基础才能看懂。我目前基础不够,只能结合《深入理解linux内核》中的进程和文件系统两章做一点简单的理解。这里就无法再做分析了。只对理解的部分做出一点总结。

  • 相关阅读:
    L255 Learning to say no brings a thrill of freedom
    2019-02-25 EST 科技文翻译
    L253 Work and Pleasure
    2019.2.22 初级英语口语班 结课
    L252 小组作业
    2019-02-22 L231
    leetcode 67 Add Binary ----- java
    leetcode 66 Plus One ----- java
    leetcode 65 Valid Number ----- java
    leetcode 64 Minimum Path Sum ----- java
  • 原文地址:https://www.cnblogs.com/SA226343/p/3134543.html
Copyright © 2020-2023  润新知