1、嵌入式Linux操作系统,胡琛,主要内容,任务调度,存储管理中断系统驱动多线程程序设计,Linux历史,Linux操作系统是UNIX操作系统的克隆系统。它诞生于1991年10月5日(这是第一次正式宣布)。现在它已经成为世界上最常用的UNIX操作系统之一,用户数量仍在快速增长。Linux操作系统的诞生、发展和壮大始终依赖于以下五大支柱:UNIX操作系统、MINIX操作系统、GNU项目、POSIX标准和互联网。进程状态、运行状态:运行状态使用中央处理器;可运行状态:进程已被分配给除了中央处理器之外的其他资源。等待状态:事件或资源正在等待的状态。处于可中断等待状态的进程可以通过信号从等待状态中释放出
2、来。处于不间断等待状态的进程通常直接或间接地等待硬件条件,这些条件只能以特定的方式释放。暂停状态:进程需要接受某种特殊处理并暂时停止运行的状态。例如,正在调试的进程处于这种状态。死状态:进程的运行已经结束,但是它所占用的资源还没有被释放。优先级策略,系统中所有进程的优先级介于0和max _ prio-1之间,该值越低,优先级越高;实时进程的优先级范围为0,最大值为PRIO-1,从创建开始就已经确定,不会改变;非实时进程的优先级介于max _ rt _ prio和max _ prio之间,优先级分为静态和动态两个方面。静态优先级是在进程生成时确定的:static_prio=MAX_RT_PRIO
3、尼斯20动态优先级在运行时随进程状态而动态变化:调度策略,对于具有相同优先级的实时进程有两种调度策略:SCHED_RR:时间片轮换;在运行指定的时间片后,SCHED_FIFO:将被抢占并重新调度。每个可以运行的实时进程根据其在调度队列中的固定顺序运行非实时进程。基于时间片的轮换,根据每个进程的情况进行优化,使进程调度公平有效,不损失响应时间。如果(有一个服务请求用于中断的后半部分)调用do_bottom_half来运行中断处理的后半部分。如果(当前进程是具有时间片旋转的实时进程)根据当前进程的状态执行相应的处理。而(遍历整个可运行队列)如果(当前位置的进程可以被调度)调用优度来计算当前位置的进
4、程的权重。如果(返回的重量大于先前保存的最大重量),则保存该重量和过程。使用切换到宏在当前进程和所选进程之间切换上下文。进程调度的定时,添加新进程,进程状态转换,系统调用执行,返回用户模式,中断处理,返回用户模式,当前进程的时间片用完,Linux内存管理,虚拟内存管理(略)内存分配策略,伙伴系统算法state分配器,伙伴系统,每个空间根据2U的块大小。如果应用程序空间的大小满足2U-1 s=2U,则整个块将被分配以通过尽可能连续地划分大内存块来获得小内存块。当一个内存块被分割时,每个部分都成为另一方的伙伴,即Linux中的伙伴系统,并且所有的页面都被分割成10组不同大小的页面块。每个组中的块大
5、小分别为1、2、4、8和512页,10个自由区结构由一个自由区结构管理,形成一个自由区数组。如果所请求的页面数量不是2的幂,则根据略大于该数量的2的幂在页面块组中查找空闲页面块,如果在相应的页面块链表中没有空闲页面块,则在较大的页面块链表中查找它。当释放页面时,伙伴系统将该页面插入到相应的页面链表中,并检查新插入的页面是否可以与原始页面块组合形成更大的页面块。如果两个块具有相同的大小,并且这两个块的物理地址是连续的,那么它们将被合并成一个新的页面块,并且被添加到相应的页面块链表中,并且这个过程将被重复,直到它不能被合并为止。Slab,如果每次都以页帧为单位从伙伴系统中分配和释放内存块,这不仅会
6、导致很多问题。平板分配器使用预先分配的内存区域作为缓冲区。当需要分配对象时,它直接从缓冲区返回。在释放对象时,Slab分配器只将对象返回到缓冲区,以便下次分配,这样可以避免频繁调用伙伴系统的应用程序和释放操作,从而加快对象的应用程序和释放时间。Linux中的BLASK分配器,BLASK对象的三层基本结构缓存,以及确定中断来源的Linux中断处理流程;保存场景,并在中断发生前保存堆栈中所有寄存器的内容;do_ IRQ()函数根据中断号执行中断处理;irq_exit()函数执行软中断。,Linux的基本数据结构(中断描述符),结构irqdesc无符号int nomask : 1;/* IRQ不屏蔽
7、IRQ */无符号整数使能: 1;/*当前启用了IRQ */无符号整数触发器: 1;/*发生了IRQ */无符号整数探测: 1;/*用于探针的IRQ */无符号int probe _ ok : 1;/* IRQ可用于探测*/无符号整数有效: 1;/* IRQ可声明*/无符号整数没有自动启用: 1;/*不要自动启用IRQ */无符号整数未使用:25;无效(*mask_ack)(无符号整数IRQ);/*屏蔽并确认IRQ*/无效(*屏蔽)(无符号整数IRQ);/*屏蔽IRQ*/无效(*取消屏蔽)(无符号整数IRQ);/*取消屏蔽IRQ */结构中断请求操作*操作;/* IRQ锁定检测*/;结构irq
8、desc irq _ descNR _ IRQS/中断描述符表,中断处理相应结构,结构IRQ操作void(*处理程序)(int,void *,结构pt _ regs *);无符号长标志;无符号长掩码;常量字符*名称;void * dev _ id结构irqaction *下一步;do_IRQ,as link void do _ IRQ(int IRQ,struct pt _ regs * regs)结构IRQ desc * desc;结构irqaction *操作;int cpu如果(irq=NR_IRQS)变为坏_ IRQ。desc=伊斯兰共和国_ desc伊斯兰共和国;自旋锁(,do_IR
9、Q),动作=desc-动作;如果(动作)int状态=0;/遍历所有的中断相应块,并执行相应程序做状态|=操作标志;动作处理程序(irq,action-dev_id,regs);action=action-next;同时(动作);/软中断!如果(软IRQ _挂起(中央处理器)做_软IRQ();返回;坏_ IRQ : IRQ _ err _ count=1;printk(KERN_ERR IRQ:杂散中断%dn,IRQ);返回;驱动程序申请中断,int request_irq(无符号int irq,void(*处理程序)(int,void *,struct pt_regs *),无符号长irq_f
10、lags,const char * devname,void * dev _ id);irq:要申请的中断号;handler:中断处理函数指针;irq _ flags:中断管理掩码;devname:设备名称;dev_id:设备相关的私用存储区,用于标示自身,申请中断的实现,int request_irq(无符号int irq,void(*处理程序)(int,void *,struct pt_regs *),无符号长irq_flags,const char * devname,void *dev_id)无符号长retval结构irqaction *操作;操作=(结构IRQ操作*)kmalloc(
11、大小为(结构IRQ操作),GFP _ KERNEL如果(!动作(返回-ENOME;动作处理程序=处理程序;操作标志=irq _ flags动作掩码=0;action-name=dev name;动作-下一个=空;action-dev _ id=dev _ id;retval=setup_arm_irq(irq,动作);if (retval) kfree(动作);返回retval,释放中断无空隙_irq(无符号整数irq,void *dev_id) irq:中断号dev_id:中断处理程序标示,释放中断的实现,无空隙_irq(无符号整数irq,void *dev_id)结构irqaction *
12、无符号长标志;if (irq=NR_IRQS |!irq_descirq.valid) /错误处理返回;自旋_锁定_irqsave(,中断处理程序,无效处理程序(int irq,void *dev_id,struct pt _ regs * regs);irq:中断号dev_id:驱动程序标示regs:上下文寄存器现场,软中断、小任务(小任务(和下半部分,为什么要引入软中断(延迟任务)?在上述硬件中断的处理过程中,需要关闭中断;如果中断处理程序的处理过于复杂,则导致不能及时响应中断;将比较简单的任务放到硬件中断处理过程,把复杂的操作放到软中断操作过程,提高内核的响应中断速度。软中断可以被硬件中
13、断所打断2007年。软中断、小任务(小任务(和下半部分,软中断,小任务,下半部分,软中断,系统中固定有4种软中断软中断存放在一个softirq_vec数组中,数据类型为softirq_action。softirq_action包含了软中断函数指针和相关数据结构。调用软中断时,通过调用softirq_pending()判断是否有软中断,如果有软中断,执行do _ softirq();判断时序包括:do_IRQ()完成中断处理程序smp_apic_timer_interrupt完成本地时钟中断。当一个特定的ksoftirqd内核线程唤醒时,基于HI_SOFTIRQ和TASKLET_SOFIRQ的软中断的tasklet、Tasklet被存储在tasklet_vec和tasklet_hi_vec数组中。每个小任务的数据结构包括:下一个:小任务的链表指针;状态:状态;函数指针数据:无符号函数,作为小任务的函数输入,如何使用小任务,分配小任务结构数据结构,通过小任务初始化()初始化,通过小任务调度()调度,通过小任务禁用()禁用小任务。示例:/tasklet初始化void short _ do _ tasklet(无符号长整型);DECLARE_TASKLET(short_tasklet,short_do_tasklet,0