eCos元件初始化

2021-06-18 18:52:32 字數 3272 閱讀 9664

mingdu.zheng gmail com

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選項,那麼該函式將更加複雜些。

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)++)

void

cyg_hal_invoke_constructors (void)

舉個例子,每個作業系統都需要乙個空閒執行緒,ecos也不例外,ecos的空閒執行緒就是以c++全域性物件例項初始化機制來建立的。

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)

從**可以看出,ecos的空閒執行緒cyg_idlethread是從常規執行緒cyg_thread繼承過來的,除了和常規執行緒一樣的初始化過程外,額外地呼叫了cyg_scheduler::scheduler.set_idle_thread函式,該函式將本執行緒設定成ecos的空閒執行緒,並將本執行緒設定成就緒狀態。

如果ecos元件是使用c語言實現的呢?舉個例子,io元件,該元件是使用c語言實現的,但是如果瀏覽他的源**,會發現他有乙個c++源**ioinit.cxx,在這個檔案中將定義乙個c++類,而這個類唯一的作用就是在建構函式中呼叫cyg_io_init函式,然後宣告乙個靜態的類例項來初始化io元件。

externc void cyg_io_init(void);

class cyg_io_init_class

};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」表示這是靜態物件初始化**,符號中間部分的數字決定初始化次序,數字後面的部分如果是全域性物件,那麼是物件識別符號,如果是靜態變數,與物件的儲存位置有關,可能是所在檔名,也可能是物件所在位置後面的全域性識別符號,反正不是物件識別符號,這個有點混亂。

01001b20 t _global__sub_i.10100_diag_write_char

01002da0 t _global__sub_i.11000_cyg_scheduler_sched_lock

01002340 t _global__sub_i.11100__zn18cyg_hardwarethread12thread_entryep10cyg_thread

01002630 t _global__sub_i.12000__zn13cyg_interrupt15disable_countere

01005d70 t _global__sub_i.14000__zn9cyg_clock15real_time_clocke

01006020 t _global__sub_i.19900_cygmem_pool_heap1

01000050 t _global__sub_i.49000_ioinit.cxx

010063a0 t _global__sub_i.56000__zn20cyg_libc_stdio_files5filese

01003290 t _global__sub_i.56000_cyg_libc_main_thread

01006300 t _global__sub_i.56000_cyg_libc_stdio_stdin

01003490 t _global__sub_i.56001_cyg_libc_stdio_stdout

01006260 t _global__sub_i.56002_cyg_libc_stdio_stderr

01000cc0 t _global__sub_i.56100_cyg_iso_c_start

Flex 元件初始化順序

在flex中,我們經常會用到,當容器或者這個元件初始化的時候,或者建立完成的時候,就去做一些事情。那麼此時flex就會派發preinitialize initialize和creationcomplete事件。當子項初始化完成後,其父容器開始初始化。即子項總是先於父容器初始化完成。然而,只有當所有子...

初始化 指定初始化

id alloc 物件的誕生過程,主要是從作業系統獲得一塊足夠大的記憶體,以存放該類的全部例項變數,並將其指定為存放記憶體物件的實力變數的位置。alloc方法同時將這塊記憶體全部設定為0。結果是 bool變數初始化為no,所有的int型別變數為0,float變數為0.0,所有的指標為nil.obje...

初始化 1 預設初始化 列表初始化

初始化的基本概念 事實 初始化和賦值是兩個完全不同的操作。初始化,是建立變數時賦予其乙個初始值。賦值,是把物件的當前值擦除,用乙個新值代替。列表初始化 p39 作為c 11新標準的一部分,用花括號 來初始化變數得到了全面應用。出於某些原因,這種初始化的方式叫做列表初始化。現在,無論是初始化物件還是某...