ImageVerifierCode 换一换
格式:DOCX , 页数:24 ,大小:55.52KB ,
资源ID:26783248      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/26783248.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(linux嵌入式课程设计源代码分析.docx)为本站会员(b****3)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

linux嵌入式课程设计源代码分析.docx

1、linux嵌入式课程设计源代码分析1.进程的概念 12.进程切换的三个层次 13.Linux 中进程的特点 14.task struct 25.进程之间的状态转换的系统调用 56.进程的创建: TASK_RUNNING 57.进程的调度 ( schedule() ) 88.进程转换 99.Semaphores (信号灯) 1310.锁 机制 1811.管道(流) 2112.进程的终止 2313总结 2614 参考文献 261.进程的概念进程执行操作系统的任务。程序是存放在磁盘上的包括一系列机器代 码指令和数据的可执行的映像,因此是一个被动的实体。进程可以看作是 一个执行中的计算机程序。它是动态

2、的实体,在处理机执行机器代码时不 断改变。进程包括处理程序的指令和数据,以及程序计数器、其他 CPU的寄存器和包括临时数据(例如:例程参数、返回地址和保存的变量)的堆 栈。当前执行的程序,或者说进程,包括微处理器中所有的当前活动。进 程是操作系统的最小调度单位。2.进程切换的三个层次(1) 用户数据的保存 : 包括正文段 (TEXT), 数据段 (DATA,BSS), 栈段 (STACK),共享内存段(SHARED MEMORY保存。(2) 寄存器数据的保存:包括PC(program counter,指向下一条要执行的指令的地址 ),PSW(processor status word, 处理机

3、状态字 ), SP(stackpointer, 栈指针), PCBP(pointer ofprocess control block, 进程控制块指 针), FP(frame pointer, 指向栈中一个函数的 local 变量的首地址 ), AP(augument pointer, 指向栈中函数调用的实参位置 ), ISP(interrupt stack pointer, 中断栈指针 ), 以及其他的通用寄存器等。(3) 系统层次的保存 : 包括 proc,u, 虚拟存储空间管理表格 , 中断处理 栈。以便于该进程再一次得到 CPU时间片时能正常运行下去。3.linux 中进程的特点Lin

4、ux 是一个多进程的操作系统,进程是分离的任务,拥有各自的权利 和责任。如果一个进程崩溃,它不应该让系统的另一个进程崩溃。每一个独 立的进程运行在自己的虚拟地址空间,除了通过安全的核心管理的机制之外 无法影响其他的进程。在一个进程的生命周期中,进程会使用许多系统资源。比如利用系统的CPU执行它的指令,用系统的物理内存来存储它和它的数据。 它会打开和使用文件系统中的文件,会直接或者间接使用系统的物理设备。如果一个进程独占了系统的大部分物理内存和 CPU对于其他进程就是不公平的。所以 Linux必须跟踪进程本身和它使用的系统资源以便公平地管理系统中的进程4.taskstructLinux 中,每个

5、进程用一个 task_struct 的数据结构来表示, 用来管统中 的进程。task_struct 结构中有关于进程调度的两个重要的数据项: structtask_struct volatile long state;*/unsigned long flags;/* -1 unrunnable , 0 runnable , 0 stopped/* per process flags, defined below */ ;每个在 Task 向量表中登记的进程都有相应的进程状态和进程标志, 是进行进程调度的重要依据。进程在执行了相应的进程调度操作后,会由于 某些原因改变自身的状态和标志, 也就是改

6、变 state 和 flags 这两个数据项 进程的状态不同、标志位不同对应了进程可以执行不同操作。/ 进程状态#define TASK_RUNNING 0#define TASK_INTERRUPTIBLE 1#define TASK_UNINTERRUPTIBLE 2#define TASK_ZOMBIE 4#define TASK_STOPPED 8#define TASK_SWAPPING 16它们的含义分别是:TASK_RUNNINGE在运行的进程(是系统的当前进程)或准备运行的 进程(在Running队列中,等待被安排到系统的CPU。处于该状态的进程实际 参与了进程调度。TASK_

7、INTERRUPTIBL处于等待队列中的进程,待资源有效时唤醒, 也可由其它进程被信号中断、唤醒后进入就绪状态。TASK_UNINTERRUPTIB处于等待队列中的进程,直接等待硬件条件, 待资源有效时唤醒,不可由其它进程通过信号中断、唤醒。TASK_ZOMBIE终止的进程,是进程结束运行前的一个过度状态(僵死 状态)。虽然此时已经释放了内存、文件等资源,但是在 Task向量表中仍有一个task_struct数据结构项。它不进行任何调度或状态转换,等待父进程将它 彻底释放。TASK_STOPPEDft程被暂停,通过其它进程的信号才能唤醒。正在调 试的进程可以在该停止状态。TASK_SWAPPI

8、N进程页面被兑换出内存的进程。 这个状态基本上没有 用到,只有在sched.c的count_active_tasks ()函数中判断处于该种状态的 进程也属于 active 的进程,但没有对该状态的赋值。/ 进程标志位:#define PF_ALIGNWARN0x00000001#define PF_STARTING 0x00000002#define PF_EXITING 0x00000004#define PF_PTRACED 0x00000010#define PF_TRACESYS 0x00000020 #define PF_FORKNOEXEC 0x00000040#define P

9、F_SUPERPRIV0x00000100#define PF_DUMPCORE0x00000200#define PF_SIGNALED 0x00000400#define PF_MEMALLOC0x00000800#define PF_VFORK 0x00001000#define PF_USEDFPU 0x00100000#define PF_DTRACE 0x00200000各个标志位的代表着不同含义,对应着不同调用:1、PF_STARTING进程正被创建2、PF_EXITING标志进程开始关闭。3、PF_PTRACED进程被跟踪标志,4、PF_TRACESYS正在跟踪系统调用。5、P

10、F_FORKNOEXEC 进程刚创建,但还没执行p-flags &= PF_FORKNOEXEC6、PF_SUPERPRIV超级用户特权标志。如果是超级用户进程则置位, 用户特权设为超级用户, 如是超级用户, 在统计时置统计标志 (accounting flag) 为 ASU。7、 PF_DUMPCORE 标志进程是否清空 core 文件。10、 PF_DTRACE 进程延期跟踪标志,只在 m68k下使用。11、 PF_ONSIGSTK 标志进程是否工作在信号栈,只在 m68k方式下使用。5.进程之间的状态转换的系统调用我将参与Linux的各进程之间的状态转换的系统调用总结成一张流程图:sys

11、call_trace do_sig nal()i i i : ,I 1 TASK INTERRUPTIBAITING STATUSTASK uninterruptible6.进程的创建:TASK_RUNNING第一个进程在系统启动时创建,当系统启动的时候它运行在核心态,这时, 只有一个进程:初始化进程。象所有其他进程一样,初始进程有一组用堆栈、寄 存器等等表示的机器状态。当系统中的其他进程创建和运行的时候这些信息存在 初始进程的task_struct 数据结构中。在系统初始化结束的时候,初始进程启动 一个核心进程(叫做init )然后执行空闲循环,什么也不做。当没有什么可以做 的时候,调度程序

12、会运行这个空闲的进程。这个空闲进程的 task_struct 是唯 一个不是动态分配而是在核心连接的时候静态定义的,为了不至于混淆,叫做 init_task 。进程由 do_fork() 函数创建,先申请空间,申请核心堆栈;然后在 Task 向 量表中找到空闲位置;在进行正式初始化以前,将新创建的进程的状态都置为 TASK_UNINTERRUPTIBL以免初始化过程被打断;开始初始化工作,如初始化进 程时钟、信号、时间等数据;继承父进程的资源,如文件、信号量、内存等;完 成进程初始化后 , 由父进程调用 wake_up_process() 函数将其唤醒,状态变为 TASK_RUNNINGt到就

13、绪队列run queue,返回子进程的pid。/ C:SRCLNXKERNELFORK.Cintdo_fork(unsigned long clone_flags, unsigned long usp, structpt_regs *regs)为新进程申请PCB空间;if ( 申请不到)返回错误 , 退出;为新进程申请核心堆栈 ;if ( 核心堆栈申请不到 )返回错误 , 退出;为新进程在 Task 向量表中找到空闲位置 ;/* 复制父进程 current PCB 中的信息,继承 current 的资源*/ ;p = current;在进 行正式初 始 化以 前, 将 新创建的 进程的 状态都

14、置为TASK_UNINTERRUPTIBL以免初始化过程被打断,并置一些标志位./* 为 防 止 信 号 、 定 时 中 断 误 唤 醒 未 创 建 完 毕 的 进 程,将子进程的状态设成不可中断的 */p-state = TASK_UNINTERRUPTIBLE;/* 跟踪状态和超级用户特权是没有继承性的,因为在 root 用户为普通用户创 建进程时,出于安全考虑这个普通用户的进程不允许拥有超级用户特权。 */p-flags &= (PF_PTRACED|PF_TRACESYS|PF_SUPERPRIV);/*将进程标志设成初建,在进程第一次获得 CPU时,内核将根据此标志进行一 定操作*/

15、p-flags |= PF_FORKNOEXEC;开始 Task_struct 的初始化工作, 如初始化进程时钟、 信号、时间等数据 ;继承父进程所有资源 :拷贝父进程当前打开的文件 ;拷贝父进程在VFS的位置;拷贝父进程的信号量 ;拷贝父进程运行的内存 ;拷贝父进程的线程 ;初始化工作结束,父进程将其将其唤醒 , 挂入 running 队列中,返回子进 程的 pid;7.进程的调度( schedule() )处于TASK_RUNNIN状态的进程移到run queue,会由schedule。按CPU 调度算法在合适的时候选中,分配给 CPU。新创建的进程都是处于TASK_RUNNING态,而且

16、被挂到run queue的队 首。进程调度采用变形的轮转法(round robin )。当时间片到时(10ms的整数倍), 由时钟中断引起新一轮调度,把当前进程挂到 run queue 队尾调度程序 schedule() 从核心的多个地方运行。它可以在把当前进程放到等 待队列之后运行,也可以在系统调用之后进程从系统态返回进程态之前运行。需 要运行调度程序的另一个原因是系统时钟刚好把当前进程的计数器 (counter) 置 成了 0。每一次调度程序运行它做以下工作:( 1) kernel work 调度程序运行 bottom half handler 并处理系统的调度任 务队列。( 2) Cur

17、rent pocess 在选择另一个进程之前必须处理当前进程。( 3)如果当前进程的调度策略是环则它放到运行队列的最后。(4)如果任务状态是 TASK_INTERRUPTIBL的而且它上次调度的时候收到过 一个信号,它的状态变为 TASK_RUNNING;如果当前进程超时,它的状态成为 RUNNING;如果当前进程的状态为 RUNNIN则保持此状态;不是RUNNING或者 INTERRUPTIBL的进程被从运行队列中删除。这意味着当 调度程序查找最值得运行的进程时不会考虑这样的进程。(5)Process Selection 调度程序查看运行队列中的进程,查找最值得运行的 进程。如果有实时的进程

18、(具有实时调度策略) ,就会比普通进程更重一些。 (6)Swap Processes 如果最值得运行的进程不是当前进程,当前进程必须被挂起,运行新 的进程。(7)交换出去进程的上下文发生在调度的最后。前一个进程存储的上下文,就 是当这个进程在调度结束的时候系统的硬件上下文的快照。相同的,当加载新的 进程的上下文时,仍旧是调度结束时的快照,包括进程的程序计数器和寄存器的 内容。(8)如果前一个进程或者新的当前进程使用虚拟内存,则系统的页表需要更新。 同样,这个动作适合体系结构相关。 Alpha AXP 处理器,使用 TLT( TranslationLook-aside Table )或者缓存的页

19、表条目,必须清除属于前一个进程的缓存的页 表条目。8.进程转换在 TASK_RUNNING及 TASK_UNINTERRUPTIBLEASK_INTERRUPTIB之间进程创建以后到被杀死的整个进程生命周期中,状态可能在 TASK_RUNNINGTASK_INTERRUPTIBLErASK_UNINTERRUPTIBLErASK_STOPPED及 TASK_ZOMBLE 之间转换的。1. 通 过 sleep_on() 、 interruptible_sleep_on() 、 sleep_on_timeout() 、 interruptible_sleep_on_timeout ()以及 wak

20、e_up() 、 wake_up_process() 、 wake_up_interruptible() 函数对进行的转换:sleep_o n():TASK_RUNNING-TASK_UNINTERRUPTIBLE一般来说引起状态变成 TASK_UNINTERRUPTIB的资源申请都是对一些硬件资源的申请,如果得不到这些资源,进程将不能执行下去,不能由 signal 信号或时 钟中断唤醒,而回到TASK_RUNNIN状态。这种类型的转换原因有:( 1)对某些资源的操作只能由一个进程进行,所以系统对该项资源采用上锁 机制。在申请该项资源时,必须先申请资源的锁,如果已经被别的进程占用,则 必须睡眠

21、在对该锁的等待队列上。而且这种睡眠不能被中断,必须等到得到了资 源才能继续进行下去。(2)某些进程在大部分时间处于睡眠状态,仅在需要时被唤醒去执行相应的 操作,当执行完后,该进程又强制去睡眠。wake_up():TASK_UNINTERRUPTIBLE- TASK_RUNNING;TASK_INTERRUPTIBLE- TASK_RUNNING处于TASK_UNINTERRUPTIB状态的进程不能由signal信号或时钟中断唤醒, 只 能 由 wake_up() 或 wake_up_process() 唤 醒 。 wake_up() 函 数 的 作 用 是 将 wait_queue 中的所有状

22、态为 TASK_INTERRUPTIBLE TASK_UNINTERRUPTIB的进 程状态都置为TASK_RUNNIN并将它们都放到running队列中去,即唤醒了所有等 待在该队列上的进程。voidwake_up(structwait_queue *q)structwait_queue *next;structwait_queue *head;if (!q | !(next = *q)return;head = WAIT_QUEUE_HEAD(q);while (next != head) structtask_struct *p = next-task;next = next-next;

23、if (p != NULL) if (p-state = TASK_UNINTERRUPTIBLE) |(p-state = TASK_INTERRUPTIBLE)wake_up_process(p);if (!next)goto bad;return;bad:printk(wait_queue is bad (eip = %p)n, _builtin_return_address(0);printk( q = %pn,q);printk( *q = %pn,*q);voidwake_up_process(structtask_struct * p) unsigned long flags;/

24、* We want the common case fall through straight, thus the goto. */spin_lock_irqsave(&runqueue_lock, flags); p-state = TASK_RUNNING;if (p-next_run)goto out;add_to_runqueue(p);spin_unlock_irqrestore(&runqueue_lock, flags);reschedule_idle(p);return;out:spin_unlock_irqrestore(&runqueue_lock, flags);这个函数

25、的实现机制与 wake_up() 的不同在于,它只能唤醒某一个特定 的睡眠进程,而 wake_up() 是唤醒整个等待队列的睡眠进程。所以,它的唤醒的 原因与 wake_up() 也有一定的区别,除了由于 wake_up() 对它的调用之外,它唤 醒进程并不是由于资源有效造成的,唤醒的进程也不是因等待资源有效而睡眠 的进程。有以下几种情况:( 1) 父进程对子进程的唤醒:如:在sys_ptrace()中当收到的跟踪请求为:PTRACE_CON在处理完信 号后继续);PTRACE_KILL将子进程杀出);PTRACE_SINGLESTE对子进程进 行单步跟踪);PTRACE_DETACH寸候,都

26、会在处理结束时,唤醒子进程,给 子进程一个运行的机会。在 do_fork() 中,新建进程初始化完毕,会由父进程唤醒它,将该进程移到run queue中,置状态为 TASK_RUNNING(2) 当需要的时候唤醒某个睡眠的系统调用,进行处理:3) 收到信号所进行的相应处理:(4) 资源有效时, wake_up() 对整个等待队列的唤醒是通过对每个等待 队列上的进程调用 wake_up_process() 实现的。9.Semaphores (信号灯)信号量用于生成锁机制 , 避免发生数据不一致。信号量最简单的形式就是内存中一个位置,它的取值可以由多个进程检验和 设置。检验和设置的操作,至少对于关

27、联的每一个进程来讲,是不可中断或者说 有原子性:只要启动就不能中止。检验和设置操作的结果是信号灯当前值和设置 值的和,可以是正或者负。根据测试和设置操作的结果,一个进程可能必须睡眠 直到信号灯的值被另一个进程改变。信号灯可以用于实现临界区域( critical regions ),就是重要的代码区,同一时刻只能有一个进程运行。对信号灯的操作是通过以下两组基本函数实现的:1 void _up(struct semaphore *sem) : TASK_UNINTERRUPTIBLE- TASK_RUNNING;TASK_INTERRUPTIBLE- TASK_RUNNINGint _do_dow

28、n(struct semaphore * sem, inttask_state) 由以下两个函数调用,分别转换到不同的等待状态:(1)int_down_interruptible (struct semaphore * sem) :TASK_RUNNING -TASK_INTERRUPTIBLE;(2)void _down(struct semaphore * sem):TASK_RUNNING -TASK_UNINTERRUPT;IBLE2. extern inline void up(struct semaphore * sem)extern inline void down(struct

29、 semaphore * sem) ;extern inline intdown_interruptible(struct semaphore * sem)Linux 信号量是通过两路 counter 变量实现的:当进程由于申请不到临界区资 源而睡眠时,会将semaphore结构中的”ount ”变量值原子地递减1,进程睡眠等待 临界区资源的释放;而当up()函数唤醒睡眠等待进程时,如果”count ”变量值小于 0,会将semaphore结构中的”waking ”变量值原子地递增1,唤醒睡眠进程。虽然 所有等待进程都被唤醒。但只有首先得到 ”waking ”的进程才能得到信号量,继续 运行下

30、去,其他进程仍然回到最初的等待状态。Linux 定义信号灯结构是:struct semaphore atomic_t count;int waking;structwait_queue * wait;信号灯的值初始化为一个宏定义的结构 MUTEXS值count=1,waking=0,wait=NULL。void _up(struct semaphore *sem)占有临界区资源的进程,调用 _up() 释放资源。在 _up() 函数中,调用wake_one_more () 函 数 , 原 子 地 读 sem-count, 如 果 sem-count waking +, 并唤醒所有等待在该 se

31、m-wait 上的进程。void _up(struct semaphore *sem) wake_one_more(sem);wake_up(&sem-wait);int _do_down(struct semaphore * sem, inttask_state):申请临界区资源的进程会通过调用 _do_down() 来竞争资源。在 _do_down() 函 数 中 , 调 用 waking_non_zero(struct semaphore *sem) 或 waking_non_zero_interruptible(struct semaphore *sem) 抢占临界区资源,如 果抢占到,则将当前进程置为TASK_RUNNIN否则将当前进程的状态置为 task_state ,并处于循环等待状态。进 程 通 过 waking_non_zero ( ) 来 竞 争 临 界 区 资

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1