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新標準的一部分,用花括號 來初始化變數得到了全面應用。出於某些原因,這種初始化的方式叫做列表初始化。現在,無論是初始化物件還是某...