linux原始碼分析1
其實linux的核心啟動的入口檔案還是非常好找的,init/main.c。
static 和 extern
首先理解的是static和extern的區別:
static int kernel_init(void *);
extern void init_IRQ(void);
extern void fork_init(void);
extern void radix_tree_init(void);
這個程式碼說的是kernel_init函式的定義在這個檔案中,extern說明init_IRQ函式的定義在其他檔案中。
這三個extern分別是對中斷的初始化,對fork功能的初始化,對基數樹的初始化。不過具體不知道為什麼有的函式以init_xxx為風格,有的又以xxx_init的風格來做。
巨集
main的第一行看到了這麼個語句
#define DEBUG
感覺有點奇怪,原來還有#define <巨集名> 而沒有定義具體的值。其實這個可以當作已經有定義,且定義了空串來理解。
http://bbs.csdn.net/topics/390960776?page=1
繼續往下面看,還會看到
bool early_boot_irqs_disabled __read_mostly;
這裡最後的__read_mostly 是一個巨集,它標記了前面這個變數是很經常被讀取的。那麼做了標記有什麼用呢?
如果在有快取的平臺上,它就能把這個變數存放到cache中,以保證後續讀取的速度。這個巨集定義在 arch/arm/include/asm/cache.h
#define __read_mostly __attribute__((__section__(".data..read_mostly")))
這裡的意思是將這個資料結構連結進data.read_mostly段。
EXPORT_SYMBOL
EXPORT_SYMBOL(system_state);
這個是和extern一起使用的,表示system_state這個方法在這個模組中定義了,提供給其他模組使用。
在其他模組中,只需要使用extern 就可以使用這個方法。
這裡就涉及到模組的概念。
模組是linux核心對外提供的一個外掛機制,由於linux是單核心,這個單核心是相對微核心來說的。所以linux很大可能會非常龐大,這個模組機制就是對單核心的一種補充,把一些功能放給核心模組開發。比如像上面的那個程式碼,就是對核心提供了system_state的函式介面。
__initdata
下面程式碼:
char __initdata boot_command_line[COMMAND_LINE_SIZE];
這裡的__initdata也是一個巨集,定義在include/linux/init.h
#define __init __section(.init.text) __cold notrace
#define __initdata __section(.init.data)
#define __initconst __constsection(.init.rodata)
#define __exitdata __section(.exit.data)
#define __exit_call __used __section(.exitcall.exit)
同上面__read_mostly一樣,是用來把這個變數繫結在某個區裡面。
http://blog.csdn.net/beatbean/article/details/8448623
這個圖就說明了什麼是__section。它的功能有點像是全域性變數,只是這個全域性變數是對彙編這個層次的表達,某個變數,我固定在某個記憶體段裡面。這麼做其實還有一個好處,段也是一種分類,比如這個段儲存的是init函式的變數,那麼等初始化結束之後,我把這個段的記憶體直接釋放。裡面的變數也一次性消除了。
EXPORT_SYMBOL_GPL
下面看到一個很奇怪的方法
EXPORT_SYMBOL_GPL(static_key_initialized);
這個和之前的EXPORT_SYMBOL不一樣,多了一個GPL字尾。
由於模組很有可能是第三方(非linux核心組成員)開發的。那麼有人希望自己開發的模組是閉源的。它就會在自己開發的模組裡面使用
MODULE_LICENSE("Proprietary")
來標記這個模組是閉源的。相對的,如果你的模組遵循GPL這個開源許可證規則,那麼則增加下面的:
MODULE_LICENSE("GPL");
好了,linux對這兩種許可證行為的模組開放的介面並不相同,本節的這個函式就是說明這個方法只對GPL的模組開放。
http://www.ruanyifeng.com/blog/2010/02/why_gpl_is_a_better_choice.html
__setup 和 early_param
unsigned int reset_devices;
EXPORT_SYMBOL(reset_devices);
static int __init set_reset_devices(char *str)
{
reset_devices = 1;
return 1;
}
__setup("reset_devices", set_reset_devices);
這段程式碼,首先需要理解__setup,這個函式就理解為:啟動時候如果有接收reset_devices引數,那麼就呼叫set_reset_devices方法。而詳細看了下set_reset_devices方法,裡面只是把reset_devices變數設定為1,但是呢,這個reset_devices變數又是一個給所有模組使用的變數。
所以這段程式碼能達到的功能是隻要啟動引數有包含reset_device,通過設定reset_devices通知給所有模組。
與__setup相對應的還有一個叫做early_param。這兩個巨集函式的功能一樣,區別就在於early_param定義的引數比__setup更早。
相關文章
- 集合原始碼分析[1]-Collection 原始碼分析原始碼
- linux原始碼分析Linux原始碼
- 介面1原始碼分析原始碼
- 原始碼分析axios(1)~原始碼分析、模擬axios的建立原始碼iOS
- 3.23 vchain原始碼分析1AI原始碼
- Netty Pipeline原始碼分析(1)Netty原始碼
- 原始碼分析系列1:HashMap原始碼分析(基於JDK1.8)原始碼HashMapJDK
- Linux下init程式原始碼分析Linux原始碼
- AFL二三事 -- 原始碼分析 1原始碼
- SpringMVC原始碼分析1:SpringMVC概述SpringMVC原始碼
- 【JDK】JDK原始碼分析-AbstractQueuedSynchronizer(1)JDK原始碼
- 3.21以太貓原始碼分析1原始碼
- rxjs 原始碼分析1-(fromEvent)JS原始碼
- newrelic python agent 原始碼分析-1Python原始碼
- EOS原始碼分析(1)安裝原始碼
- JDK 原始碼分析(1) Object類JDK原始碼Object
- k8s client-go原始碼分析 informer原始碼分析(1)-概要分析K8SclientGo原始碼ORM
- Riffa學習——Linux Driver原始碼分析Linux原始碼
- Java容器類框架分析(1)ArrayList原始碼分析Java框架原始碼
- 重拾RunLoop之原始碼分析1OOP原始碼
- 【原創】Linux虛擬化KVM-Qemu分析(三)之KVM原始碼(1)Linux原始碼
- iOS開發原始碼閱讀篇--FMDB原始碼分析1(FMResultSet)iOS原始碼
- SQLMAP原始碼分析Part1:流程篇SQL原始碼
- Retrofit原始碼分析三 原始碼分析原始碼
- Android 系統原始碼-1:Android 系統啟動流程原始碼分析Android原始碼
- [轉帖]Linux核心原始碼分析分享專題Linux原始碼
- Linux核心原始碼分析之set_arch (一)Linux原始碼
- Linux核心原始碼分析之setup_arch (四)Linux原始碼
- Linux核心原始碼分析之setup_arch (二)Linux原始碼
- Linux核心原始碼分析之setup_arch (三)Linux原始碼
- Linux程式排程邏輯與原始碼分析Linux原始碼
- 【JDK原始碼分析系列】ArrayBlockingQueue原始碼分析JDK原始碼BloC
- 集合原始碼分析[2]-AbstractList 原始碼分析原始碼
- 集合原始碼分析[3]-ArrayList 原始碼分析原始碼
- Android 原始碼分析之 AsyncTask 原始碼分析Android原始碼
- Guava 原始碼分析之 EventBus 原始碼分析Guava原始碼
- [原始碼分析] Facebook如何訓練超大模型---(1)原始碼大模型
- FFmpeg libswscale原始碼分析1-API介紹原始碼API
- Element原始碼分析系列1一Layout(佈局)原始碼