zoukankan      html  css  js  c++  java
  • 解析Linux中shell执行一次命令的全过程

    1.  在busybox中先进入main函数

    2.  根据调用号进入ash_main(也就是busybox的shell)

    3.  进入cmdloop(1)中for循环

    4.  在parsecmd中解析标准输入

    5.  此时在控制台上输入./a_static执行(a_static为我的elf格式的应用程序)

    6.  shell解析出命令退出parsecmd进入evaltree再进入evalcommand

    7.  调用forkshell创建子线程,该子线程用来执行a_static,而父进程我们这边被先调用

    8.  父进程进行waitpid系统调用进入wait4再进入do_wait,设置了局部变量wo->notask_error = -ECHILD;设置进程状态TASK_INTERRUPTIBLE

    9.  进入do_wait_thread因为有子进程所以进入wait_consider_task设置wait_consider_task=0退回do_wait

    10.  执行到标号notask处因为局部变量wo->notask_error = 0所以会进入进程调度,而父进程进入睡眠

    11.  子线程被调度后进入shellexec再进入tryexec再进行系统调用execve加载用户空间

    12.  arm中通过swi xxx (xxx为系统调用号)进入软中断向量,再进入vector_swi,保存硬件上下文,此时根据 lr-4 也就是swi指令的后半部

        确定系统调用号,根据sys_call_table中的调用号偏移找到入口函数这里是sys_execve并执行

    13.  此时我们的用户空间和父进程一样,TTB中的页表基地址是父进程的页表基地址

    14.  调用do_execve为线程申请用户空间

    15.  退出do_execve,这时我们有了新的用户线性区(我们这边打印出来有四个线性区)和页表,TTB也已经指向自己的页全局目录

        线性区:

            8000 88000    代码区

            8f000 90000  数据区

               90000 92000  堆区

             be9b7000 be9d9000   栈+命令行参数+环境变量

    16.  退出sys_execve,pop出内核栈中的硬件上下文

    17.  执行完用户a_static程序后我们调用系统调用_exit(***)让进程进入僵尸态

    18.  进入SYSCALL_DEFINE1(exit, int, error_code)再进入do_exit进入exit_notify进入do_notify_parent唤醒父进程,退回exit_notify

    19.  设置current->exit_state=EXIT_ZOMBIE,退回do_exit

    19.  调度schedule

    20.  父进程由于被唤醒重新调度进入标号repeat执行,进入do_wait_thread进入wait_consider_task由于子进程tsk->exit_state == EXIT_ZOMBIE

        所以调用wait_task_zombie会返回正值,回到do_wait

    21.  由于返回值>0进入标号end,不再进行睡眠和进程调度,直接退出返回用户态 

    22.  回到用户态shell又进行了waitpid调度(不知道为什么)由于没有子进程所以不会进行进程调度直接再次返回用户态

        所以说进程发布waitpid调度 进入睡眠的必要条件是要有子进程。

  • 相关阅读:
    PHP面向对象练习
    PHP面向对象的特点
    PHP的构造函数和析构函数
    PHP面向对象
    AVL-TREE
    ReentrantLock
    treap-名次树-树堆
    细数那些我们熟悉的 排序!
    数据结构 - trie
    python 凸包(经纬度) + 面积[近似]
  • 原文地址:https://www.cnblogs.com/genshu123/p/11867708.html
Copyright © 2011-2022 走看看