进程管理

进程是处于执行期的程序以及相关资源的总称。通常是fork()调用的结果。该系统调用通过复制一个进程来创建新的进程。fork()系统调用从内核返回两次,一次返回父进程,另一次返回新产生的子进程。接着调用exec()这组函数就可以创建新的地址空间,并将程序载入。最终通过exit()退出执行。

内核把进程的列表存放在task_list(任务队列)的双向循环列表里,每一项称为进程描述符(process descriptor),包含一个具体进程的所有信息。                

linux通过slab分配器分配task_struct结构。

                             

用slab分配器动态生成task_struct,只需在栈底(向下生成的栈)创建一个新的结构 struct thread_info.

通过current宏查找进程描述符。x86系统,current把栈指针的后13位有效位屏蔽掉,用来计算偏移,最后current再从thread_info的task域提取并返回task_struct的地址。

pid_t pid;  
pid_t tgid;  

Unix系统通过pid来标识进程,linux把不同的pid与系统中每个进程或轻量级线程关联,而unix程序员希望同一组线程具有共同的pid,遵照这个标准linux引入线程组的概念。一个线程组所有线程与领头线程具有相同的pid,存入tgid字段,getpid()返回当前进程的tgid值而不是pid的值。

在CONFIG_BASE_SMALL配置为0的情况下,PID的取值范围是0到32767,即系统中的进程数(短整型16位)最大为32768个。

#define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000)  

在Linux系统中,一个线程组中的所有线程使用和该线程组的领头线程(该组中的第一个轻量级进程)相同的PID,并被存放在tgid成员中。只有线程组的领头线程的pid成员才会被设置为与tgid相同的值。注意,getpid()系统调用返回的是当前进程的tgid值而不是pid值。

TASK_STOPPED和TASK_TRACED状态判断

  对于进程本身来说,TASK_STOPPED和TASK_TRACED状态很类似,都是表示进程暂停下来。而TASK_TRACED状态相当于在TASK_STOPPED之上多了一层保护,处于TASK_TRACED状态的进程不能响应SIGCONT信号而被唤醒。只能等到调试进程通过ptrace系统调用执行PTRACE_CONT、PTRACE_DETACH等操作(通过ptrace系统调用的参数指定操作),或调试进程退出,被调试的进程才能恢复TASK_RUNNING状态。

设置当前进程状态 set_task_state(task,state);

ptrace系统调用:

ptrace 系统调从名字上看是用于进程跟踪的,它提供了父进程可以观察和控制其子进程执行的能力,并允许父进程检查和替换子进程的内核镜像(包括寄存器)的值。其基 本原理是: 当使用了ptrace跟踪后,所有发送给被跟踪的子进程的信号(除了SIGKILL),都会被转发给父进程,而子进程则会被阻塞,这时子进程的状态就会被 系统标注为TASK_TRACED。而父进程收到信号后,就可以对停止下来的子进程进行检查和修改,然后让子进程继续运行。    
    其原型为:    
    #include <sys/ptrace.h>
    long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
    ptrace有四个参数: 
    1). enum __ptrace_request request:指示了ptrace要执行的命令。
    2). pid_t pid: 指示ptrace要跟踪的进程。
    3). void *addr: 指示要监控的内存地址。
    4). void *data: 存放读取出的或者要写入的数据

进程创建: 使用fork()和exec()函数。fork()通过拷贝当前进程来创建一个新的进程,和父进程唯一区别在于PID、某些资源和统计量不同;exec()负责读取可执行文件并载入地址空间开始运行。linux的fork()采用写时拷贝页实现,也就是说资源的复制只有在写入的时候才会被复制,在此之前,都是以只读的方式共享,这种技术使得地址空间的页的拷贝被推迟到实现发生写入的时候才进行。

fork()具体执行流程如下

线程在linux中的实现:

在内核中,线程被看成一个普通的进程,每个线程都拥有一个唯一的task_struct。在同一程序内共享内存地址空间的一组线程还可以共享打开的文件和其他资源。

创建线程:

现成的创建和普通进程的创建类似,只不过需要在调用clone()传递一些参数标志来指明共享的资源。

 

内核线程:

内核经常需要在后台完成一些操作需要内核线程完成,内核线程是独立运行在内核空间的标准进程,它们没有独立的地址空间,只在内核空间运行,不会被切换到用户空间去。从现有内核进程创建一个新的进程方法如下:

        

 

内核线程启动后就一直运行知道调用do_exit()退出或者内核其他部分调用kthread_stop()退出。

进程终结:

主要分为以下两个阶段:

 

do_exit()主要做以下工作:                                                                                                                  

 

 

转载于:https://www.cnblogs.com/lzh-blog/p/8576293.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值