皮皮网

【pdfbox源码解析】【学校网站 discuz源码】【dsa加密 c源码】tcb源码大全

时间:2024-11-29 09:49:54 来源:金色黑马指标源码 作者:拐点源码公式

1.C++后端开发——POSIX网络API解析
2.什么是PSOS
3.如何保证 Java 应用安全?标准答案来了
4.如何学习 nucleus os

tcb源码大全

C++后端开发——POSIX网络API解析

       网络中进程之间如何通信?网络中进程通信的唯一标识是三元组(ip地址,协议,端口),利用此标识,网络进程可以进行交互。实现网络通信的pdfbox源码解析常用API是UNIX BSD的套接字(socket)和UNIX System V的TLI,而现代应用几乎都采用socket。

       POSIX标准定义了操作系统为应用程序提供的接口标准,实现源代码级别的软件可移植性。不同内核提供的系统调用不同,POSIX标准通过统一接口解决了源代码移植问题。如创建进程的函数,Linux下是fork,Windows下是createprocess。编写程序时只需包含unistd.h,调用统一接口函数,实现源代码级别移植。

       POSIX网络API是网络编程常用的接口,包括socket、bind、listen、connect、accept、send、recv等。socket函数用于创建句柄和TCB控制块,建立文件描述符与内部控制块的对应关系。bind函数将特定地址赋给socket,listen函数开始监听网络上的连接请求,connect函数向服务端发起连接请求,accept函数接收连接请求并分配新描述符,学校网站 discuz源码send和recv函数用于数据收发。

       注意点包括:主机字节序与网络字节序的转换,listen、connect、accept三个函数与三次握手过程,send和recv数据收发策略,以及close关闭socket的四次挥手过程。实现网络中进程通信的关键在于正确使用这些API,并注意细节。

什么是PSOS

       pSOS系统结构

       pSOS是一个由标准软组件组成的,可剪裁的实时操作系统。其系统结构如图2.1所示

       ,它分为内核层、系统服务层、用户层。

       1. 内核层

       pSOS内核负责任务的管理与调度、任务间通信、内存管理、实时时钟管理、中断服

       务;可以动态生成或删除任务、内存区、消息队列、信号灯等系统对象;实现了基于优

       先级的、选择可抢占的任务调度算法,并提供了可选的时间片轮转调度。pSOS Kernel还

       提供了任务建间通信机制及同步、互斥手段,如消息、信号灯、事件、异步信号等。

       pSOS操作系统在Kernel层中将与具体硬件有关的dsa加密 c源码操作放在一个模块中,对系统服务层

       以上屏蔽了具体的硬件特性,从而使得pSOS很方便地从支持Intel x系列转到支持MC

       XXX系列,并且在系统服务层上对不同应用系统不同用户提供标准的软组件如PNA+、

       PHILE+等。

       2. 系统服务层

       pSOS系统服务层包括PNA+、PRPC+、PHILE+等组件。PNA+实现了完整的基于流的TCP

       /IP协议集,并具有良好的实时性能,网络组件内中断屏蔽时间不大于内核模块中断屏蔽时

       间。PRPC+提供了远程调用库,支持用户建立一个分布式应用系统。PHILE+提供了文件系

       统管理和对块存储设备的管理。PREPC+提供了标准的C、C++库,支持用户使用C、C++语言

       编写应用程序。

       由于pSOS内核屏蔽了具体的硬件特性,因此,pSOS系统服务层的软组件是标准的、与

       硬件无关的。这意味着pSOS各种版本,无论是对X系列还是MCXXX系列,其系统服务

       层各组件是标准的、同一的,这减少了软件维护工作,增强了软件可移植性。

       每个软组件都包含一系列的系统调用。对用户而言,这些系统调用就象一个个可重入

       的C函数,然而它们却是用户进入pSOS内核的唯一手段。

       3. 用户层

       用户指的是用户编写的应用程序,它们是以任务的形式出现的。任务通过发系统调

       用而进入pSOS内核,并为pSOS内核所管理和调度。

       pSOS为用户还提供了一个集成式的开发环境(IDE)。pSOS_IDE可驻留于UNIX或DOS

       环境下,它包括C和C++优化编译器、CPU和pSOS模拟仿真和DEBUG功能。

       pSOS内核机制

       §3.1 几个基本概念

       3.1.1 任务

       在实时操作系统中,任务是参与资源竞争(如CPU、Memory、I/O devices等)

       的基本单位。pSOS为每个任务构造了一个虚拟的、隔离的环境,从而在概念上,一个任务

       与另一个任务之间可以相互并行、独立地执行。人脸识别源码app任务与任务之间的切换、任务之间的通

       信都是通过发系统调用(在有些情况下是通过ISR)进入pSOS Kernel,由pSOS Kernel完

       成的。

       pSOS系统中任务包括系统任务和用户任务两类。关于用户任务的划分并没有一个固

       定的法则,但很明显,划分太多将导致任务间的切换过于频繁,系统开销太大,划分太少又

       会导致实时性和并行性下降,从而影响系统的效率。一般说来,功能模块A与功能模块B是

       分开为两个任务还是合为一个任务可以从是否具有时间相关性、优先性、逻辑特性和功

       能耦合等几个方面考虑。

       3.1.2 优先级

       每个任务都有一个优先级。pSOS系统支持0~级优先级,0级最低,级最高。0级

       专为IDLE任务所有,~级为系统所用。在运行时,任务(包括系统任务)的优先级

       可以通过t_setpri系统调用改变。

       3.1.3 任务状态

       pSOS下任务具有三种可能状态并处于这三个状态之一。只有通过任务本身或其他任

       务、ISR对pSOS内核所作的系统调用才能改变任务状态。从宏观角度看,一个多任务应用

       通过一系列到pSOS的系统调用迫使pSOS内核改变受影响任务而从运行一个任务到运行另

       一任务向前发展的。

       对于pSOS kernel,任务在创建前或被删除后是不存在的。被创建的任务在能够运行

       前必须被启动。一旦启动后,一个任务通常处于下面三个状态之一:

       ①Executing (Ready)就绪

       ②Running运行

       ③Blocked阻塞

       就绪任务是未被阻塞可运行的,只等待高优先级任务释放CPU的任务。由于一个任务

       只能由正运行的任务通过调用来被启动,而且任何时刻只能有一个正在运行的任务,所

       以新任务总是从就绪态开始。

       运行态任务是正在使用CPU的就绪任务, 系统只能有一个running任务。一般runni

       ng任务是所有就绪任务中优先级最高的,但也有例外。

       任务是iapp源码制作教程由自身特定活动而变为阻塞的,通常是系统调用引起调用任务进入等待状态

       的。所以任务不可能从ready态到blocked态,因为只有运行任务才能执行系统调用。

       3.1.4 任务控制块

       任务控制块TCB是pSOS内核建立并维护的一个系统数据结构,它包含了pSOS Kernel调

       度与管理任务所需的一切信息,如任务名、优先级、剩余时间片数、当前寄存器状态等。

       在有的RTOS中,任务的状态与任务TCB所处的队列是等同的。pSOS操作系统将二者分

       为两个概念,例如任务处于阻塞状态,但它的TCB却处于消息等待队列、信号灯等待队列、

       内存等待队列、超时队列之一。

       pSOS启动时,将根据Configuration Table中的参数kc_ntask建立一个包含kc_ntask

       个TCB块的TCB池,它表示最大并行任务数。在创建一个任务时,分配一个TCB给该任务,在

       撤销一个任务时,该TCB将被收回。

       3.1.5 对象、对象名及ID号

       pSOS Kernel是一个面向对象的操作系统内核,pSOS系统中对象包括任务、memory

       regions、memory partitions、消息队列和信号灯。

       对象名由用户定义(4位ASCII字符),并且在该对象创建时作为系统调用obj_CREAT

       E

       的一个人口参数传给pSOS Kernel。pSOS Kernel反过来赋予该对象一个唯一的位ID号

       。除obj_CREATE和obj_IDENT外,所有涉及对象的系统调用都要用到对象ID号。

       创建对象的任务通过obj_CREATE就已经知道了该对象的ID号,其余任务可通过obj_

       IDENT或通过全局变量(如果已经为该任务的ID号建立了一个全局变量的话)获取该对象

       的ID号。对象ID号隐含了该对象控制块(如TCB、QCB)的位置信息,这一位置信息被pSO

       S

       Kernel用于对该对象的管理和操作,如挂起/解挂一个任务、删除一个消息队列等。

       3.1.6 任务模式字Mode word.

       每个任务带有一个mode word,用来改变调度决策或执行环境。主要有以下四个参

       数

       Preemption Enabled/Disabled.

       Roundrobin Enabled/Disabled

       Interupts Enabled/Disabled.

       ASR Enabled/Disabled: 每个任务有一个通过as-catoh建立起来的异步信号服务例

       程ASR。异步信号类似于软件中断。当ASR位为1时as-catch所指向的任务将会被改变执行

       路径,先执行ASR,再返回原执行点。

       §3.2 任务调度

       3.2.1 影响动态调度效果的两个因素

       pSOS采用优先级+时间片的调度方式。有两个因素将影响动态调度的效果:一是优先

       级可变(通过t_setpri系统调用改变任务的优先级);二是任务模式字中的preemption

       bit位和roundrobin bit位。preemption bit位决定不同优先级的任务是否可抢占,并和

       roundrobin bit位一起决定任务的时间片轮转是否有效。

       3.2.2 引起任务调度的原因及结果

       pSOS系统中引起调度的原因有两条:

       1. 在轮转方式下时间片到

       2. pSOS系统调用引发任务调度。该系统调用可能是ISR发出的,也可能是某个任务发出的

       pSOS任务调度的结果有两种:

       1. 引起运行任务切换,这指的是

       2. 不引起运行任务切换,这指的是

       不论任务调度是否引发运行任务切换,都有可能引起一个或多个任务状态变迁。

       3.2.3 运行任务的切换

       一、何时切换

       下面三种情况将引发运行任务切换:

       1. 在时间片轮转方式下(此时任务模式字的roundrobin bit与preemption bit均为

       enable),运行任务Task A的时间片用完,且Ready队列中有相同优先级的其它任务,则

       Task A退出运行。

       2. 在运行任务Task A的Mode word的preemption bit位为enable的前提下,若Task A发出

       的某条相同调用引发一个优先级高于Task A的任务Task B从Block状态进入Reary状态,则

       将Task B投入运行。

       3. ISR使用I_RETURN系统调用,则ISR退出运行,pSOS Kernel选择Ready队列中优先级最高

       的任务投入运行(这一任务并不一定是被ISR打断的前运行任务)。

       二、如何切换

       上述三类运行任务的切换,其具体的pSOS Kernel运作过程并非完全一样,但彼此之间

       差别不大。为了简单起见,我们以

       为例对切换过程作一简单叙述。这一过程可细分为4个步骤:

       1. 任务A运行信息保存(_t_save proc far)

       这一过程主要完成修改系统工作标志,保存切换点地址及运行信息、任务A栈调

       整

       栈

       指针保存、栈切换、参数及返址入栈等一系列工作。

       2.任务A入就绪队列(void t_in_chain)

       这一过程将任务A的TCB块按优先级顺序插入就绪队列。

       3.选择一个高优先级任务B(void t_choice( ))

       按一定算法从就绪队列中选出最高优先级任务B的TCB块,并使运行指针指向它。

       4.将任务B投入运行(_t_run proc far)

       从系统栈切换到任务B栈,用任务B的TCB块中保存的信息恢复上次运行被打断的

       地

       ,恢

       复任务运行环境,于是任务B开始继续运行。

       图3.1反映了典型任务切换过程中CPU控制权的转移、各堆栈活动生命期、任务活动

       生命期等信息。图中

       t1,t4为切换点 t2,t3为开/关中断

       Tsch=t4-t1 // Tsch为任务切换时间

       Tforbid=t3-t2 // Tforbid为中断禁止时间

       它们是实时操作系统最重要的两个性能指标。

如何保证 Java 应用安全?标准答案来了

       如何保证 Java 应用安全?

       在 Java 程序内存中保护密码安全,可以通过引入机密计算技术来实现。龙蜥社区云原生机密计算 SIG 推出了 Java 机密计算实现技术——Teaclave Java TEE SDK。该技术具有显著优点,已经经过企业级内部场景验证并在 Apache 社区开源。它在软件工程顶级会议 ICSE 上发表的论文获得了 ACM SIGSOFT 杰出论文奖,是自 年以来,龙蜥社区云原生机密计算 SIG、上海交通大学、大连理工大学首次获此荣誉。

       保护 Java 程序内存中密码的安全,关键在于如何在运行时环境中安全使用敏感数据。密码一旦解密后,即以明文形式存在于 Java 堆上,可能导致被攻击或主动泄漏。为了解决这一问题,Teaclave Java TEE SDK 通过将密码从内存中销毁,大大减少了敏感信息暴露的时间窗口。此外,通过将密码保存为 char 数组或 byte 数组,避免了反射调用,使得销毁过程更加便利。使用 byte 数组保存密码,更是增加了信息的隐蔽性,使其难以被解读。

       然而,当前在网络上找到的解决方法,如缩短明文密码在内存中的存放时间,仅缩短了敏感信息暴露的时间窗口,并未真正保护明文密码。这些方法对密码的销毁时间判断弹性较大,开发人员未必能准确判断何时是最佳时机。更典型的案例,如著名的 log4j 漏洞问题,攻击者能够利用漏洞将恶意类文件上传至服务器,并通过 Java 动态类加载机制运行,窃取 Java 堆中的私钥,进而获得服务器与客户端之间通信内容的完全访问权限。

       为了解决 Java 程序安全性问题,机密计算技术成为了一个标准答案。它通过提供硬件级的系统隔离,保障数据安全和程序运行安全。机密计算将执行环境分为富执行环境(REE)和可信执行环境(TEE),认为 REE 和 TEE 应该相互隔离,TEE 需要通过硬件加密来保证外界无法知晓其中的内容。这一机制在 年即已提出,并在随后的 多年中得到了发展。

       其中,SGX、TrustZone 等提供了通用型机密计算的硬件基础,Intel、微软等开源的驱动和 SDK 则为通用型机密计算提供了软件基础。然而,直接在 TEE 中运行 Java 程序并不友好,因为 TEE 只能执行 native 程序。为解决这一问题,Occlum 作为介于 TEE 底层 SDK 与 JVM 之间的一层 LibOS,支持 JVM 在 TEE 中的运行。然而,Occlum 方案存在安全性和性能下降的问题,TCB(可信计算基)过大,导致安全性不佳;性能下降,TEE 硬件与 REE 相比存在性能退化。

       针对上述问题,Teaclave Java TEE SDK 提出了一种在 TEE 中仅放入可信代码的解决方案。通过将可信代码从 Java 代码直接编译为 native code 放入 TEE 运行,Teaclave Java 采用模块分隔、机密计算服务化、简洁的机密计算服务生命周期管理 API、Java 静态编译等关键技术特性,将应用代码分为 Host、Enclave 和 Common 三个模块。Host 中为普通安全非敏感程序,Enclave 中为安全敏感程序,Common 中则是两者的公共代码。通过将可信代码放入 TEE 运行,实现了 Java 应用的机密计算,降低了安全性和性能的下降问题。Teaclave Java 提供了一站式快速实现 Java 机密计算应用的开发和构建能力,简化了 Java 机密计算的开发门槛。

       在实际应用中,Teaclave Java 通过将应用的普通代码放在 REE 中执行,安全敏感的解密和私钥放在 TEE 中,实现了对敏感数据和运算过程的保护。在机密计算框架的对比中,Teaclave Java 的 TCB(可信计算基)大小仅为 Occlum 的大约 1/ 到 1/,具有更高的安全性。运行时性能方面,Teaclave Java 的 native image 会直接以 native 代码形式运行,启动速度非常快,适用于小型应用。对于长时间执行的应用,性能优势会逐渐减小。此外,Teaclave Java 的运行时内存使用量更少,为应用提供了更高效、安全的运行环境。

       综上所述,Teaclave Java TEE SDK 是解决 Java 应用安全问题的有效方案,它通过硬件宽容性、安全沙箱隔离、高效的运行时性能和简洁的开发流程,为 Java 应用提供了全面的安全保障。未来,随着 GraalVM 的 Java 静态编译技术被贡献给 OpenJDK,Teaclave Java 方案将获得 JDK 的原生支持,进一步提升其性能和易用性。同时,Teaclave Java 项目的源代码已被贡献至 Apache 社区,加入机密计算框架 Teaclave 项目,正在开源孵化中。

如何学习 nucleus os

       å†…容:

       ä¸€ã€nucleus plus特点:

           1.内核采用微内核的设计,方便移植,资料写着更reliable,但是我不这么认为,与linux相比,以ARM平台为例,NU只用到了SVC mode,内核与用户任务都运行在同一个状态下,也就是说所有的task都拥有访问任何资源的权限,这样很reliable么?

           2.real-time OS,NU是一个软实时操作系统(VxWorks是硬实时),thread control component支持多任务以及任务的抢占,对于中断的处理定义了两种服务方式,LISR和HISR,这个与linux中的上、下半部机制类似,linux中的下半部是通过软中断来实现的,NU的HISR只是作为一种优先级总是高于task的任务出现。

           3.NU是以library的方式应用的,通过写自己的app task与裁剪后的NU内核及组件链接起来,NU并没有CLI

       äºŒã€ç»„件

       1.IN component

           初始化组件由三个部分组成,硬件在reset后首先进入INT_initialize(),进行板级的相关初始化,首先设置SVC mode,关中断,然后将内核从rom中拷贝至ram中,建立bss段,依次建立sys stack, irq stack和fiq stack,最后初始化timer,建立timer HISR的栈空间,看了一下平台的代码,一个tick大概是.8ms,完成板级的初始化后就进入了INC_initialize,初始化各个组件,其中包括Application initialize,create task和HISR,最后将控制权交给schedule,主要看了一下RAM中地址空间的安排

       |timer HISR stack = |

       |FIQ stack = |

       |IRQ stack = |

       |SVC stack = |

       |.bss|

       |.data|

       |.text|

       å…¶ä¸­SVC stack的大小与中断源的个数相关,nested irq发生时,irq_context保存在SVC stack中,IRQ的stack只是做了临时栈的作用。

       2.thread control component

           TC组件是NU内核的最重要组成部分,主要涵盖了调度、中断、任务的相关操作、锁、时钟几个方面,下面分别介绍。

       è°ƒåº¦ï¼ˆschedule)

           NU中的线程类型(在同一个地址空间内)有两种,HISR和task,HISR可以理解为一种优先级较高的task,但又不是task,HISR优先级高于task的实现方式就是schdule时,先去查看当前是否有active的HISR,再去查看task。task有suspend、ready、finished和terminated四种状态,而HISR只有executing和no-active这两种状态。

           每一个task都有一个线程控制的数据结构(TCB thread control block),其中包括了task的优先级、状态、时间片、task栈、protect信息、signal操作的标志位和signal_handler等,task在创建时初始化这些信息,将task挂到一个create_list上,初始设定task为pure_suspend,如果设定auto start,调用resume_task()唤醒task,这里有个细节,如果在application initialize中create_task(),则task不会自动运行,因为初始化还未完成,控制权还没有交给schedule,无法调度task。task被唤醒后状态改变为ready,并挂在一个TCD_Priority_List[]上,数组的每个元素是一个指向TCB环形双向链表的指针,根据task的tc_priority找到对应优先级的TCB head pointer。

                                  

           每一个HISR都有一个HISR控制的数据结构(HCB HISR control block),其中只有优先级,HISR栈和HISR entry信息,因此HISR是不可以suspend,同时也没有time slice以及signal的相关操作,一般情况下当发生了中断后,HISR被activate,schedule就会调度HISR运行,期间如果不发生中断,HISR的执行是不会被打断的,HISR的优先级只有0、1、2,timer的HISR优先级为2,也就是说由外部中断激活的HISR很难被抢占的,只有更高优先级的中断HISR才可以。与task不同,被激活的HISR使用head_list和tail_list将HCB挂在一个单项的链表上,因为相同优先级的HISR不会抢占对方,因此不需要双向链表,使用两个指针目的是加快HISR执行的速度。

           一个实时操作系统的核心就是对于任务的调度,NU的调度策略是time slice和round robin的算法,

       è°ƒåº¦çš„部分主要有三个函数control_to_system()用于保存上下文,建立solicited stack,关中断,关system time slice,并重置task的time slice为预设值,将sp更新为system_stack_pointer,调用schedule(),调度的过程是非常简单的查询,就是查看两个全局的变量,TCD_Execute_HISR和TCD_Execute_Task,schedule部分的关键是打开了中断,不然如果当前没有ready的task或是被激活的HISR,则shedule死循环下去,查询到下一个应该执行的线程后跳转至control_to_thread(),在这里重新开启system time slice,然后将线程的tc_stack_ptr加入到sp中,切换至线程的栈中,依次pop出来,即完成了任务调度。

           任务的切换主要是上下文的切换,也就是task栈的切换,函数的调用会保存部分regs和返回地址,这些动作都是编译器来完成的,而OS中的任务切换是运行时(runtime)的一种状态变化,因此编译器也无能为力,所以对于上下文的保存需要代码来实现。

           任务的抢占是异步的因此必须要通过中断来实现,一般每次timer的中断决定当前的task的slice time是否expired,然后设置TCT_Set_Execute_Task为相同优先级的其他task或更高优先级的task;高优先级的task抢占低优先级的task,一般是外部中断触发,在HISR中resume_task()唤醒高优先级的task,然后schedule到高优先级的task中,因为timer的HISR是在系统初始化就已经注册的,只是执行timeout和time slice超时后的操作,并没有执行resume_task的动作。

           NU中的stack有两种solicited stack和interrupt stack,solicited stack是一种minmum stack,而interrupt stack是对当前所有寄存器全部保存,TCB中的minimum stack size = 申请得到stack size - solicited stack(在arm mode下占字节,thumb mode下占字节),thumb标志用来记录上下文保存时的ARM的工作模式,c代码编译为thumb模式,这样可以减小code size,提高代码密度,assembly代码编译为arm模式提升代码的效率,NU中内核的代码不多,主要是assembly代码。stack的类型与其中PC指向的shell无关,interrupt stack保存的是task或是HISR在执行的过程中被中断时的现场,solicited stack建立的地方包括 control_to_system()、schedule_protect()和send_signals()发送给占有protect资源的task的情况,HISR_Shell()执行完后会建立solicited stack,再跳转至schedule。

       (Lower Address) Stack Top -> 1 (Interrupt stack type)

       CPSR Saved CPSR

       r0 Saved r0

       r1 Saved r1

       r2 Saved r2

       r3 Saved r3

       r4 Saved r4

       r5 Saved r5

       r6 Saved r6

       r7 Saved r7

       r8 Saved r8

       r9 Saved r9

       r Saved r

       r Saved r

       r Saved r

       sp Saved sp

       lr Saved lr

       (Higher Address) Stack Bottom-> pc Saved pc

       (Lower Address) Stack Top -> 0 (Solicited stack type)

       !!FOR THUMB ONLY!! 0/0x Saved state mask

       r4 Saved r4

       r5 Saved r5

       r6 Saved r6

       r7 Saved r7

       r8 Saved r8

       r9 Saved r9

       r Saved r

       r Saved r

       r Saved r

       (Higher Address) Stack Bottom-> pc Saved pc

       ä¸€ä¸ªç®€å•çš„例子说明stack的情况,首先是一个task在ready(executing)的状态下,而且time slice超时了,timer中断发生后,保存task上下文interrupt_contex_save(),在task的tc_stack_ptr指向的地方建立中断栈

       taskA    |interrupt stack|___tc_stack_ptr 栈顶端是pc=lr-4

       ARM对于中断的判定发生在当前指令完成execute时,同时pipeline的原因pc=pc+8,入栈时就把lr-4首先放在stack的最高端(high)。

       timer的LISR完成后激活了HISR,执行TCC_Time_slice()将当前task移到相同优先级的尾端,并且设置下一个要执行的task,HISR在栈顶端保存的是这个HISR_shell的入口地址,因为task的执行完就finished,HISR是可重入的

       HISR     |solicited stack|  æ ˆé¡¶ç«¯æ˜¯HISR_shell_entry

       ä¸­æ–­ï¼ˆinterrupt)

       å‰é¢å·²ç»æåŠäº†ä¸­æ–­çš„基本操作,这里就写一些代码路径的细节,中断的执行主要是两个部分LISR和HISR,分成两个部分的目的就是将关中断的时间最小化,并且在LISR中开中断允许中断的嵌套,以及建立中断优先级,都可以减少中断的延迟,保证OS的实时性。

       NU的中断模式是可重入的中断处理方式,也就是基于中断优先级和嵌套的模式,中断的嵌套在处理的过程中应对lr_irq_mode寄存器进行保存,因为高优先级的中断发生时会覆盖掉低优先级中断的r和spsr,因此要利用系统的栈来保存中断栈。

       NU对于中断上下文的保存具体操作如下:

       ï¼ˆ1)在中断发生后执行的入口函数INT_IRQ()中,将r0-r4保存至irq的栈中

       ï¼ˆ2)查找到对应的interrupt_shell(),clear中断源,更新全局的中断计数器,然后进行interrupt_contex_save

       ï¼ˆ3)首先利用r1,r2,r3保存irq模式下的sp,lr,spsr,这里sp是用来切换至系统栈后拷贝lr和spsr的,这里保存lr和spsr是目的是task被抢占后,当再次schedule时可以返回task之前的状态。

       ï¼ˆ4)切换至SVC模式,如果是非嵌套的中断则保存上下文至task stack中,将irq模式下的lr作为顶端PC的返回值入栈,将SVC模式下的r6-r入栈,将irq模式下的sp保存至r4中入栈,最后将保存在irq_stack中的r0-r4入栈

       ï¼ˆ5)如果是嵌套中断,中断的嵌套发生在LISR中,在执行LISR时已经切换至system stack,因此嵌套中断要将中断的上下文保存至system stack中,与task stack中interrupt stack相比只是少了栈顶用来标记嵌套的标志(1 not nested)

       ï¼ˆ6)有一个分支判断,就是如果当前线程是空,即TCD_Current_Thread == NULL,表明当前是schedule中,因为初始化线程是关中断的,这样就不为schedule线程建立栈帧,因为schedule不需要保存上下文,在restore中断上下文时直接跳转至schedule。

       ä¸­æ–­ä¸Šä¸‹æ–‡çš„恢复

       å…¨å±€çš„中断计数器INT_Count是否为0来判定当前出栈的信息,如果是嵌套则返回LISR中,否则切换至system stack执行schedule

       timer

       timer与中断紧密相关,其实timer也是中断的一种,只是发生中断的频率较高,且作用重大,一个实时操作系统,时间是非常重要的一部分,NU中的timer主要有四个作用:

       ï¼ˆ1)维护系统时钟 TMD_system_clock

       ï¼ˆ2)task的time slice

       ï¼ˆ3)task的suspend timeout timer

       ï¼ˆ4)application timer

       å…¶ä¸­ï¼ˆ3)(4)共用一种机制,一个全局的时间轴TMD_timer,timeout timer和app timer都建立在一个TM_TCB的数据结构上,通过tm_remaining_time来表征当前timer的剩余时间,例如当前有timer_list上有三个TM_TCB,依次是Ta = 5,Tb = 7, Tc = ,那么建立的链表上剩余时间依次是5,2,8,如果现在要加入一个新的timer根据timer值插入至合适的位置,如果插入的timer为,则安排在Tb后面,剩余时间为1,后面的8改为7,当发生了timer expired,则触发timer_HISR,如果是app timer则执行timer callback,如果是task timeout timer,则执行TCC_Task_Timeout唤醒task。

       ï¼ˆ2)的实现也是依赖于全局的time slice时间轴,每一个task在执行时都会将自己的时间片信息更新至全局的时间轴上,当一个task的time slice执行完在timer HISR中调用TCC_task_Timeout将当前的task放在相同优先级list的最尾端,并设置下一个最高优先级的任务。task在执行的过程中只有被中断后time slice会保存下来,其他让出处理器的情况都会将time slice更新为预设值。

       protect

       protect与linux的锁机制类似,互斥访问,利用开关中断来实现,并且拥有protect的task是不可以suspend的,必须要将protect释放后才可以挂起,当一个优先级较低的task占有protect资源,如果被抢占,一个高优先级的task或HISR在请求protect资源时会执行TCC_schedule_protect()让出处理器给低优先级的task执行,直到低优先级的task执行unprotect()为止,此时task或HISR建立的是solicited stack,同时在control_to_thread前开关中断一次,这样可以减少一次上下文的切换。NU中常用到的是system_protect,它就是一把大锁,保护内核中所有全局数据结构的顺序访问,粒度很大。

       LISR中不可以请求protect资源,因为LISR是中断task后执行,如果task占有protect资源,这时LISR又去请求protect资源,会发生死锁,因为LISR让出处理器后,schedule没办法再次调度到LISR执行,则发生死锁错误,因此在LISR中除了activate_HISR()以外不可以使用system call,例如resume_task等等,这写系统调用都会请求protect资源。

       å¯¹äºŽprotect的请求按照一定的顺序可以防止死锁,NU的源码中一般将system_protect资源的请求放在后面,其他如DM_protect先请求。

关键词:msv源码

copyright © 2016 powered by 皮皮网   sitemap