Linux之进程管理

进程管理

1. 进程如何创建

1.1 linux 0.11内核fork进程实现要点

  • 每个进程需要有一个内核栈。不管是4KB还是8KB。这个内核栈需要承载:task_struct结构体本身和内核栈
  • 继承父进程的task_struct数据结构,然后进行微调
  • 设置进程的栈。
  • 拷贝父进程的进程地址空间给子进程。

1.2 fork相关函数实现

fork实现
  do_fork(SIGCHLD, 0, 0, NULL, NULL);
vfork实现
do_fork(CLONE_VFORK | CLONE_VM | SIGCHID, 0, 0 ,NULL,NULL);
clone实现
do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr);
内核线程
do_fork(flags|CLONE_VM|CLONE_UNTRACED,(unsigned long)fn, (unsigned long)arg, NULL, NULL);
  • fork函数

    • 子函数会从复函数继承进程地址空间,包括进程上下文、进程堆栈、内存信息、打开的文件描述符、进程优先级、根目录、资源限制、控制终端等。

      • 返回值:父进程会返回子进程的PID,子进程会返回0
      NAME
             fork - create a child process
      
      SYNOPSIS
             #include <sys/types.h>
             #include <unistd.h>
      
             pid_t fork(void);
      
      DESCRIPTION
             fork() creates a new process by duplicating the calling process.  The new process is referred to as the child process.
             The calling process is referred to as the parent process.
      
    • vfork函数

      • vfork父进程会一直阻塞,知道子进程调用exit()或exec()为止。

        #include <sys/types.h>
        #include <unistd.h>
        
        pid_t vfork(void);
        
      • vfork()函数通过系统调用进入到linux内核,然后通过do_fork()函数来实现。

    • clone函数

      • clone()函数用来创建用户线程。fn就是线程的回调函数。

        /* Prototype for the glibc wrapper function */
        
        #define _GNU_SOURCE
        #include <sched.h>
        
        int clone(int (*fn)(void *), void *stack, int flags, void *arg, ...
        /* pid_t *parent_tid, void *tls, pid_t *child_tid */ );
        
      • clone()函数通过系统调用进入到Linux内核,然后通过do_fork()函数来实现。

    • 内核线程创建API

      kthread_create(threadfn, data, namefmt, arg...)
      kthread_run(threadfn, data, namefmt, ...)
      

2. do_fork函数

2.1 do_fork函数原型

[kernel/fork.c]
long do_fork(unsigned long clone_flags, unsinged long stack_start, unsigned stack_size, int __user *parent_tidptr, int __user *child_tidptr)
  • do_fork()函数有5个参数。

    • clone_flags: 创建进程的标志位集合。
    • stack_start: 用户态栈的起始地址。
    • stack_size:用户态栈的大小,通常设置为0。
    • parent_tidptr和child_tidptr:指向用户空间中地址的两个指针,分别指向父子进程的PID
  • 常用的clone标志位

    参数标志含义
    CLONE_VM父子进程共享进程地址空间
    CLONE_FS父子进程共享文件系统信息
    CLONE_FILES父子进程共享打开的文件
    父进程被跟踪,子进程也会被跟踪
    CLONE_VFORK在创建子进程时启动linux内核的完成机制(completion),wait_for_completion()会使父进程进入睡眠等待,指到子进程调用execve()或exit()释放虚拟内存资源。
    指定子进程拥有同一个父进程。
    CLONE_THREAD父子进程在同一个线程组里。
    CLONE_NEWS为子进程创建新的命名空间
    CLONE_SYSVSEM父子进程共享Sytem V等语义
    CLONE_SETTLS为子进程创建新的TLS(thread local storage)
    CLONE_PARENT_SETTID设置父进程的TID

3. 进程终止

  • 进程主动终止主要有如下两个途径:

    • 从main()函数返回,链接程序会自动添加对exit()系统调用。
    • 主动调用exit()系统调用。
  • 进程被动终止主要有如下三个途径:

    • 进程收到一个自己不能处理的信号。
    • 进程在内核态执行的时候产生了一个异常。
    • 进程收到SIGKILL等终止信号。
  • exit()系统调用吧退出码转换成内核要求的格式并且调用do_exit()函数来处理。

    SYSCALL_DEFINE1(exit, int, error_code)
    {
    		do_exit((error_code & 0xff) << 8);
    }
    

4. Linux内核中线程的实现

  • 进程是资源管理的最小单位,线程是程序执行的最小单位。
  • Linux线程的实现:在内核里和普通进程是一样的,都是task_struct数据结构俩描述。成为轻量级进程。
  • pthread库:应用程序实现线程的库。

5. 0号进程和1号进程

  • 进程0是指的Linux内核初始化从无到有创建的一个内核线程。
    • 进程0
    • idle进程
    • swapper进程
  • Linux内核初始化函数start_kernel()在初始化完内核所需要的所有数据结构之后会创建里另外一个内核线程,这个内核线程就是进程1或叫init进程。

6. 僵尸进程和托孤进程

  • 当一个进程通过exit()系统调用已经终止之后,进入处理与僵尸状态(ZOMBIE)。
  • 当父进程通过调用wait()系统调用来获取已终结的子进程的信息之后,内核才会去释放子进程的task_struct数据结构。
  • 托孤进程
    • 如果父进程先于子进程消亡,那么子进程就变成托孤进程。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

byd yes

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值