亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

helloworld程序是如何被調用的

發布時間:2021-12-23 09:09:43 來源:億速云 閱讀:129 作者:柒染 欄目:互聯網科技

helloworld程序是如何被調用的,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。

分析 helloworld程序是如何被調用,SYS_RUN做什么事情

相信大家都已經在鴻蒙系統上實現了自己的第一個helloworld程序了。

 helloworld程序是如何被調用的

代碼很簡單,編譯燒錄后,我們就可以看到串口有打印 [DEMO] Hello world. 

但是 HelloWorld 函數是在何時被調用的呢?SYS_RUN 又是干嘛的呢?

我們來看下。

1. 啟動流程

首先,我們需要分析一下Hi3861的啟動流程。目前Hi3861 使用的是liteOS-M內核,相關源碼廠家沒有提供,不過也不妨礙我們。經過我一番查找,可以知道hi3861啟動內后,第一個入口函數是 app_main函數。

(vendor\hisi\hi3861\hi3861\app\wifiiot_app\src\app_main.c)

大家可以打開,看到app_main函數的內容,如下,當然我這里只是簡版的,我刪除了很多初始化的函數,只保留最終要的。

hi_void app_main(hi_void)
{
 //打印sdk版本
 const hi_char* sdk_ver = hi_get_sdk_version();
    printf("sdk ver:%s\r\n", sdk_ver);

 //串口、IO初始化等
 peripheral_init();

 //wifi初始化
 ret = hi_wifi_init(APP_INIT_VAP_NUM, APP_INIT_USR_NUM);


 //鴻蒙系統初始化
 HOS_SystemInit();
}

我們可以看到其實app_main啟動后做了很多工作,包括io初始化、wifi初始,最后調用了HOS_SystemInit(); 進行鴻蒙系統最后的初始化。

那我們看下 HOS_SystemInit(); 做了什么動作吧。

打開源碼 base\startup\services\bootstrap_lite\source\system_init.c

可以看到函數內容如下:

void HOS_SystemInit(void)
{
    MODULE_INIT(bsp);
    MODULE_INIT(device);
    MODULE_INIT(core);
    SYS_INIT(service);
    SYS_INIT(feature);
    MODULE_INIT(run);
    SAMGR_Bootstrap();
}

看起來好像在調用某些模塊,仔細看,其中有一個是 MODULE_INIT(run); 。顧名思義,好像在初始化或者調用 一個 run 模塊。那run模塊又是什么呢?我們看下標題的 SYS_RUN(HelloWorld)。 是不是可以猜測其實MODULE_INIT(run); 就是調用了 HelloWorld 呢?

哈哈哈~其實還真是。大家如果加打印信息,可以看到如下打印。

../../base/startup/services/bootstrap_lite/source/system_init.c 38 

../../applications/sample/wifi-iot/app/my_first_app/hello_world.c 9 

[DEMO] Hello world.

../../base/startup/services/bootstrap_lite/source/system_init.c 40

仔細看我加的打印語句,確實是在 38 行執行 MODULE_INIT(run); 后才打印 [DEMO] Hello world.

所以跟我們猜測的一樣。當然沒完,我們得分析為啥 是這樣。

 

2. 鏈接

我們看下 MODULE_INIT(run);  做了什么。事實上,它只是一個宏。

#define MODULE_INIT(name)     \

    do {                      \

        MODULE_CALL(name, 0); \

    } while (0)

而 MODULE_CALL(name, 0); 又可以展開:當然里面的if 語句的打印是我后面加的

 helloworld程序是如何被調用的

我們可以看到 它其實是定義了一個  InitCall 指針,然后指針是這個:

(MODULE_BEGIN(name, step))

而 MODULE_BEGIN 宏其實展開后如下:

#define MODULE_NAME(name, step) ".zinitcall.">

我這里再幫大家展開,其實".zinitcall." #name #step ".init" 最后 就是 .zinitcall.run2.init

它其實是一種寫法,就是說我們代碼編譯的時候,代碼里面有一段地址比較特殊,它的名字是 .zinitcall.run2.init ,也就是說 InitCall 指針 指向的是 .zinitcall.run2.init 代碼段的地址。

畫個圖:

綠色的是.zinitcall.run2.init 代碼段,里面存放著函數指針。

 helloworld程序是如何被調用的

好了,到這里大家應該都明白了吧,繼續看這個圖,其實 這里只不過是把這個代碼段里面的所有函數指針都取出來,然后執行一下函數指針指向的函數。

 helloworld程序是如何被調用的

到了這里就剩下最后一個問題了: 怎么讓它指向 HelloWorld 函數。

這里其實就是 SYS_RUN的功勞了。

我們也來看SYS_RUN做了什么,其它也是一個宏,展開過程如下:

我們可以看到,其實SYS_RUN(HelloWorld) 其實最終結果就是:

static const InitCall USED_ATTR __zinitcall_##layer##_##func \

        __attribute__((section(".zinitcall.">

看起來很復雜,我們不乏拆解一下:

 helloworld程序是如何被調用的

我們先不看紅色字體部分,那么結果就是:

static const InitCall  = HelloWorld

是不是很簡單,其實就是定義了一個全局變量(函數指針),它指向 HelloWorld 。

那紅色字體是做什么用呢?它其實就是告訴編譯,我這個變量(static const InitCall 變量),很特殊,編譯的時候給我編譯在 .zinitcall.run2.init 段。

3. 忠告

這里有兩個忠告:

1、請不要直接在SYS_RUN()定義的入口函數直接寫 while(1)

——這個很簡單理解了,因為系統啟動后,app_main會調用到 我們定義的SYS_RUN()定義的入口函數,比如HelloWorld。 如果我們在 HelloWorld 函數中寫了while(1) 就會導致 app_main 后續的代碼得不到執行,肯定有問題。

2、SYS_RUN()定義的入口函數創建的線程,請一定要有sleep動作。

為了解決第一個問題,我們很自然地想到,可以在 SYS_RUN()定義的入口函數 創建線程,這樣就可以while(1)了。哈哈,其實也是有問題,因為 app_main 本身也是一個任務,如果我們自己創建地任務優先級特別高,就會導致 app_main 任務不會被執行,還是有問題。所以要有sleep,確保 app_main 后續地代碼能順利執行下去。

看完上述內容,你們掌握helloworld程序是如何被調用的的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

桐柏县| 峨眉山市| 大足县| 股票| 新闻| 琼结县| 马公市| 大关县| 武胜县| 上林县| 句容市| 西丰县| 深水埗区| 类乌齐县| 桂平市| 融水| 巴东县| 清河县| 洱源县| 嘉兴市| 棋牌| 谷城县| 兴仁县| 利川市| 墨竹工卡县| 无锡市| 揭东县| 绥江县| 托里县| 时尚| 鄂伦春自治旗| 曲水县| 弥渡县| 泸定县| 南部县| 柳州市| 盐亭县| 林州市| 庆元县| 南皮县| 盐津县|