eCos组件初始化 .

来源:互联网 发布:农村淘宝服务站在哪 编辑:程序博客网 时间:2024/06/06 09:06

eCos组件初始化机制

eCos组件初始化利用了C++静态对象实例初始化的机制。C++对象在初始化时不像C语言中的静态变量那样只是在特定的内存单元写入特定的数值,C++对象在初始化时将会调用该对象类的构造函数来初始化对象。如果C++对象是在函数内声明,那么函数执行到对象的声明处调用类构造函数来初始化对象,如果C++对象在函数外声明,也就是将C++对象声明为全局对象或静态对象,那么编译器会将该对象的初始化代码地址(函数指针)写到名为".ctors"节,普通程序在进入main函数前由操作系统的运行时库调用存储在".ctors"中的函数指针列表来初始化全局或静态C++对象。

eCos应用在编译后同样会将全局或静态C++对象的初始化代码地址写到".ctors"节,在进入用户代码前,eCos HAL将调用cyg_hal_invoke_constructors函数,该函数调用存储在".ctors"节中的初始化代码。

需要注意的一点,".ctors"中存储的是对象初始化代码地址,而不是类构造函数,因为在初始化对象时,不仅要调用构造函数,而且还要给构造函数传入参数,即使是没有参数的默认构造函数也需要传入隐式的this指针。

忽略CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG选项的cyg_hal_invoke_constructors函数,如果配置了CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG选项,那么该函数将更加复杂些。

[cpp] view plaincopyprint?
  1. extern pfunc __init_array_start__[];   
  2. extern pfunc __init_array_end__[];    
  3. #define CONSTRUCTORS_START  (__init_array_start__[0])// ".ctors"的起始地址  
  4. #define CONSTRUCTORS_END    (__init_array_end__) // ".ctors"的终止地址  
  5. #define NEXT_CONSTRUCTOR(c) ((c)++)  
  6.   
  7. void  
  8. cyg_hal_invoke_constructors (void)  
  9. {  
  10.     pfunc *p;  
  11.     for (p = &CONSTRUCTORS_START; p != CONSTRUCTORS_END; NEXT_CONSTRUCTOR(p))  
  12.         (*p)();  
  13. }  
extern pfunc __init_array_start__[]; extern pfunc __init_array_end__[];  #define CONSTRUCTORS_START  (__init_array_start__[0])// ".ctors"的起始地址#define CONSTRUCTORS_END    (__init_array_end__) // ".ctors"的终止地址#define NEXT_CONSTRUCTOR(c) ((c)++)voidcyg_hal_invoke_constructors (void){    pfunc *p;    for (p = &CONSTRUCTORS_START; p != CONSTRUCTORS_END; NEXT_CONSTRUCTOR(p))        (*p)();}

C++语言实现的组件初始化

举个例子,每个操作系统都需要一个空闲线程,eCos也不例外,eCos的空闲线程就是以C++全局对象实例初始化机制来创建的。

[cpp] view plaincopyprint?
  1. Cyg_IdleThread idle_thread[CYGNUM_KERNEL_CPU_MAX] CYG_INIT_PRIORITY( IDLE_THREAD );  
  2.   
  3. Cyg_IdleThread::Cyg_IdleThread()  
  4.     : Cyg_Thread( CYG_THREAD_MIN_PRIORITY,  
  5.                   idle_thread_main,  
  6.                   0,  
  7.                   (char *)"Idle Thread",  
  8.                   (CYG_ADDRESS)idle_thread_stack[this-&idle_thread[0]],  
  9.                   CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE)  
  10. {  
  11.     Cyg_Scheduler::scheduler.set_idle_thread( thisthis-&idle_thread[0] );  
  12. }  
Cyg_IdleThread idle_thread[CYGNUM_KERNEL_CPU_MAX] CYG_INIT_PRIORITY( IDLE_THREAD );Cyg_IdleThread::Cyg_IdleThread()    : Cyg_Thread( CYG_THREAD_MIN_PRIORITY,                  idle_thread_main,                  0,                  (char *)"Idle Thread",                  (CYG_ADDRESS)idle_thread_stack[this-&idle_thread[0]],                  CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE){    Cyg_Scheduler::scheduler.set_idle_thread( this, this-&idle_thread[0] );}

从代码可以看出,eCos的空闲线程Cyg_IdleThread是从常规线程Cyg_Thread继承过来的,除了和常规线程一样的初始化过程外,额外地调用了Cyg_Scheduler::scheduler.set_idle_thread函数,该函数将本线程设置成eCos的空闲线程,并将本线程设置成就绪状态。

C语言实现的组件初始化

如果eCos组件是使用C语言实现的呢?举个例子,IO组件,该组件是使用C语言实现的,但是如果浏览他的源代码,会发现他有一个C++源代码ioinit.cxx,在这个文件中将定义一个C++类,而这个类唯一的作用就是在构造函数中调用cyg_io_init函数,然后声明一个静态的类实例来初始化IO组件。

[cpp] view plaincopyprint?
  1. externC void cyg_io_init(void);  
  2.   
  3. class cyg_io_init_class {  
  4. public:  
  5.     cyg_io_init_class(void) {   
  6.         cyg_io_init();  
  7.     }  
  8. };  
  9.   
  10. static cyg_io_init_class _cyg_io_init CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO);  
  11. ​  
externC void cyg_io_init(void);class cyg_io_init_class {public:    cyg_io_init_class(void) {         cyg_io_init();    }};static cyg_io_init_class _cyg_io_init CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO);​

初始化次序的问题

因为组件之间的依赖关系,初始化过程需要按照一定的次序进行。初始化的次序由CYGBLD_ATTRIB_INIT_PRI宏指定,该宏带有一个参数,该参数数值越小,那么越早调用该实例的初始化代码,例如_cyg_io_init对象的CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_IO)展开后为__attribute__((init_priority(49000))),而idle_thread对象的宏展开后为__attribute__((init_priority(11100))),由此可以判断空闲线程在IO组件之前被初始化。

检查初始化代码

使用nm和grep可以打印过滤可执行文件的符号列表来检查初始化代码,符号前缀“_GLOBAL__sub_I”表示这是静态对象初始化代码,符号中间部分的数字决定初始化次序,数字后面的部分如果是全局对象,那么是对象标识符,如果是静态变量,与对象的存储位置有关,可能是所在文件名,也可能是对象所在位置后面的全局标识符,反正不是对象标识符,这个有点混乱。

[plain] view plaincopyprint?
  1. $ nm app.elf | grep "t _GLOBAL"  
  2. 01001b20 t _GLOBAL__sub_I.10100_diag_write_char  
  3. 01002da0 t _GLOBAL__sub_I.11000_cyg_scheduler_sched_lock  
  4. 01002340 t _GLOBAL__sub_I.11100__ZN18Cyg_HardwareThread12thread_entryEP10Cyg_Thread  
  5. 01002630 t _GLOBAL__sub_I.12000__ZN13Cyg_Interrupt15disable_counterE  
  6. 01005d70 t _GLOBAL__sub_I.14000__ZN9Cyg_Clock15real_time_clockE  
  7. 01006020 t _GLOBAL__sub_I.19900_cygmem_pool_heap1  
  8. 01000050 t _GLOBAL__sub_I.49000_ioinit.cxx  
  9. 010063a0 t _GLOBAL__sub_I.56000__ZN20Cyg_libc_stdio_files5filesE  
  10. 01003290 t _GLOBAL__sub_I.56000_cyg_libc_main_thread  
  11. 01006300 t _GLOBAL__sub_I.56000_cyg_libc_stdio_stdin  
  12. 01003490 t _GLOBAL__sub_I.56001_cyg_libc_stdio_stdout  
  13. 01006260 t _GLOBAL__sub_I.56002_cyg_libc_stdio_stderr  
  14. 01000cc0 t _GLOBAL__sub_I.56100_cyg_iso_c_start  

原文见:http://blog.csdn.net/zoomdy/article/details/12754709