资源预览内容
第1页 / 共29页
第2页 / 共29页
第3页 / 共29页
第4页 / 共29页
第5页 / 共29页
第6页 / 共29页
第7页 / 共29页
第8页 / 共29页
第9页 / 共29页
第10页 / 共29页
亲,该文档总共29页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
嵌入式Linux操作系统 第5章 操作系统进程,www.embedu.org,2,第1章 嵌入式Linux操作系统简介 第2章 Linux操作系统使用与系统配置 第3章 嵌入式Linux编程环境 第4章 存储管理 第5章 操作系统进程 第6章 进程间通信 第7章 中断与系统调用 第8章 文件管理 第9章 设备管理 第10章 嵌入式Linux的构建,课程安排:,www.embedu.org,3,第5章 操作系统进程 5.1 进程的基本概念 5.2 Linux系统进程 5.3 Linux进程的创建 5.4 Linux进程相关的系统调用 5.5 Linux的进程调度 5.6 实时Linux 思考题,本章课程:,www.embedu.org,4,5.1 进程的基本概念,在传统的操作系统中,程序并不能独立运行,作为资源分配和独立运行的基本单元都是进程。程序是一个普通文件,是机器代码指令和数据的集合,这些指令和数据存储在磁盘上的一个可执行映象(Executable Image)中。进程是由正文段(Text)、用户数据段(User Segment)以及系统数据段(System Segment)共同组成的一个执行环境,它是一个动态实体。相对的,程序是硬盘上存放的一个文件(代码)。当程序被运行,它也就成为了进程。 程序和进程的区别:,www.embedu.org,5,5.1 进程的基本概念,进程的组成部分如下: 正文段:存放被执行的机器指令。这个段是只读的,它允许系统中正在运行的两个或多个进程之间能够共享这一代码,但是不能对其内容进行更改。 用户数据段:存放进程在执行时直接进行操作的所有数据,包括进程使用的全部变量在内。显然,这里包含的信息可以被改变。虽然进程之间可以共享正文段,但是每个进程需要有它自己的专用用户数据段。 系统数据段:该段有效地存放程序运行的环境。如上图所示,这也是进程和程序的不同的一个原因之一。,www.embedu.org,6,5.1 进程的基本概念,Windows和Linux操作系统都属于多任务系统,可以同时运行多个进程。我们经常使用的Windows任务管理器可以清楚的列出当前系统运行的进程 线程是系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元。对于操作系统来说,其调度单元是线程。一个进程至少包括一个线程,通常将该线程称为主线程。一个进程从主线程的执行开始进而创建一个或多个附加线程,就是所谓基于多线程的多任务。 在Linux 2.6内核中,Linux采用了更为先进的线程模型:NPTL(Native POSIX Thread Library)。与传统的LinuxThreads线程模型比,NPTL与POSIX标准兼容,并且性能提升明显,也具备更好的可伸缩性。对Linux内核而言,线程和进程没有本质的区别,它们都是调度的基本单位(实际上,Linux内核基于进程机制实现线程),本书重点介绍进程的内容。,www.embedu.org,7,5.2 Linux系统进程,5.2.1 Linux进程基础 Linux进程一般分为交互进程、批处理进程和守护进程三类。与Windows任务管理器一样,我们在Linux中可以通过ps命令查看系统当前的进程,例如下面的命令列出系统所有的进程: rootlocalhost # ps -aux 如果进程太多,可以把ps命令的输出保存到一个文件中: rootlocalhost # ps -aux mypsout ps是Linux进程管理中最重要的一个命令,它提供了很多的选项参数 ps命令的选项参数,www.embedu.org,8,5.2 Linux系统进程,5.2.1 Linux进程基础 ps的输出列说明: Linux进程状态:,www.embedu.org,9,5.2 Linux系统进程,5.2.2 进程描述符 Linux系统的每一个可调度实体都有一个进程描述符。进程描述符可以表示进程的各种状态信息,是内核操作进程的手段。进程描述符用task_struct数据结构表示,该结构包含了一个进程所拥有的各种信息,非常庞大,在内核文件的sched.h中定义。 每一个进程都有自己的进程号,该数字在系统中是唯一的,它存放在进程描述符的成员变量pid中: pid_t pid; 同样的,线程组号存放在成员变量tgid中: pid_t tpid; 这个结构大致可以分为以下几类: 进程状态。将纪录进程在等待、运行、或死锁; 调度信息。由哪个调度函数调度,怎样调度等; 进程的通讯状况; 因为要插入进程树,必须有联系父子兄弟的指针; 时间信息。比如计算好执行的时间,以便cpu 分配; 标号。决定改进程归属; 可以读写打开的一些文件信息; 进程上下文和内核上下文; 处理器上下文; 内存信息。,www.embedu.org,10,5.2 Linux系统进程,5.2.3 进程的状态与转换 进程对系统资源的竞争和进程之间的并发执行,使得一个进程在从创建到销毁的这个生命周期内要经历各种不同的状态的变化。一个进程的各种状态在task_struct结构中通过成员变量state、exit_state记录。 Linux系统通过一系列机制, 每个进程的状态不断转换, 从而实现多任务同时进行, 其状态转换图如图,www.embedu.org,11,5.2 Linux系统进程,5.2.3 进程的状态与转换 获得CPU而正在运行的进程若申请不到某个资源,则调用sleep_on()或interruptible_sleep_on()睡眠,其task_struct挂到相应的等待队列。如果调用sleep_on()睡眠,则其状态变为TASK_UNINTERRUPTIBLE。或者,如果调用interruptible_sleep_on()睡眠,则其状态变为TASK_INTERRUPTIBLE。sleep_on()或interruptible_sleep_on()将调用schedule()函数把睡眠进程释放的CPU分配给run-queue队列的某个就绪进程。 状态为TASK_INTERRUPTIBLE的睡眠进程当它申请的资源有效时被唤醒(如wake_up_interruptible()),也可以由信号(signal)或定时中断唤醒。而状态为TASK_UNINTERRUPTIBLE的睡眠进程只有当它申请的资源有效时被唤醒(如wake_up()),不能被信号(signal)、定时中断唤醒。唤醒后,进程状态改为TASK_RUNNING,并进入运行队列。 进程执行系统调用sys_exit()或收到SIG_KILL信号而调用do_exit()时,进程状态变为TASK_ZOMBIE,释放所申请资源。同时启动schedule()把CPU分配给运行队列中其它就绪进程。若进程通过系统调用设置PF_SYSTRACE,则在系统调用返回前,进入ptrace(),状态变为TASK_STOPPED,CPU分配给运行队列中其它就绪进程。只有通过其它进程发送SIG_KILL或SIG_CONT,才能把TASK_STOPPED进程唤醒。重新进入运行队列。,www.embedu.org,12,5.2 Linux系统进程,5.2.4 进程队列指针 为了有效的管理系统中的每个进程,需要采用一种高效的数据结构把系统内全部进程组织起来。在需要进程的信息时,可以从该结构中查找到相关进程。Linux的所有进程组成一个双向链表,在内核中的类型是struct list_head的成员变量tasks: struct list_head tasks; list_head结构体在include/linux/list.h文件中定义。 struct list_head struct list_head *next, *prev; ; 在include/linux/list.h文件中,提供了用来操作该链表的函数和宏,它们实现了对链表的插入、删除、转移、合并、遍历。,www.embedu.org,13,5.2 Linux系统进程,5.2.5 进程队列的全局变量 在Linux中,内核使用current变量表示当前正在运行的进程。current是一个task_struct类型的全局变量。下面的语句可以打印当前进程:printk( “Current task is %s %d, current-comm, current-pid ); 打开arch/arm/include/asm/current.h头文件,可以了解到current只是一个宏定义: static inline struct task_struct *get_current(void) _attribute_const_; static inline struct task_struct *get_current(void) return current_thread_info()-task; #define current (get_current() current_thread_info函数用来获得当前进程地址信息,代码及解释如下: static inline struct thread_info *current_thread_info(void) register unsigned long sp asm (“sp“); return (struct thread_info *)(sp 在ARM平台中,内核栈是8K字节,在栈顶(最低地址)处存放了一个指向当前进程的task_struct的指针,而sp就是当前的内核态堆栈指针,把它和8191进行“与”操作(清空最后13位),即获得栈顶的地址。然后把里面的值赋给current,这样current就得到了当前task_struct的指针。THREAD_SIZE在thread_info.h文件中有定义: #define THREAD_SIZE 8192 #define THREAD_START_SP (THREAD_SIZE - 8),www.embedu.org,14,5.2 Linux系统进程,5.2.5 进程队列的全局变量 thread_info.h文件中定义的thread_info结构如下: struct thread_info struct task_struct *task; /* main task structure */ struct exec_domain *exec_domain; /* execution domain */ unsigned long flags; /* low level flags */ _u32 cpu; /* current CPU */ int preempt_count; /* 0 = preemptable, BUG */ mm_segment_t addr_limit; /* thread address space: 0-0xBFFFFFFF for user 0-0xFFFFFFFF for kernel */ struct restart_block restart_block; struct thread_info *real_thread; /* Points to non-IRQ stack */ ; 其实thread_info结构的第一个成员就是一个指向task_struct结构的指针,所以要用current_thread_info()-task表示task_struct的地址,但是整个过程对用户是完全透明的,我们还是可以用current表示当前进程。,www.embedu.org,15,5.3 Linux进程的创建,在Linux中,通过调用fork系统调用来创建一个新的进程。新创建的子进程同样也能执行fork,所以,有可能形成一颗完整的进程树。注意,每个进程只有一个父进程,但可以有0个、1个、2个或多个子进程。下图描述了Linux进程层次结构。其中Pa和
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号