【聲明:著作權,歡迎轉載,請勿用於商業用途。 聯絡信箱:feixiaoxing @163.com】
記得我在讀書的時候,雖然老師也教過作業系統的課程,但是自己的理解卻不是很充分,實踐部分的內容就更少。對於課程中的內容,比如說中斷、互斥、線程、IO等概念常常也是一知半解,沒有什麼特別深刻的體會。等到畢業後,自己開始花錢買一些國外作者寫的書,認識上有了很大的改變,但是自己真正動手寫代碼、調試的部分還是太少。等到去年的時候,自己開始在pc上面模擬ucos系統的時候,對每一行代碼進行單步調試的時候,才真正從本質上理解了系統本身。
當然,我對很多電腦課程的認識,原來都是基本停留在書本上面。不管是電腦網路、編譯原理還是人機介面,書本上的知識點雖然大概也知道些,但是你要說理解得有多透徹卻說不上來。等到自己真正閱讀了lwip、lua和ftk的相關代碼,你才會大呼一聲,原來是這麼回事,好像也不是很複雜。所以,對於電腦的知識,要想把自己的認識提高一個層次的話,最好的方法就是實踐。
在國內,喜歡研究linux的人很多,但是大多數朋友對linux kenel的理解只是停留在書本上面、視頻上面以及ppt上面。真正自己動手做實驗、把每一行代碼都弄懂弄明白的朋友卻不是那麼多。其實,和以前相比,現在的linux版本更多、也更穩定,資源也特別豐富。就我個人認為,linux系統是學習電腦最好的系統。因為在這麼一個系統上面,沒有人幫你,很多的困惑都需要自己去解決,只有去克服一個一個痛點,你才能感受到自己確實實在進步。這種進步不是停留在學會了某種配置、安裝了某種軟體、熟悉了某種環境,而在於你對系統本身的認識更高了,看問題的角度發生改變了。
在書店裡面,介紹linux基本軟體開發的書特別多,但是卻有很少的書介紹如何在linux進行kernel的學習、編譯、調試,哪些調試工具比較合適等等。他們做的就是直接把答案告訴你,至於為什麼這樣設計,交代的內容卻很少。一方面這方面的需求比較少,另外一方面這些知識點有點難度,不易被大家接受。實際上,這裡大家存在一個誤區,現在的linux kernel開發其實不是那麼難,你所需要的其實就是一個pc、一根網線,這樣你就獲得了學習的全部資源。下面內容主要是介紹給大家如何學習linux kernel,特別是如何在實踐中學習。
(1)選擇一個合適linux發行版本,我自身選用的版本是CentOS 6,使用非常方便
(2)從www.kernel.org下載kernel代碼,學習如何編譯linux 核心,其實步驟也不複雜
a)解壓linux核心版本
b)cd linux目錄
c)cp /boot/config-2.6.32-220.el6.i686 .config
d) make menuconfig
e)儲存,直接exit退出
f)make bzImage
g) make modules
h) make modules_install
i) make install
(3) 重啟電腦,開機選用新的linux 核心。開始編寫hello.c檔案,產生模組,利用模組與linux核心功能進行互動,用dmesg -c查看列印
#include <linux/module.h>#include <linux/init.h>MODULE_LICENSE("GPL");MODULE_AUTHOR("feixiaoxing");MODULE_DESCRIPTION("This is just a hello module!\n");static int __init hello_init(void){ printk(KERN_EMERG "hello, init\n"); dump_stack(); return 0;}static void __exit hello_exit(void){ printk(KERN_EMERG "hello, exit\n");}module_init(hello_init);module_exit(hello_exit);
(4)安裝elfutils-devel,systemtap安裝包,用stap -v *.stp開始分析核心。你要做的就是插入調試驗,編寫指令檔,自由分析核心的代碼內容,
a)基礎列印
probe begin{ printf("hello begin!\n")}probe end{ printf("hello end!\n")}
b)定時列印
global numberprobe begin{ number = 0}probe timer.ms(5000){ number ++ printf ("%d\n", number)}probe end{ number = 0}
c)統計syscall調用
global syscallsfunction print_top () { cnt = 0 log ("SYSCALL\t\t\tCOUNT") foreach ([name] in syscalls-) { printf("%-20s %5d\n",name, syscalls[name]) if (cnt++ == 20) break } printf("--------------------------------------\n") delete syscalls}probe kernel.function("sys_*") { syscalls[probefunc()]++}# print top syscalls every 5 secondsprobe timer.ms(5000) { print_top ()}
d)統計schedule函數被調用的次數
global countprobe kernel.function("schedule"){ count ++}probe begin{ count = 0}probe end{ printf("count = %d\n", count);}
e)列印回調堆棧
global countprobe kernel.function("schedule").return{ if(!count) print_backtrace() count ++}probe begin{ count = 0}probe end{}
f)記錄一次進程切換
global countprobe begin{ count = 0}probe kernel.function("__switch_to"){ if(!count) { printf("from [%s] to [%s]\n", task_execname($prev_p), task_execname($next_p)) } exit()}probe end{}
更多關於systemtap的範例,可以參考《systemtap language reference》這本手冊。