嵌入式操作系统进程.ppt

上传人:牧羊曲112 文档编号:6414956 上传时间:2023-10-28 格式:PPT 页数:122 大小:983KB
返回 下载 相关 举报
嵌入式操作系统进程.ppt_第1页
第1页 / 共122页
嵌入式操作系统进程.ppt_第2页
第2页 / 共122页
嵌入式操作系统进程.ppt_第3页
第3页 / 共122页
嵌入式操作系统进程.ppt_第4页
第4页 / 共122页
嵌入式操作系统进程.ppt_第5页
第5页 / 共122页
点击查看更多>>
资源描述

《嵌入式操作系统进程.ppt》由会员分享,可在线阅读,更多相关《嵌入式操作系统进程.ppt(122页珍藏版)》请在三一办公上搜索。

1、第五章操作系统进程,在Linux系统中,进程操作。需要掌握以下基本内容进程的基本概念Linux进程及进程创建Linux进程系统调用Linux进程调度,学习目标,主要内容,1,3,2,4,进程的基本概念,Linux系统进程,Linux进程的创建,Linux进程的系统调用,5,Linux进程调度,一、进程的基本概念,进程的基本概念进程的状态及转换进程的组成,在传统的操作系统中,程序并不能独立运行,作为资源分配和独立运行的基本单元都是进程。程序是一个普通文件,是机器代码指令和数据的集合,这些指令和数据存储在磁盘上的一个可执行映象(Executable Image)中。进程是程序的一次“动态执行”,也

2、就是说进程是“执行中的程序”。每一个进程都有自己的地址空间,包括文本区域、数据区域和堆栈区域。,1、进程的基本概念,一、进程的基本概念,进程是由正文段(Text)、用户数据段(User Segment)以及系统数据段(System Segment)共同组成的一个执行环境,它是一个动态实体。相对的,程序是硬盘上存放的一个文件(代码)。当程序被运行,它也就成为了进程。,1、进程的基本概念,一、进程的基本概念,线程是系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元。对于操作系统来说,其调度单元是线程。一个进程至少包括一个线程,通常将该线程称为主线程。一个进程从主线程的执行开始进而创

3、建一个或多个附加线程,就是所谓基于多线程的多任务。在Linux 2.6内核中,Linux采用了更为先进的线程模型:NPTL(Native POSIX Thread Library)。与传统的LinuxThreads线程模型比,NPTL与POSIX标准兼容,并且性能提升明显,也具备更好的可伸缩性。对Linux内核而言,线程和进程没有本质的区别,它们都是调度的基本单位(实际上,Linux内核基于进程机制实现线程),本书重点介绍进程的内容。,1、进程的基本概念,一、进程的基本概念,1、进程的基本概念,一、进程的基本概念,进程和程序区别和联系(1)动态性和静态性。(2)从结构上看每个进程的实体都是由程

4、序段和相应的数据段两部分构成的,这一特征与程序的含义相近。(3)一个进程可以涉及到一个或几个程序的执行;反之一程序可以对应多个进程,即同一程序段可在不同数据集合上运行,可构成不同的进程。,2、进程的状态及其转换,一、进程的基本概念,(1)运行状态:进程正在处理机上运行的状态,该进程已获得必要的资源,也获得了处理机,用户程序正在处理机上运行。(2)阻塞状态:进程等待某种事件完成(例如,等待输入/输出操作的完成)而暂时不能运行的状态,处于该状态的进程不能参加竞争处理机,此时,即使分配给它处理机,它也不能运行。(3)就绪状态:该进程运行所需的一切条件都得到满足,但因处理机资源个数少于进程个数,所以该

5、进程不能运行,而必须等待分配处理机资源,一旦获得处理机就立即投入运行。,2、进程的状态及其转换,一、进程的基本概念,2、进程的状态及其转换,一、进程的基本概念,3、进程的组成,一、进程的基本概念,进程实体一般由程序段、数据段和进程控制块(PCB)这三部分组成。其中进程的程序段就是该进程所对应的可执行程序。而数据段就是该程序运行过程中要用到的数据或工作区。,3、进程的组成,一、进程的基本概念,进程控制块作用每个进程有唯一进程控制块操作系统根据PCB对进程实施控制盒管理,记录进程动态、并发等运行特征PCB是进程存在的唯一标志当系统或父进程创建一个进程时,实际上就是为其建立一个进程控制块。进程控制块

6、既能标识进程的存在,又能刻画出进程的动态特征,它是一个进程仅有的被系统真正感知的部分。对操作系统而言,所有进程控制块将构成并发执行控制和维护系统工作的依据。,3、进程的组成,一、进程的基本概念,主要内容,1,3,2,4,进程的基本概念,Linux系统进程,Linux进程的创建,Linux进程的系统调用,5,Linux进程调度,二、Linux系统进程,Linux进程的基础进程的描述符进程的状态与转换进程队列指针进程队列的全局变量,1、Linux进程基础,二、Linux系统进程,Linux进程一般分为交互进程、批处理进程和守护进程三类。与Windows任务管理器一样,在Linux中可以通过ps命令

7、查看系统当前的进程,例如下面的命令列出系统所有的进程:rootlocalhost#ps-aux如果进程太多,可以把ps命令的输出保存到一个文件中:rootlocalhost#ps-aux mypsoutps是Linux进程管理中最重要的一个命令,它提供了很多的选项参数,1、Linux进程基础,二、Linux系统进程,ps的输出列说明,1、Linux进程基础,二、Linux系统进程,ps命令的选项参数,1、Linux进程基础,二、Linux系统进程,Linux进程状态,1、Linux进程基础,二、Linux系统进程,Linux系统中的进程都具有以下4个要素。(1)有一个程序正文段供其执行。(2)

8、有进程专用的系统堆栈空间。(3)有一个进程描述符,即在内核中的一个task_struct数据结构。有了这个数据结构,进程才能成为内核调度的一个基本单位,接受内核的调度。同时,该结构还记录着进程所占用的各项资源。(4)有一个独立的地址空间,即拥有专有的用户空间和专用的用户空间堆栈。,1、Linux进程基础,二、Linux系统进程,Linux的进程状态共有6种。(1)TASK_RUNNING:正在运行(己获得CPU)或准备运行(就绪态等待获得CPU)的进程。(2)TASK_INTERRUPTIBLE:可中断等待状态。进程处于等待队列中,一旦资源可用时被唤醒,也可以由其他进程通过信号(SIGNAL)

9、或中断唤醒。(3)TASK_UNINTERRUPTIBLE:不可中断等待状态。进程处于等待队列中,一旦资源可用时被唤醒,但不可以由其他进程通过信号(SIGNAL)或中断唤醒。(4)TASK_ZOMBIE:进程僵死状态。进程停止运行但是尚未释放PCB。(5)TASK_STOPPED:进程停止状态。可能被特定信号终止,也可能是受其他进程的跟踪调用而暂时将CPU出让给跟踪它的进程。(6)TASK_SWAPPING:页面被交换出内存的进程。,2、Linux进程描述符,二、Linux系统进程,Linux系统的每一个可调度实体都有一个进程描述符。进程描述符可以表示进程的各种状态信息,是内核操作进程的手段。

10、进程描述符用task_struct数据结构表示,该结构包含了一个进程所拥有的各种信息,非常庞大,在内核文件的includelinux sched.h中定义。task_struct就是Linux系统中的PCB。系统内核中还有一个task向量表,是指向系统中每一个task_struct数据结构的指针的task数组。因而task向量表就是Linux系统中的PCB表。在创建一个新进程时,系统在内存中申请一个空的task_struct区,即空闲PCB块,并填入所需信息,同时将指向该结构的指针填入到task数组中。,2、Linux进程描述符,二、Linux系统进程,Linux系统的PCB包括很多参数,每个

11、PCB约占1KB多的内存空间。用于表示PCB的结构task_struct简要描述如下:struct task_structvolatile long state;unsigned short uid;int pid;int processor;.;(见P100)传统上,这样的数据结构被叫作进程控制块(PCB process control block),2、Linux进程描述符,二、Linux系统进程,Task_struct结构的描述:进程标识进程状态(State)进程调度信息和策略标识号(Identifiers)进程通信有关的信息(IPC)进程链接信息(Links)时间和定时器信息(Time

12、s and Timers)文件系统信息(Files System)处理器相关的上下文信息,2、Linux进程描述符,二、Linux系统进程,2、Linux进程描述符,二、Linux系统进程,标识信息:用简单数字对进程进行标识pid_t pid;进程标识号pid_t pgrp;进程组标识号pid_t tty_old_pgrp;进程控制终端所在的组标识 pid_t session;进程所在的会话标识号 pid_t tgid;线程组号int leader;布尔量,标志,表示进程是否为会话主管 状态信息:描述进程动态的变化调度信息:描述进程优先级、调度策略等信息进程间通信信息:描述多个进程在同一任务上

13、协作工作虚拟内存信息:描述每个进程拥有的地址空间时间和定时器信息:描述进程在生命周期内使用CPU统计、计费等信息,进程标识符:每一个进程都有一个唯一的标识符,内核通过这个标识符来识别不同的进程。进程标识符PID也是内核提供给用户程序的接口,用户程序通过PID对进程发号施令。PID是32位的无符号整数,它被顺序编号每个进程都属于某个用户组task_struct结构中定义有用户标识符UID(user identifier)和组标识符GID(Group identifier)这两种标识符拥有系统的安全控制系统通过这两种标识符控制进程对系统中文件和设备的访问,2、Linux进程描述符,二、Linux系

14、统进程,3、Linux进程状态及转换,二、Linux系统进程,状态信息:Linux的进程状态 state(include/linux/sched.h)若进程可运行,则state的取值如下所示:#define TASK_RUNNING 0/*R执行态*/#define TASK_INTERRUPTIBLE 1/*S可中断睡眠*/#define TASK_UNINTERRUPTIBLE 2/*D不可中断睡眠*/#define TASK_ZOMBIE 4/*Z僵死状态,退出状态*/#define TASK_STOPPED 8/*T暂停状态或跟踪状态*/#define TASK_EXCLUSIVE 3

15、2/*T排他状态,不可独立使用,必须与TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE合用。EXIT_DEAD/*X退出状态,进程即将被销毁*/TASK_DEAD/*死亡状态*/,在内核源代码中的定义如下:/usr/src/linux/fs/proc/array.c static const char*task_state_array=R(running),/*0*/S(sleeping),/*1*/D(disk sleep),/*2*/T(stopped),/*4*/T(tracing stop),/*8*/Z(zombie),/*16*/X(dead)/*32

16、*/;内核 2.6.26 中的新状态定义#define TASK_KILLABLE#define TASK_STOPPED#define TASK_TRACED,3、Linux进程状态及转换,二、Linux系统进程,Linux的进程状态 state,二、Linux系统进程,状态信息:Linux有10个进程标志(process flags)。PF_ALIGNWARN 打印“对齐”警告信息。PF_PTRACED 被ptrace系统调用监控。PF_TRACESYS 正在跟踪。PF_FORKNOEXEC 进程刚创建,但还没执行。PF_SUPERPRIV 超级用户特权。PF_DUMPCORE dumpe

17、d core。PF_SIGNALED 进程被信号(signal)杀出。PF_STARTING 进程正被创建。PF_EXITING 进程开始关闭。PF_USEDFPU 该进程使用FPU(SMP only)。PF_DTRACE delayed trace(used on m68k)。,3、Linux进程状态及转换,进程间状态转换:,3、Linux进程的状态与转换,二、Linux系统进程,3、Linux进程的状态与转换,二、Linux系统进程,获得CPU,若申请不到某个资源,则调用sleep_on()或interruptible_sleep_on()睡眠,其task_struct挂到相应的等待队列。

18、sleep_on()或interruptible_sleep_on()将调用schedule()函数把睡眠进程释放的CPU分配给run-queue队列的某个就绪进程。状态为TASK_INTERRUPTIBLE申请的资源有效时被唤醒(如wake_up_interruptible()),也可以由信号(signal)或定时中断唤醒。而状态为TASK_UNINTERRUPTIBLE申请的资源有效时被唤醒(如wake_up(),唤醒后,进程状态改为TASK_RUNNING,并进入运行队列。进程执行系统调用sys_exit()或收到SIG_KILL信号而调用do_exit()时,进程状态变为TASK_ZO

19、MBIE,释放所申请资源。通过启动schedule()把CPU分配给其它就绪进程。若进程通过系统调用设置PF_SYSTRACE,则在系统进入ptrace(),状态变为TASK_STOPPED,CPU分配给其它就绪进程。只有通过其它进程发送SIG_KILL或SIG_CONT,才能唤醒进程,重新进入运行队列。,(1)分析不可被中断的睡眠进程:终端1)rootlocalhost state#vi testu.c#include void main()if(!vfork()sleep(100);rootlocalhost state#gcc testu.c-o testu./testu终端2)root

20、localhost state#ps aux|grep testuroot 24773 0.0 0.0 1336 224 pts/2 D 15:34 0:00./testuroot 24840 0.0 0.2 4816 640 pts/3 S 15:36 0:00 grep testu,3、Linux进程的状态与转换,二、Linux系统进程,(2)分析被跟踪或被停止的进程状态(T):终端1)rootlocalhost state#strace top终端2)rootlocalhost state#ps auxf|grep toproot 24978 4.3 0.2 1552 552 pts/2

21、 S 15:42 0:00|_ strace toproot 24979 2.6 0.3 5156 960 pts/2 T 15:42 0:00|_ toproot 24981 0.0 0.2 4812 636 pts/3 S 15:42 0:00 _ grep top,3、Linux进程的状态与转换,二、Linux系统进程,(2)分析进程的可中断睡眠态与运行态:终端1)rootlocalhost state#vi pisqrt.c编译链接后:rootlocalhost state#gcc-Wall-o pisqrt pisqrt.c-lm 监控pisqrt进程 rootlocalhost s

22、tate#watch-n 1 ps aux|grep pisqrt|grep-v ps|awk print$2|sort-k 8终端2)rootlocalhost state#strace./pisqrt.read(3,177ELF11100000000030301000200X1.,512)=512fstat64(3,st_mode=S_IFREG|0755,st_size=1572440,.)=0old_mmap(NULL,1279916,PROT_READ|PROT_EXEC,MAP_PRIVATE,3,0)=0 x49e000,3、Linux进程的状态与转换,二、Linux系统进程,#

23、include#include#include#include void run_status(void)double pi=M_PI;double pisqrt;long i;for(i=0;i100000000;+i)pisqrt=sqrt(pi);int main(void)run_status();sleep(10);run_status();exit(EXIT_SUCCESS);,(2)分析进程的可中断睡眠态与运行态:此时切换到终端1看pisqrt进程状态,此时为R状态:root 3792 99.9 0.0 1516 268 pts/2 R 02:40 0:01./pisqrtroo

24、t 3801 0.0 0.0 3700 672 pts/1 S 02:40 0:00 grep pisqrtroot 3791 1.0 0.0 1728 564 pts/2 S 02:40 0:00 strace./pisqr 之后pisqrt进程进入S状态,因为执行了sleep(10)函数,10秒之后pisqrt再次进入R状态,最终退出。,3、Linux进程的状态与转换,二、Linux系统进程,(3)分析进程的僵死态(Z):终端1)rootlocalhost state#vi testz.c编译链接后:rootlocalhost state#gcc-Wall-o testz testz.c监

25、控testz进程 rootlocalhost state#watch-n 1 ps aux|grep testz|grep-v ps|awk print$2|sort-k 8“终端2)rootlocalhost state#./testz查看终端1:root 5402 0.0 0.0 1380 240 pts/3 S 16:05 0:00|_./testz root 5401 0.0 0.0 0 0 pts/3 Z 16:05 0:00|_ testz 20秒后查看终端2:child pid=5401 parent pid=5402,3、Linux进程的状态与转换,二、Linux系统进程,#i

26、nclude#include#include#include#include int main()if(!fork()printf(child pid=%dn,getpid();exit(5);sleep(20);printf(parent pid=%dn,getpid();exit(EXIT_SUCCESS);,4、Linux进程的队列指针,二、Linux系统进程,操作系统以队列方式管理进程。主要有线性方式、链表方式和索引方式。1)线性表方式:不论进程的状态如何,将所有的PCB连续地存放在内存的系统区。这种方式适用于系统中进程数目不多的情况。2)索引表方式:该方式是线性表方式的改进,系统按照

27、进程的状态分别建立就绪索引表、阻塞索引表等。3)链接表方式:系统按照进程的状态将进程的PCB组成队列,从而形成就绪队列、阻塞队列、运行队列等,4、Linux进程的队列指针,二、Linux系统进程,线性表方式:空间固定、查找费时索引方式:空间整齐、容易维护,4、Linux进程的队列指针,二、Linux系统进程,链接方式:构建方便、容易维护,4、Linux进程的队列指针,二、Linux系统进程,为了有效的管理系统中的每个进程,需要采用一种高效的数据结构把系统内全部进程组织起来。在需要进程的信息时,可以从该结构中查找到相关进程。Linux的所有进程组成一个双向链表。task_struct中的stru

28、ct task_struct*next_task,*prev_task;,task_struct中的struct list_head run_list;list_head是Linux内核当中定义的一个数据结构用来实现双向链表,Linux内核中使用上百个双向链表来存放各种数据结(usr/src/linux/include/list.h),提供了用来操作该链表的函数和宏,它们实现了对链表的插入、删除、转移、合并、遍历。,4、Linux进程的队列指针,二、Linux系统进程,在Linux中,内核使用current变量表示当前正在运行的进程。current是一个task_struct类型的全局变量。t

29、ask_struct 结构中成员void*stack就是指向下面的内核栈结构体的“栈底”,在系统运行的时候,宏current获得的就是当前进程的struct task_struct结构体。进程通过alloc_thread_info函数分配它的内核栈,通过free_thread_info函数释放所分配的内核栈。,5、Linux进程的队列全局变量,二、Linux系统进程,其中,THREAD_SIZE_ORDER宏在/asm/thread_info.h文件中被定义为1,也就是说alloc_thread_info函数通过调用_get_free_pages函数分配2个页的内存(它的首地址是8192字节对

30、齐的)。Linux内核通过thread_union联合体来表示进程的内核栈,其中THREAD_SIZE宏的大小为8192。,5、Linux进程的队列全局变量,二、Linux系统进程,当进程从用户态切换到内核态时,进程的内核栈总是空的,所以ARM的sp寄存器指向这个栈的顶端。因此,内核能够轻易地通过sp寄存器获得当前正在CPU上运行的进程。,5、Linux进程的队列全局变量,二、Linux系统进程,struct thread_info是记录部分进程信息的结构体,其中包括了进程上下文信息。关键是其中的task成员,指向的是所创建的进程的struct task_struct结构体。而其中的stack

31、成员就是内核栈。从这里可以看出内核栈空间和 thread_info是共用一块空间。thread_info结构的第一个成员就是一个指向task_struct结构的指针,所以要用current_thread_info()-task表示task_struct的地址,但是整个过程对用户是完全透明的,还是可以用current表示当前进程。,5、Linux进程的队列全局变量,二、Linux系统进程,struct thread_info struct task_struct*task;/*main task structure*/struct exec_domain*exec_domain;/*execut

32、ion domain*/unsigned long flags;/*low level flags*/unsigned long status;/*thread-synchronous flags*/.,5、Linux进程的队列全局变量,二、Linux系统进程,内核栈-struct thread_info-struct task_struct三者的关系如下图:,4KB*2=8192B,1KB,7KB,主要内容,1,3,2,4,进程的基本概念,Linux系统进程,Linux进程的创建,Linux进程的系统调用,5,Linux进程调度,三、Linux进程的创建,fork()函数进程之间的关系ini

33、t进程Linux进程创建过程,1、fork()函数,三、Linux进程的创建,Linux中一般进程都是由现有的一个进程创建的,也就是我们所说的父进程,子进程。具体的创建是通过fork()实现的。fork()这个函数名是英文中“分叉”的意思。因为一个进程在运行中,如果使用了fork,就产生了另一个进程,于是进程就分叉了,所以这个名字取得很形象。fork的语法:#include#include pid_t fork();/pid_t是系统定义的类型,一般被定义为short int。,2、进程之间关系,三、Linux进程的创建,进程之间的父子关系,每个进程只有一个父进程,但可以有0个、1个、2个或多

34、个子进程。,三、Linux进程的创建,进程之间的父子关系,2、进程之间关系,3、init进程,三、Linux进程的创建,Linux在启动时就创建一个称为init的特殊进程,其进程标识符PID为1,它是用户态下所有进程的祖先进程,以后诞生的所有进程都是它的子进程 或是它的儿子,或是它的孙子。1号进程运行时查询系统当前存在的终端数,然后为每个终端创建一个新的管理进程,这些进程在终端上等待着用户的登录。当用户正确登录后,系统再为每一个用户启动一个shell进程,由shell进程等待并接受用户输入的命令。,rootlocalhost root#ps auxUSER PID%CPU%MEM VSZ RS

35、S TTY STAT START TIME COMMANDroot 1 0.0 0.0 1368 92?S 06:53 0:04 initroot 2 0.0 0.0 0 0?SW 06:53 0:00 keventd.,4、Linux进程创建过程,三、Linux进程的创建,4、Linux进程创建过程,三、Linux进程的创建,在 Linux 内核中,供用户创建进程的体系调用fork()函数的相应函数是 sys_fork()、sys_clone()、sys_vfork()。这三个函数都是通过调用内核函数 do_fork()来实现的。按照调用时所应用 的 clone_flags 参数差别,do_

36、fork()函数完成的事件也各异。sys_fork和sys_vfork在arch/um/kernel/syscall.c文件中实现,sys_clone函数在arch/um/sys-i386/syscall.c文件中实现,4、Linux进程创建过程,三、Linux进程的创建,在kernel/fork.c文件内找到 do_fork函数原型 long do_fork(unsigned long clone_flags,/克隆标识 unsigned long stack_start,/栈起始位置 struct pt_regs*regs,/指向通用寄存器值的指针 unsigned long stack_

37、size,/栈大小,一般设置为0 int _user*parent_tidptr,/父进程在用户态下pid的地址,该参数在CLONE_PARENT_SETTID标志被设定时有意义;int _user*child_tidptr)/子进程在用户态下pid的地址,该参数在CLONE_CHILD_SETTID标志被设定时有意义。,4、Linux进程创建过程,三、Linux进程的创建,clone_flags:该标志位的4个字节分为两部分。最低的一个字节为子进程结束时发送给父进程的信号代码,通常为SIGCHLD;剩余的三个字节则是各种clone标志的组合,也就是若干个标志之间的或运算。通过clone标志可

38、以有选择的对父进程的资源进行复制;常见的clone标志:,4、Linux进程创建过程,三、Linux进程的创建,do_fork函数的主要作用就是复制原来的进程成为另一个新的进程,它完成了整个进程创建中的大部分工作,do_fork函数中比较重要的有两个部分,首先是给子进程分配进程号,然后是利用具体的进程号创建子进程。do_fork()函数程序代码位于 kernel/fork.c 文件中。下面是do_fork()函数执行的主要过程:,4、Linux进程创建过程,三、Linux进程的创建,(1)一开始,该函数定义了一个task_struct类型的指针p,用来接收即将为新进程(子进程)所分配的进程描述

39、符。紧接着使用alloc_pidmap函数为这个新进程分配一个pid。由于系统内的pid是循环使用的,所以采用位图方式来管理。简单的说,就是用每一位(bit)来标识该位所对应的pid是否被使用。分配完毕后,判断pid是否分配成功。,long do_fork(unsigned long clone_flags,unsigned long stack_start,struct pt_regs*regs,unsigned long stack_size,int _user*parent_tidptr,int _user*child_tidptr)struct task_struct*p;int tr

40、ace=0;long pid=alloc_pidmap();if(pid 0)return-EAGAIN;.,4、Linux进程创建过程,三、Linux进程的创建,(2)接下来检查当前进程(父进程)的ptrace字段。ptrace是用来标示一个进程是否被另外一个进程所跟踪。所谓跟踪,最常见的例子就是处于调试状态下的进程被debugger进程所跟踪。父进程的ptrace字段非0时说明debugger程序正在跟踪父进程,那么接下来通过fork_traceflag函数来检测子进程是否也要被跟踪。如果trace为1,那么就将跟踪标志CLONE_PTRACE加入标志变量clone_flags中。通常上述

41、的跟踪情况是很少发生的,因此在判断父进程的ptrace字段时使用了unlikely修饰符。使用该修饰符的判断语句执行结果与普通判断语句相同,只不过在执行效率上有所不同。正如该单词的含义所表示的那样,current-ptrace很少为非0。因此,编译器尽量不会把if内的语句与当前语句之前的代码编译在一起,以增加cache的命中率。与此相反,likely修饰符则表示所修饰的代码很可能发生。,if(unlikely(current-ptrace)trace=fork_traceflag(clone_flags);if(trace)clone_flags|=CLONE_PTRACE;,4、Linux进

42、程创建过程,三、Linux进程的创建,(3)接下来的这条语句要做的是整个创建过程中最核心的工作:通过copy_process()创建子进程的描述符,并创建子进程执行时所需的其他数据结构,最终则会返回这个创建好的进程描述符。该函数中的参数意义与do_fork函数相同。copy_process()函数主要用来创建子进程的描述符(PCB)以及与子进程相关数据结构。这个函数内部实现较为复杂,在短时间内,对于内部详细代码原理和实现不能完全理解,自己业余深入学习。,p=copy_process(clone_flags,stack_start,regs,stack_size,parent_tidptr,ch

43、ild_tidptr,pid);,4、Linux进程创建过程,三、Linux进程的创建,(4)如果copy_process函数执行成功,那么将继续下面的代码。首先定义了一个完成量vfork,如果clone_flags包含CLONE_VFORK标志,那么将进程描述符中的vfork_done字段指向这个完成量,之后再对vfork完成量进行初始化。完成量的作用是,直到任务A发出信号通知任务B发生了某个特定事件时,任务B才会开始执行;否则任务B一直等待。我们知道,如果使用vfork系统调用来创建子进程,那么必然是子进程先执行。究其原因就是此处vfork完成量所起到的作用:当子进程调用exec函数或退出

44、时就向父进程发出信号。此时,父进程才会被唤醒;否则一直等待。此处的代码只是对完成量进行初始化,具体的阻塞语句则在后面的代码中有所体现。,if(!IS_ERR(p)struct completion vfork;if(clone_flags,4、Linux进程创建过程,三、Linux进程的创建,(5)如果子进程被跟踪或者设置了CLONE_STOPPED标志,那么通过sigaddset函数为子进程增加挂起信号。signal对应一个unsigned long类型的变量,该变量的每个位分别对应一种信号。具体的操作是,将SIGSTOP信号所对应的那一位置1。,if(p-ptrace,4、Linux进程创

45、建过程,三、Linux进程的创建,(6)如果子进程并未设置CLONE_STOPPED标志,那么通过wake_up_new_task函数使得父子进程之一优先运行;否则,将子进程的状态设置为TASK_STOPPED。,if(!(clone_flags,4、Linux进程创建过程,三、Linux进程的创建,(7)如果父进程被跟踪,则将子进程的pid赋值给父进程的进程描述符的pstrace_message字段。再通过ptrace_notify函数使得当前进程定制,并向父进程的父进程发送SIGCHLD信号。,if(unlikely(trace)current-ptrace_message=pid;ptr

46、ace_notify(trace 8)|SIGTRAP);,4、Linux进程创建过程,三、Linux进程的创建,(8)如果CLONE_VFORK标志被设置,则通过wait操作将父进程阻塞,直至子进程调用exec函数或者退出。,if(clone_flags,4、Linux进程创建过程,三、Linux进程的创建,(9)如果copy_process()在执行的时候发生错误,则先释放已分配的pid;再根据PTR_ERR()的返回值得到错误代码,保存于pid中。(10)返回pid。这也就是为什么使用fork系统调用时父进程会返回子进程pid的原因。至于为什么子进程会返回0则在copy_process(

47、)中有所体现。,else free_pidmap(pid);pid=PTR_ERR(p);,主要内容,1,3,2,4,进程的基本概念,Linux系统进程,Linux进程的创建,Linux进程的系统调用,5,Linux进程调度,四、Linux进程相关的系统调用,fork()函数调用Linux进程关系execve()系统调用wait()系统调用exit()系统调用,1、fork()函数调用,四、Linux进程相关的系统调用,这里看一个最简单的调用示例。fork函数 有三种返回值:父进程中,fork返回新创建的子进程的ID子进程中,fork返回0如果出现错误,fork返回一个负数,#include#

48、include“unistd.h”#includesys/types.hint main(void)pid_t pid=fork();printf(My process ID is%d.n,getpid();return 0;,fork函数是分裂创建进程的,这也就是fork(分叉)命名的原因吧。如何理解这个“分裂”呢,,四、Linux进程相关的系统调用,#include#include“unistd.h”#includesys/types.hint main(void)pid_t pid=fork();if(pid 0)printf(Im parent process.);/*父进程的pid大

49、于0*/printf(Parent process is running,ChildPid is%d,ParentPid is%dn,pid,getpid();else if(pid=0)printf(Im child process.);/*子进程的pid等于0*/printf(Child process is running,CurPid is%d,ParentPid is%dn,pid,getppid();else printf(Cannot create process.n);/*如果pid小于0,表示出错*/return 0;,1、fork()函数调用,四、Linux进程相关的系统调

50、用,所以fork调用后有2个进程在同时执行后面的代码。如何区分呢?在父进程中,pid变量被标记为一个正整数;而子进程的pid被标记为0;当然,当pid为负数时,系统只有1个进程运行,表示创建进程出错。看下面这个程序:,#include#include“unistd.h”#includesys/types.hint main(void)pid_t pid1,pid2,pid3;pid1=fork();pid2=fork();pid3=fork();printf(Im a process.n);return 0;,1、fork()函数调用,四、Linux进程相关的系统调用,父进程和子进程共享打开的

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号