eCos内核概览

合集下载

基于eCos的嵌入式远程测控系统设计

基于eCos的嵌入式远程测控系统设计
a d r l b l y,a di a e wieyusd i h n u ty c n r la e . n ei i t a i n tc n b d l e n t eid s r o to r a
Ke wo d :e b d e y tm ;e s y r s m e d d s se Co ;m e s rm e ta d c n r l y tm ;ra i es se a u e n n o to se s e lt y t m m
0 引 言
当前 , 控制技 术 已经在 工业控 制领域 得 到快速 的 网络
程 监控 ;
() 有一定 的通用 性 , 定 的人 机 交互 功能 , 3能 有一 方便
实际中对工业参数的设定 、 系统的维护和扩充性 。 考虑如上要求 , 本文设计出如 图 1 所示的硬件结构。
R A M ¥C 4 0 含一 个 1/2b的 R S ( R 2T) 3 21 包 6 3 IC A M90 的
De i n o e o e m e s r m e nd c n r le b d e s g f r m t a u e nta o t o m e d d
s se a e n e s y t m b s d o Co
L i i e J
( S gn eig CO., CI DIEn iern LTD,Ch n qn 0 0 0 o i 403) g g
raie r mo emo i rn e l e t nt ig,t ed sg a e na m b d e n o f u e y tm ,n m ey t go m b d e y tm , z o h e inb sd o ne e d d a d c n i r ds se g a l hee se e d d 2 卷 第5 5 期

ecos内存管理

ecos内存管理
该函数产生一个可进行固定大小内存分配的定长内存池。堆大小不一定是整个可用内存的大小。定长内存池在速度上要优于变长的。新产生的内存池可以通过句柄对其进行访问。
2、删除内存池
void cyg_mempool_fix_delete(内存池句柄)
该函数删除定长内存池。不要删除正在使用的内存池,否则会引起系统错误。
7、检查是否有线程正等待分配内存
cyg_bool_t cyg_mempool_var_waiting(句柄)
8、取得内存池信息
void cyg_mempool_var_get_info(句柄,要返回的信息结构指针)
注意不定长分配内存时为了避免小碎片影响系统性能,应限定可变内存申请的最小值为一个比较大的数信箱和线程所需内存块
static char memvar[CYGNUM_LWIP_VARMEMPOOL_SIZE];//可变长内存池实体
static cyg_mempool_var var_mempool;//内存池结构体变量,详见kapidata.h.
#include "arch/sys_arch.h"
#include "lwip/sys.h"
#include "lwip/def.h"
#define tick_to_msec(tick) ((u16_t)((tick)*10+1))
#define msec_to_tick(msec) ((cyg_tick_count_t)(msec+9)/10)
***********************
1、创建内存池
void cyg_mempool_fix_create(堆起址,堆大小,内存块大小,返回的内存池句柄,固定内存池结构体)

(原创)eCos驱动分析 之 ISR是如何与硬件中断联系起来的 ---转载文章

(原创)eCos驱动分析 之 ISR是如何与硬件中断联系起来的 ---转载文章

(原创)eCos驱动分析之ISR是如何与硬件中断联系起来的---转载文章要想知道ecos的中断ISR是怎么与硬件中断向量联系起来的,是怎么被调用的?那就要看下面这两个关键的函数:cyg_drv_interrupt_create()cyg_drv_interrupt_attach()这两个函数都声明在cyg/kernel/kapi.h中,其形式如下:void cyg_interrupt_create( cyg_vector_t vector, /* Vector to attach to */ cyg_priority_t priority, /* Queue priority */ cyg_addrword_t data, /* Data pointer*/ cyg_ISR_t *isr, /* Interrupt Service Routine */ cyg_DSR_t *dsr, /* Deferred Service Routine */ cyg_handle_t *handle, /* returned handle */ cyg_interrupt *intr /* put interrupt here */) __THROW;void cyg_interrupt_attach( cyg_handle_t interrupt )__THROW;(注: __THROW是在C++中用的,是用来抛出异常的,详见我的博文/blog/static/888807432011611193510/ 这里可以视而不见.)其中文意义对照如下:cyg_interrupt_create( 中断号, 中断优先级, 传递的中断参数, ISR函数,DSR函数, 被返回的中断句柄, 存放与此中断相关的内核数据的变量空间);cyg_interrupt_attach(中断句柄);这样实际上去研究一下cyg_interrupt_create函数的定义内容,应该就能搞明白我们的问题了!由于其函数声明在kapi.h中,很自然的就想到其定义应在kapi.c文件中,找到....\ecos\ecos-current\packages\kernel\current\src\common\kapi.cxx文件,找到这两个函数的定义如下:/*---------------------------------------------------------------------------*//* Interrupt handling*/externC void cyg_interrupt_create( cyg_vector_t vector, /* Vector to attach to */ cyg_priority_t priority, /* Queue priority*/ cyg_addrword_t data, /* Data pointer */ cyg_ISR_t*isr, /* Interrupt Service Routine */ cyg_DSR_t *dsr, /* Deferred Service Routine */ cyg_handle_t *handle,/* returned handle */ cyg_interrupt *intr /* put interrupt here */) __THROW{ CYG_ASSERT_SIZES( cyg_interrupt,Cyg_Interrupt );Cyg_Interrupt *t = new((void *)intr) Cyg_Interrupt( (cyg_vector)vector, (cyg_priority)priority, (CYG_ADDRWORD)data, (cyg_ISR *)isr,(cyg_DSR *)dsr ); t=t;CYG_CHECK_DATA_PTR( handle, "Bad handle pointer" ); *handle = (cyg_handle_t)intr;}voidcyg_interrupt_attach( cyg_handle_t interrupt )__THROW{ ((Cyg_Interrupt *)interrupt)->attach();}函数内容比想象中的简单,所有的操作又都传给了Cyg_Interrupt这个类来完成,那就来对Cyg_Interrupt探个究竟吧:(注意Cyg_Interrupt是个C++类, 可不要找成了struct cyg_interrupt,注意哟,cyg_interrupt_create函数的最后一个参数就是这个cyg_interrupt struct类型的,在cyg/kernel/kapidata.h中有个struct cyg_interrupt定义,虽然名字和内容都很相似,但实际上不是.)真正的class Cyg_Interrupt定义在cyg/kernel/intr.hxx中,这个头文件没干别的,就是声明这个class了,可见这是一个很大的class,如下:// -------------------------------------------------------------------------// Interrupt class. This both represents each interrupt and provides a static// interface for controlling the interrupt hardware.class Cyg_Interrupt{friend class Cyg_Scheduler; friend voidinterrupt_end( cyg_uint32,Cyg_Interrupt *,HAL_SavedRegisters *); friend voidcyg_interrupt_post_dsr( CYG_ADDRWORD intr_obj );friend void cyg_interrupt_call_pending_DSRs( void );cyg_vector vector; // Interrupt vector cyg_priority priority; // Queuing priority cyg_ISR *isr; // Pointer to ISR cyg_DSR *dsr; // Pointer to DSRCYG_ADDRWORD data; // Data pointer // DSR handling interface called by the scheduler// Check for pending DSRs static cyg_bool DSRs_pending();// Call anypending DSRs static void call_pending_DSRs(); static void call_pending_DSRs_inner();// DSR handling interface called by the scheduler and HAL // interrupt arbiters.void post_dsr(); // Post the DSR for this interrupt // Data structures for handling DSR calls. We implement two DSR // handling mechanisms, a list based one and a table based // one. The list based mechanism is safe with respect to temporary // overloads and will not run out of resource. However it requires // extra data per interrupt object, and interrupts must be turned // off briefly when delivering the DSR. The table based mechanism // does not need unnecessary interrupt switching, but may be prone // to overflow on overload. However, since a correctly programmed // real time application should not experience such a condition, // the table based mechanism is more efficient for real use. The // list based mechainsm is enabled by default since it is safer to// use during development.#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_TABLE static Cyg_Interrupt *dsr_table[CYGNUM_KERNEL_CPU_MAX][CYGNUM_KERNEL_INTERRUPTS_DSRS_TABLE_SIZE] CYGBLD_ANNOTATE_VARIABLE_INTR;static cyg_ucount32dsr_table_head[CYGNUM_KERNEL_CPU_MAX]CYGBLD_ANNOTATE_VARIABLE_INTR;static volatile cyg_ucount32dsr_table_tail[CYGNUM_KERNEL_CPU_MAX]CYGBLD_ANNOTATE_VARIABLE_INTR;#endif#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LIST // Number of DSR posts made volatilecyg_ucount32 dsr_countCYGBLD_ANNOTATE_VARIABLE_INTR;// next DSR in list Cyg_Interrupt* volatile next_dsr CYGBLD_ANNOTATE_VARIABLE_INTR;// static list of pending DSRs static Cyg_Interrupt* volatile dsr_list[CYGNUM_KERNEL_CPU_MAX]CYGBLD_ANNOTATE_VARIABLE_INTR;#endif#ifdef CYGIMP_KERNEL_INTERRUPTS_CHAIN// The default mechanism for handling interrupts is to attach just // one Interrupt object to each vector. In some cases, and on some // hardware, this is not possible, and each vector must carry a chain // ofinterrupts.Cyg_Interrupt *next; // Next Interrupt in list// Chaining ISR inserted in HAL vector staticcyg_uint32 chain_isr(cyg_vector vector, CYG_ADDRWORD data);// Table of interrupt chains static Cyg_Interrupt*chain_list[CYGNUM_HAL_ISR_TABLE_SIZE];#endif// Interrupt disable data. Interrupt disable can be nested. On // each CPU this is controlled bydisable_counter[cpu]. When the // counter is first incremented from zero to one, the //interrupt_disable_spinlock is claimed using spin_intsave(), the // original interrupt enable state being saved in// interrupt_disable_state[cpu]. When the counter is decremented // back to zero the spinlock is cleared using clear_intsave().// The spinlock is necessary in SMP systems since a thread // accessing data shared with an ISR may be scheduled on a // different CPU to the one that handles the interrupt. So, merely // blocking local interrupts would be ineffective. SMP aware // device drivers shouldeither use their own spinlocks to protect // data, or use the API supported by this class, via //cyg_drv_isr_lock()/_unlock(). Note that it now becomes// essential that ISRs do this if they are to be SMP-compatible.// In a single CPU system, this mechanism reduces to just // disabling/enabling interrupts.// Disable level counter. This counts the number of times // interrupts have been disabled. static volatile cyg_int32 disable_counter[CYGNUM_KERNEL_CPU_MAX] CYGBLD_ANNOTATE_VARIABLE_INTR;// Interrupt disable spinlock. This is claimed by any CPU that has // disabled interrupts via the Cyg_Interrupt API. static Cyg_SpinLock interrupt_disable_spinlockCYGBLD_ANNOTATE_VARIABLE_INTR;// Saved interrupt state. When each CPU first disables interrupts // the original state of the interrupts are saved here to be // restored later. staticCYG_INTERRUPT_STATEinterrupt_disable_state[CYGNUM_KERNEL_CPU_MAX] CYGBLD_ANNOTATE_VARIABLE_INTR;public:Cyg_Interrupt // Initialize interrupt ( cyg_vector vector, // Vector to attach to cyg_priority priority,// Queue priority CYG_ADDRWORD data,// Data pointer cyg_ISR *isr,// Interrupt Service Routine cyg_DSR *dsr // Deferred Service Routine );~Cyg_Interrupt(); // ISR return values enum { HANDLED = 1, // Interrupt was handled CALL_DSR = 2// Schedule DSR };// Interrupt management void attach();// Attach to vector void detach();// Detach from vector // Static Interrupt management functions// Get the current service routine static voidget_vsr(cyg_vector vector, cyg_VSR **vsr);// Install a vector service routine static voidset_vsr( cyg_vector vector, // hardware vector to replace cyg_VSR *vsr,// my new service routine cyg_VSR **old = NULL// pointer to old vsr, if required ); // Staticinterrupt masking functions// Disable interrupts at the CPU static voiddisable_interrupts();// Re-enable CPU interrupts static voidenable_interrupts();// Are interrupts enabled at the CPU? static inline cyg_bool interrupts_enabled() { return (0 == disable_counter[CYG_KERNEL_CPU_THIS()]); } // Get the vector for the following calls inline cyg_vectorget_vector() { return vector; } // Static PIC control functions // Mask a specific interrupt in a PIC static void mask_interrupt(cyg_vector vector); // The same but not interrupt safe static voidmask_interrupt_intunsafe(cyg_vector vector);// Clear PIC mask static voidunmask_interrupt(cyg_vector vector); // The same but not interrupt safe static voidunmask_interrupt_intunsafe(cyg_vector vector);// Acknowledge interrupt at PIC static void acknowledge_interrupt(cyg_vector vector);// Change interrupt detection at PIC static void configure_interrupt( cyg_vector vector,// vector to control cyg_bool level,// level or edge triggered cyg_bool up// hi/lo level, rising/falling edge );#ifdef CYGPKG_KERNEL_SMP_SUPPORT// SMP support for associating an interrupt with a specific CPU. static void set_cpu( cyg_vector,HAL_SMP_CPU_TYPE cpu ); static HAL_SMP_CPU_TYPE get_cpu( cyg_vector );#endif };这只是声明了这个class,这个class的构造/析构函数和成员函数的实现,还要找cyg/kernel/intr.hxx头文件相对应的C文件,在这里....\packages\kernel\current\src\intr\intr.cxx 找到了intr.cxx文件,因为cyg_interrupt_create函数实际上调用了classCyg_Interrupt的构造函数,我们就来看看这个构造函数: Cyg_Interrupt::Cyg_Interrupt( cyg_vector vec,// Vector to attach to cyg_priority pri,// Queue priority CYG_ADDRWORD d,// Data pointer cyg_ISR *ir,// Interrupt Service Routine cyg_DSR *dr// Deferred ServiceRoutine ){ CYG_REPORT_FUNCTION();CYG_REPORT_FUNCARG5("vector=%d, priority=%d,data=%08x, isr=%08x, ""dsr=%08x", vec, pri, d, ir, dr); vector = vec; priority = pri; isr = ir; dsr = dr; data = d;#ifdef CYGIMP_KERNEL_INTERRUPTS_DSRS_LISTdsr_count = 0; next_dsr = NULL;#endif#ifdef CYGIMP_KERNEL_INTERRUPTS_CHAINnext = NULL;#endifCYG_REPORT_RETURN();};也就是分配了一下成员变量,把cyg_interrupt_create函数传进来的中断号、ISR、DSR等分配给类的成员变量,好像也没什么特别的。

EEOS

EEOS

EEOS内核分析报告(线程与调度部分)——工程实践总结计73班魏小亮971290一、EEOS概况Easy Embedded OS (EEOS )嵌入式操作系统是中科院计算所组织开发的开放源码的嵌入式操作系统。

该嵌入式操作系统重点支持p-Java,要求一方面小型化,一方面能复用Linux的驱动和其他模块。

EEOS的系统功能结构如下图所示:中科院在EEOS的开发上利用CYGNUS公司的RTOS(Real Time Operating System实时操作系统)eCos作为蓝本,并利用Utah大学的可重用OS工具OS-Kit作为开发基础,在此之上建立自己的驱动程序、API、Java虚拟机和相应软件开发工具和调试器,同时把Mini GUI纳入EEOS体系,最后形成了上图EEOS构架。

(该项目持续两三年,现在仍在发展。

)EEOS的目标是重点支持机顶盒产品的网络传输和多媒体浏览功能,同时具有非常灵活的可移植性。

二、内核总览[内核特点]我们研究的RTOS内核来自eCos实时内核。

作为EEOS的底层,eCos内核具有以下特征:1、实时性。

内核从调度器内部支持线程的实时特征,实现了真正意义上的实时性。

而通过Linux裁减的RTOS一般是在内核的外部添加一层外壳(Shell)来解决实时性的问题,并不能真正意义支持的实时功能。

2、可配置性。

内核的大小和功能非常灵活。

整个内核小于50K,核心源代码(C++程序)约17000行。

但实际应用的时候,配置非常灵活,eCos支持实时性/非实时性进程,BitMap/多级队列/彩票调度三种线程调度方式,单链表/多链表两种Alarm组织方式,固定大小内存/可变大小内存……用户可以根据实际应用生成自己需要的系统。

eCos 提供了可视化的系统配置工具,可以在windows上对系统(包括内核)进行各种配置。

3、支持uItron核心服务界面标准。

uItron是专门为实时系统制定的专用标准。

适用于代码尺寸限制严格的场合。

基于ARM920T的嵌入式系统eCos移植分析及应用

基于ARM920T的嵌入式系统eCos移植分析及应用

AR 2 T 处理器 内核 , M9 0 采用 0 1 x 制 造工艺 , . 8/ m 最 高操 作 频率 达 到 2 3MHz的微 处 理 器 。凭 借 低 价 0 格 、 功耗 、 低 高性 能 的 品质 , 国 内外 广 泛应 用 于 各 被 类 开发 板及 手持 便 携 设 备 中 。然 而 在 e o C s的官方
网站及 相关 文献 中并 没 有 公 布 e o C s针 对 ¥ C 4 0 3 2 1
i g wih ma e t m i i u n m m c nfgu a i wa buit O o i r ton s l t
gu d Co .The o ec fg a i nsa a k ge iee s n m r on i ur to nd p c a s w e e a de O t e t r e a d a e la n e S r d d t h a g t bo r s w l s a CO a plc to pr g a W a c m p l d T he r s t p ia in o rm S o ie . e ul s o s t a e s nd t a h w h t Co a is ppl a i n r r m c n i to p og a c a r n r a l h a g tbo r u no m ly on t e t r e a d.
CHENG n Yo g—Ia , ITig—j n. IXi u, I a~q n n o L n u CA n—j L U Hu i
( v lAe o a t a n ie rn n t u e Ya t i 6 0 1, h n ) Na a r n u i lE g n e i g I s i t , n a 4 0 C i a c t 2

面向eCos的嵌入式软件集成开发环境设计

面向eCos的嵌入式软件集成开发环境设计
组件 的嵌入式 可配置实时操作 系统 , 具有 良好 的可移植 性, 支持 当前 流行 的 A M、o eP X 6等 众 多体 系 的 R P w rC、 8 嵌入式处理器 , 以在 1 可 6位 、2位 和 6 3 4位 系 统之 上运 行 。 目前市场 上 已经 有许 多 应用 e o C s的嵌 入 式 产 品 , 为 了加快基 于 e o C s的嵌入 式系 统 的开 发 , 计 一 个优 设 秀的嵌入式 系统集成 开发环境非常重要 。
i 回
1 e o 操 作 系统 简 介 Cs
嵌 入式 可配 置操作 系 统 e o E e ddC n g — C s( mb d e of u i rbeO e t n Ss m) R d a 推 出 的嵌 入 式 实 a l pr i yt ¨ 是 e H t ao e 时操 作系统 。它 是 一个 源 码 开放 的操 作 系统 , 有 良 具
收 稿 日期 :070 -9 20 -31 修 订 日期 :07 6 6 20 - - 0 0
作者简 介: 马
辉( 9 2) 男 , 1 7 一 , 山西芮城人 , 高级工程师 , 研究 方向为计算机应用及系统仿 真。
维普资讯
20 07年 7月
的标 准 函数 ,C s 许 多软 件包 提 供 对 现有 A I的兼 eo有 P
容 , P SX和 IT O 应 用程序 可 以调 用 一些 标 准 如 OI x R N, l 函数 如 phed c a t a—r t r e e来使 用 内核服务 。
r . …………一
荏 ……………
嵌入式系统 主要 由嵌 入式 处理 器 、 关 支撑 硬件 、 相
理 、 务 f通 信 、 任 司 例外 处理等 。e o 内核结构 如 图 1 Cs 所

eCos用户指南之手动配置_翻译

eCos用户指南之手动配置_翻译
这段允许配置工具重载各种包形成配置。大多数信息不应该被编辑。如果需
要增加一个新包或者删除一个已存在的包应该用合适的工具,例如:
$ ecosconfig remove CYGPKG_LIBM
有 两 个 地 方 可 以 编 辑 。 配 置 有 个 名 字 , 这 里 是 eCos ; 有 一 个 描 述
跟着头段的段定义配置的整体。一个典型的例子是:
# ---- toplevel -------------------------------------------------------# This section defines the toplevel configuration object. The only # values that can be changed are the name of the configuration and # the description field. It is not possible to modify the target, # the template or the set of packages simply by editing the lines # below because these changes have wide-ranging effects. Instead # the appropriate tools should be used to make such modifications.
eCos User Guide(Chapter 28.manual Configuration)
eCos 用户指南之手动配置_翻译
翻译:JARI TOOL
1. 编辑一个 eCos 存档文件
eCos 配置信息存放在一个存档文件(savefile)中,典型的是 ecos.ecc, 这个文件既可以通过 GUI 界面配置工具产生,也可以通过命令行 ecosconfig 配 置工具产生。这个文件通常存在于编译树(build tree)的顶层。它是一个文本 文件,允许通过文本编辑器、其它程序或脚本来编辑各种配置选项,也可以在 GUI 配置工具里编辑。

三种开源嵌入式操作系统的比较

三种开源嵌入式操作系统的比较

;i●■三种开源嵌入式操作系统的比较苟军年(兰州交通大学自动化与电气工程学院甘肃兰州730070)信息科掌【捕要】嵌入式操作系统的性能和选择是大多数嵌入式系统开发都要面临的问题。

比较3种开源嵌入式操作系统嵌入式L i nu x、Q N x和ecos,分析3种开源操作系统的主要性能,并根据分析结果指出各自的适用领域.【关键词】嵌入式操作系统RT O S嵌入式系统中图分类号:TP316.2文献标识码:A文章编号i1671--7597(2008)1110061--01一、三种开曩E O S介绍(一)嵌入式L i M U X.L i n ux是一个类似于U ni x的操作系统,它已经是最为流行的一款开放源代码的操作系统。

嵌入式L i nux由于其源代码公开,人们可以任意修改来满足自己的应用。

像大多数自由软件一样,L i nux遵从G PL,因此使用它无须为每例应用交纳许可证费。

Li nux下的应用软件大量可用,其中大部分都遵从GPL,是开放源代码和免费的。

稳定是L i nu x本身具备的一个很大优点。

内核精悍,运行所需资源少,支持的硬件数量庞大等都是Li nux所具备的.(二)O N X∞。

Q N)【O S是由0N X软件系统有限公司开发的一套实时操作系统,它是一个实时的、可扩展的操作系统,部分遵循了PO S I X( Por t abl e O per a t i ng S ys t em I nt er f ace of U ni x)相关标准,可以提供一个很小的微内核及一些可选择的配合进程。

其内核仅提供4种服务:进程调度、进程阃通信、底层网络通信和中断处理。

(三)e C os。

e C os(e m be dde d C onf i gur a bl e oper a t i ng syst em),即嵌入式可配置操作系统。

它是一个源代码开放的可配置、可移植、面向深度嵌入式应用的实时操作系统。

其最大特点是配置灵活,采用模块化设计,包括内核、c语言库和底层运行包在内的核心部分由不同的组件构成。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

eCos内核概览eCos内核概览(1)实时内核eCos的核心是一个功能全面的,灵活的,可配置的实时内核。

这个内核提供了多线程支持,多种调度器的选择,一组丰富的同步原语,内存分配原语和线程管理函数。

在这个内核中,可以改变或替换其中的某些部分(比如调度器)而不会影响内核本身的别的模块。

下列是这个内核的一些特征:可以选择内存分配算法可以选择调度算法一组丰富的同步原语定时器,计数器和alarms中断处理exception处理cache控制线程支持内核支持用GDB进行多线程调试trace buffersinfrastructure and instrumentationeCos内核概览(2)调度器调度器是内核的核心。

它定义了线程运行的方式,提供了线程同步的机制。

它也控制中断是如何影响线程执行的。

没有一个调度器可以覆盖所有可能的系统配置。

我们需要几种调度策略来满足不同的需要。

这里提供了三种调度器。

位图调度器位图中每一位表示一个可运行的线程,而每个线程有一个独一无二的优先级,系统允许的线程数是有上限的。

多级队列调度器可以在相同优先级线程之间按时间片轮换,支持优先级继承。

lottery调度器目前在任何时候系统只支持一种调度器。

将来系统会允许多种调度器共存,但是这将会隐藏在现有的调度器API后。

为了能够安全调度,我们需要一种在并发访问中保护调度器数据结构的机制,传统的方法是在这个临界区禁止中断。

不幸的是,这增加了中断的最大dispatch延迟,在任何实时系统中都应当避免这种情形的发生。

eCos采用的机制是保持一个计数器,Scheduler::sched_lock。

如果它的值不为0,就防止了重新调度。

当前的中断通过调用Scheduler::lock()得到这个锁,它对这个计数器加1避免进一步的调度。

函数Scheduler::unlock()对这个计数器减1,如果它返回0,允许继续调度。

为了在中断存在的情况下这种机制能够很好地工作,需要ISR推迟执行任何引起调度(scheduler-oriented)的操作,直到这个锁将要为0。

为此我们把ISR的工作分割成两部分。

并把第二部分,DSR,写进队列,直到调度器认为运行它们是安全的。

(细节见第三章的中断和exception handler)在单处理器上,Scheduler::lock()仅仅是对Scheduler::sched_lock加1。

既然这个锁严格地被嵌套,Scheduler::lock()不需要一个读-修改-写周期。

当前线程正在运行这个事实意味着这个锁还没有被别的线程获得,因此它总是可获得的。

eCos内核概览(3)线程同步为了允许线程协调和竟争资源,提供同步和通讯机制是必要的。

传统的同步机制是互斥/条件变量和信号量。

eCos内核不但支持这些机制,它还提供了在实时系统中普遍用到的其它同步和通讯机制,例如event flags和消息队列。

在任何实时系统中必须处理的一个问题是优先级倒转(priority inversion)问题。

它出现在一个高优先级线程(错误地)被一个低优先级线程阻止了继续执行。

一般的例子是:一个高优先级线程等待一个互斥量,而这个互斥量正被一个低优先级线程所拥有,如果这个低优先级线程被一个中等优先级的线程剥夺了运行,那么就发生了优先级倒转,既然这个高优先级线程被一个不相关的较低优先级线程阻止了继续执行。

这里有好几种方法可以解决这个问题。

最简单的是运用一个优先级ceiling protocal。

所有获得这个互斥量的线程把它们的优先级提升到一个事先规定好的值。

它有如下不利因素:它需要事先知道使用这个互斥量线程的最高优先级;如果这个事先规定的值太高,它相当于一个全局锁禁止了所有的调度。

一个更好的解决方案是使用优先级继承协议,拥有互斥量的线程的优先级被提升到与正在等待这个互斥量的最高优先级线程的优先级相等。

这个技术不需要预先知道准备使用这个互斥量线程们的优先级。

当一个更高优先级线程处于等待时,只有拥有互斥量的线程的优先级被提升。

这种方法减少了对别的线程进行调度的影响。

但是它的不利之处在于:每次同步调用的开销增加了,因为每次都得遵守这个继承协议。

第三种方法是:认识到糟糕地选择了相对的线程优先级,因此这个发生优先级倒转的系统本身是有缺陷的。

在这种情况下,当发生优先级倒转时,内核要有能力检测到,并产生一个exception来调试这个系统。

eCos提供了一种相对简单的实现方式。

它只在多级队列调度器中有效,它同时不能完全正确地处理嵌套的互斥量的极端例子。

但是,它不但速度快而且是确定性的。

如果不需要互斥优先级倒转,可以disable它,这将减少代码大小和数据空间。

eCos内核概览(4)例外(exceptions)一个exceptions是一个同步事件,它由一个线程在执行时产生。

exception包括硬件引起的机器exception(比如除零,内存出错和非法指令)和软件引起的机器exception(比如deadline overrun)。

标准c++ exception机制代价太昂贵了而不能在这儿使用。

处理exception最简单和最灵活的方式是调用一个函数。

这个函数需要赖以工作的上下文,因此需要访问一些工作数据。

这个函数至少也需要exception号和一些可选参数。

exception handler接受一个数据参数,这个参数是一个用handler和上下文信息指针注册的值。

它也接受一个exception号和一个错误码,exception号用来确认哪个exception产生了,而错误码则包含处理这个exception时需要的额外信息(比如一个内存出错地址)。

从这个函数返回使得线程继续执行。

根据配置选项,exception handler可以是全局的也可以是每个线程一个(per-thread),或者两种情况都有。

如果exception handler是每个线程一个,必须把exception handler附带(attach)在每个线程上。

eCos内核概览(5)中断中断是由外设引起的异步事件。

在任何时候它们都有可能发生。

它们并不与当前正在运行的线程有一丝联系。

中断处理是RTOS设计中最复杂的一部分,主要由于it is the least well defined。

如何对中断向量命名,如何把中断递交给软件和如何屏蔽中断都是高度与特定CPU结构(有时候与特定板)相关的。

让我们考虑一下中断向量这个问题。

这儿是硬件支持主要的差异:Intel和680X0支持把中断导引(vectored)到它们自己的向量上,而大多数RISC只有一个向量。

第一种情况,可以直接把ISR附带在这个向量上;第二种情况,必须确定实际是哪个外设产生中断,然后导引到正确的ISR。

如果这儿有一个外部中断控制器,将有可能对它进行查询并硬件实现本来是由软件实现的一些操作。

如果没有外部中断控制器,就必须依次调用ISRs对外设进行测试来决定产生中断的外设。

既然两个外设可以同时产生中断,那么每次中断产生时,就必须调用所有的ISRs。

屏蔽中断也有同样的问题。

大多数处理器在状态寄存器上有一个简单的中断屏蔽位。

而680X0有七级屏蔽。

可以对任何带有中断控制器的板进行编程提供相同的多级屏蔽。

必须保持中断屏蔽机制简单和高效,同时只需要CPU结构支持。

操作一个板上的中断控制器代价可能太高。

然而,个别的设备驱动程序可能需要访问中断控制器上个别的屏蔽位,因此必须提供这种支持。

eCos内核概览(6)计数器、时钟、ALARM和定时器如果硬件提供一个周期性时钟或定时器,它们将会用来驱动与定时有关的系统features。

很多CPU结构现在都有内嵌的定时寄存器,它们可以提供一个周期性中断。

应当用它们来驱动这些features。

要不然就必须使用一个外部的定时器/时钟芯片。

我们区分计数器,时钟,alarm和定时器:一个计数器保持一个递增的counter,它由一些ticks源驱动。

一个时钟是由一个有规律的ticks源驱动的计数器。

时钟有一个相关联的精度。

一个缺省系统时钟由上面提到的周期性中断驱动,tracks real-time。

别的中断源可能驱动另外一些计数器,它们以不同精度track real-time。

一些计数器可以被非周期的事件驱动,因此与实时没有一点联系。

一个Alarm附带在一个计数器上,基于counter的值,提供了一种产生single-shot或周期性事件的机制。

一个定时器是一个附带在时钟上的简单Alarm。

系统(包括内核)以ticks单元表示时间。

这儿有特定时钟的时间单元和通常是定时器中断的周期。

只有在必需的情况下,通过库函数完成由ticks到传统时间和数据单元的转换。

需要用64位表示当前tick count。

这需要编译器支持64位整数或汇编码。

第五章的时钟,计数器和alarm描述影响时钟,计数器和alarm的时钟API。

相关文档
最新文档