精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

從微觀角度來看Linux內(nèi)核設(shè)計(jì)

Linux閱碼場 ? 來源:未知 ? 作者:李倩 ? 2018-11-15 16:29 ? 次閱讀

◆◆從微觀角度來看Linux內(nèi)核設(shè)計(jì)◆◆

余生皆歡喜

最近總結(jié)出來學(xué)習(xí)內(nèi)核有兩個(gè)大的角度,一種就是從宏觀角度來看,總的來說就是順著抽象,管理,操作來看,這種角度更多的是內(nèi)核中應(yīng)用層面的內(nèi)容,用來理解內(nèi)核中是怎么運(yùn)轉(zhuǎn)起來的。第二種就是從內(nèi)核的最細(xì)節(jié)部分出發(fā),深入到一個(gè)個(gè)具體的宏,看看內(nèi)核設(shè)計(jì)者在細(xì)節(jié)部分有著怎么樣的巧妙之處,這樣也有助于我們夯實(shí)C語言基礎(chǔ),也可以學(xué)習(xí)到GNU C的用法。

最近學(xué)習(xí)了如下的GNU C的內(nèi)容:

指定初始化

語句表達(dá)式

typeof關(guān)鍵字

內(nèi)核第一宏

我們來看看這些內(nèi)容是怎么設(shè)計(jì)的,GNU C就是打輔助的,專門為了OS而存在,(為什么全世界不統(tǒng)一使用GNU C呢?)它帶來了太多的方便,換句話說,它幫助內(nèi)核設(shè)計(jì)人員解決了很多內(nèi)核設(shè)計(jì)者在設(shè)計(jì)內(nèi)核時(shí)所遇到的問題,我這樣認(rèn)為,GNU C中每一條功能,就是內(nèi)核設(shè)計(jì)者在實(shí)際設(shè)計(jì)中遇到的問題。

這里再次分析總結(jié)gitbook中的兩個(gè)宏,一個(gè)是max/min宏,一個(gè)是內(nèi)核第一宏container_of。

max/min宏

內(nèi)核中的樣子:

這里的max宏可以讓我們學(xué)會(huì)語句表達(dá)式,typeof關(guān)鍵字;基礎(chǔ)方面可以鞏固運(yùn)算符優(yōu)先級(jí)。

這個(gè)宏是怎么得到的呢?

我們來寫一個(gè)宏,用來比較兩個(gè)變量的大小,我一定會(huì)這么寫:

那么我們來比較一下4!=4和2!=3,結(jié)果是錯(cuò)誤的,原因是運(yùn)算符優(yōu)先級(jí)出了問題。那么我們來解決,使用括號(hào)是最簡單的方法:

我們來運(yùn)行一條語句:printf("max = %d\n",3 + MAX(4,5));,結(jié)果是7,這里是因?yàn)?的運(yùn)算優(yōu)先級(jí)大于>了,換句話說,是因?yàn)橥獠康恼Z句,影響到了宏,那么我就把自己隔離起來:

再來運(yùn)行一下printf("max=%d\n",MAX(2++,3++));,輸出的會(huì)是4,但我們只想要比較2和3的值,這里是因?yàn)樽栽鲎詼p運(yùn)算符導(dǎo)致的問題,那么怎么解決呢?和交換兩個(gè)數(shù)字的想法一樣,通過一個(gè)中轉(zhuǎn)值來存放,就可以隔離影響了

這里就有一些內(nèi)核代碼中的味道了,注意一個(gè)細(xì)節(jié),這里的第四行沒有括號(hào)了,為什么?這里就是因?yàn)檎Z句表達(dá)式了,不存在上面的影響了。這里我們回顧一下代碼,再看看目前這個(gè)宏的第二三行,是int,也就是我們這個(gè)宏只能比較int類型的變量,而在內(nèi)核中需要比較大小的變量有很多,那么我們來提高一下:

這個(gè)宏就可以用來比較任意類型的變量了,再來看一下代碼,我們需要替換的變量有type,x,y三個(gè),如果有了typeof關(guān)鍵字,我們還可以減少一個(gè):

接著來,如果我們使用了一次宏,是MAX(i,j),其中i是int類型,j是float類型,這樣比較是可以的,但是在內(nèi)核的設(shè)計(jì)過程之中,很有可能有些地方會(huì)出現(xiàn)問題,所以還需要改造:

這就是究極形態(tài)了,我們添加了第四行的代碼,來看&_min1,它的意思是取_min1的地址,而&_min2的意思是取_min2的地址,我們也知道,這兩個(gè)地址肯定不可能是一樣的,那為什么還要這樣寫呢?這里就很巧妙了,當(dāng)兩個(gè)變量的類型不同時(shí),對應(yīng)的地址,也就是指針類型也不相同,比如一個(gè)是int類型,一個(gè)是char類型,那么指向他們的指針就是int *和char *,這兩個(gè)指針在比較的時(shí)候,就比較的是類型了。如果比較的類型不一樣,gcc會(huì)警告的。

我們來看這一系列改進(jìn),我相信內(nèi)核設(shè)計(jì)人員也想把代碼寫成# define MAX(x,y) x > y? x : y的樣子,但是現(xiàn)實(shí)是殘酷的,我們?yōu)榱舜a的健壯性,就必須這樣一步一步來改進(jìn),所以,內(nèi)核代碼看起來很復(fù)雜,又很巧妙,是因?yàn)槲覀冎苯涌吹降氖蔷繕O形態(tài)的代碼,它是向現(xiàn)實(shí)妥協(xié)了多次以后的產(chǎn)物,也就是健壯性+GNU C。但是,內(nèi)核設(shè)計(jì)者的初衷,或者說最初的想法和我們都是一樣的。

有內(nèi)核源碼在旁邊,鞏固基礎(chǔ)知識(shí)就不用像以前的學(xué)習(xí)模式了,可以在源碼中代入學(xué)習(xí),增添一份趣味性,并且可以很快理解。

在以后處理因?yàn)檫\(yùn)算符而導(dǎo)致的問題的時(shí)候,使用括號(hào)是最方便的,內(nèi)核就這么干了。

在寫程序的時(shí)候,要巧用中轉(zhuǎn)變量,雖然只是簡單的存入另一個(gè)變量之中,但是代碼的健壯性提高了很多。

兩個(gè)地址在進(jìn)行比較的時(shí)候,我們可以得知這兩個(gè)指針類型是否一致。

內(nèi)核第一宏

gitchat中把container_of宏叫做內(nèi)核第一宏,我也很喜歡這個(gè)稱號(hào),因?yàn)閷W(xué)內(nèi)核兩個(gè)月里見這個(gè)宏的次數(shù)太多了。在陳老師講list.h的時(shí)候,就學(xué)習(xí)過這個(gè)宏,但是并沒有完完全全地剖析開。

高能預(yù)警:

這個(gè)宏的作用我們已經(jīng)很清楚了,根據(jù)結(jié)構(gòu)體中某一成員的地址,就可以獲得這個(gè)結(jié)構(gòu)體的首地址,再說的明白一點(diǎn),假如你是內(nèi)核設(shè)計(jì)人員,前面也說道了,我們已經(jīng)對數(shù)據(jù)進(jìn)行了多次封裝,我們一定會(huì)遇到這種情況:傳給某個(gè)函數(shù)的參數(shù)是某個(gè)結(jié)構(gòu)體成員變量,但是我們在這個(gè)函數(shù)中還想使用這個(gè)結(jié)構(gòu)體的其它成員變量,這個(gè)時(shí)候就需要想辦法,于是才有了我們現(xiàn)在看到的這個(gè)內(nèi)核第一宏。

它的三個(gè)參數(shù)是:

ptr:此結(jié)構(gòu)體內(nèi)成員member的地址

type:此結(jié)構(gòu)體類型

member:此結(jié)構(gòu)體內(nèi)的成員

我們直接看代碼,這個(gè)宏的最后的值,就是最后一條語句,(type *)( (char *)__mptr - offsetof(type,member) );}),這條語句也是這個(gè)宏的中心思想拿結(jié)構(gòu)體成員的地址減去此成員的偏移,這里也體現(xiàn)了指針做減法是很有意義的。成員的地址好說,我們直接傳進(jìn)來了,偏移是通過offsetof來實(shí)現(xiàn)的,來看看這個(gè)offsetof:將0強(qiáng)制類型轉(zhuǎn)換成這個(gè)結(jié)構(gòu)體的指針類型,然后訪問這個(gè)成員,加上&得到它的偏移,返回。這里要注意一下,那就是為什么只通過TYPE和MEMBER就可以得到偏移,我一開始認(rèn)為的是內(nèi)核中這個(gè)類型的結(jié)構(gòu)體多了,到底用的是哪一個(gè)結(jié)構(gòu)體來得到的,最后發(fā)現(xiàn),并沒有關(guān)系,因?yàn)槲覀冃枰氖亲止?jié)數(shù),與實(shí)際這個(gè)字段賦什么樣的值并沒有關(guān)系,因?yàn)樗羞@個(gè)類型的結(jié)構(gòu)體中,各成員的字節(jié)大小是一樣的。

再來看(char *)__mptr,這個(gè)通過第四行代碼可以很容易得出它是成員的地址,為什么要強(qiáng)制轉(zhuǎn)換成char *呢?轉(zhuǎn)換成int *不行嗎?這里又可以學(xué)習(xí)一下C指針的基礎(chǔ)知識(shí),通過代碼可以很容易知道有什么區(qū)別:

打印出來的值,p(int *)類型,增加了4字節(jié),而q(char *)增加了1字節(jié),回到宏中,我們的偏移是按照字節(jié)來算的,所以不能使用(int *),必須使用(char *)。在最后,再次強(qiáng)制類型轉(zhuǎn)換成指向這個(gè)結(jié)構(gòu)體的指針類型。

回過頭來看第四行代碼,const typeof( ((type *)0)->member ) *__mptr = (ptr);,這里和max宏之中類似,使用了中轉(zhuǎn)變量來存放,這里為什么要使用中轉(zhuǎn)變量?max宏中是為了防止自增自減的影響(當(dāng)然只是原因之一了),但我們在使用的時(shí)候總不至于發(fā)過來成員的地址再加一個(gè)++運(yùn)算符吧。我們可以從const的用法來思考,const int * p //p可變,p指向的內(nèi)容不可變,所以,使用了const,我們就可以保證ptr指向的內(nèi)容在這里只是可讀的,這也許就是為什么使用中轉(zhuǎn)變量的原因,為了防止我們通過指針改變了原有的成員的值,畢竟指針雖然強(qiáng)大,但也是很危險(xiǎn)的,所以,這里的中轉(zhuǎn)要配合const來使用。既然是中轉(zhuǎn),那么類型就必須要求一致了,所以我們要得到和這個(gè)成員一致的類型,就通過typeof來得到了,將0強(qiáng)制類型轉(zhuǎn)換成這個(gè)這個(gè)結(jié)構(gòu)體的指針類型,然后訪問這個(gè)變量,(注意仔細(xì)看代碼,這里的代碼和offsetof非常類似)這里沒有使用&,所以只是訪問到變量了,沒有得到偏移。另外根據(jù)const的用法,第四行的代碼也可以寫成typeof( ((type *)0)->member ) const *__mptr = (ptr);也就是把const放到后面。

我們再來注意一個(gè)細(xì)節(jié),就是offsetof里的size_t,這個(gè)是什么,這里在敲代碼的過程中偶然學(xué)到一個(gè)小技巧,就是這個(gè)size_t絕對是封裝,就是C語言中那幾種變量類型,我們可以typedef int size_t;然后運(yùn)行,gcc就會(huì)報(bào)錯(cuò),并且會(huì)給你顯示:以前已經(jīng)定義過:typedef __SIZE_TYPE__ size_t,并且會(huì)指定這個(gè)值在哪個(gè)文件,我們就可以知道它的真面目了。換句話說,gcc這么強(qiáng)大,我們當(dāng)然可以把它當(dāng)做一個(gè)學(xué)習(xí)工具來使用。

另外還可以通過sublime,可以很快找到它的真面目(3.10版本):

最后,為了更深入理解這些知識(shí)的使用方法,還是需要自己動(dòng)手來敲代碼的,尤其是內(nèi)核第一宏,將代碼寫到用戶態(tài)下,然后瘋狂改造,這樣才會(huì)真正理解這個(gè)宏。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11227

    瀏覽量

    208924
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7598

    瀏覽量

    136186
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4747

    瀏覽量

    68349

原文標(biāo)題:趙晨雨: 從微觀角度來看linux內(nèi)核設(shè)計(jì)

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Linux內(nèi)核data段和bss段的區(qū)別

    進(jìn)程的角度Linux內(nèi)核是采用虛擬地址空間的,如下兩張圖所示,分別為32位、64位系統(tǒng)下進(jìn)程地址空間的大概布局。
    發(fā)表于 10-13 17:07 ?8848次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>data段和bss段的區(qū)別

    Linux內(nèi)核中系統(tǒng)調(diào)用詳解

    Linux內(nèi)核中設(shè)置了一組用于實(shí)現(xiàn)各種系統(tǒng)功能的子程序,稱為系統(tǒng)調(diào)用。用戶可以通過系統(tǒng)調(diào)用命令在自己的應(yīng)用程序中調(diào)用它們。某種角度來看,系
    發(fā)表于 08-23 10:37 ?763次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>中系統(tǒng)調(diào)用詳解

    Linux內(nèi)核教程

    本章學(xué)習(xí)目標(biāo)掌握LINUX內(nèi)核版本的含義理解并掌握進(jìn)程的概念掌握管道的概念及實(shí)現(xiàn)了解內(nèi)核的數(shù)據(jù)結(jié)構(gòu)了解LINUX內(nèi)核的算法掌握
    發(fā)表于 04-10 16:59 ?0次下載

    linux內(nèi)核啟動(dòng)流程

    Linux的啟動(dòng)代碼真的挺大,匯編到C,Makefile到LDS文件,需要理解的東西很多。畢竟Linux內(nèi)核是由很多人,花費(fèi)了巨大的時(shí)間
    發(fā)表于 11-14 16:19 ?4339次閱讀
    <b class='flag-5'>linux</b><b class='flag-5'>內(nèi)核</b>啟動(dòng)流程

    Linux 內(nèi)核才是真正的規(guī)則改變者

    Linux 內(nèi)核被稱為創(chuàng)新,但它又被稱為現(xiàn)代計(jì)算中最大的奇跡,一個(gè)微觀世界中的龐然大物。
    發(fā)表于 09-28 01:31 ?721次閱讀

    Linux內(nèi)核架構(gòu)--基本概念

    首先,Linux整體的架構(gòu)如圖: 再來看Linux內(nèi)核架構(gòu), 內(nèi)核由五個(gè)主要子系統(tǒng)組成: Process Scheduler : 進(jìn)程調(diào)度(
    發(fā)表于 05-20 09:28 ?725次閱讀

    linux內(nèi)核是什么_linux內(nèi)核學(xué)習(xí)路線

    Linux內(nèi)核是一個(gè)操作系統(tǒng)(OS)內(nèi)核,本質(zhì)上定義為類Unix。它用于不同的操作系統(tǒng),主要是以不同的Linux發(fā)行版的形式。Linux
    發(fā)表于 09-16 15:49 ?2614次閱讀

    linux內(nèi)核參數(shù)設(shè)置_linux內(nèi)核的功能有哪些

    本文主要闡述了linux內(nèi)核參數(shù)設(shè)置及linux內(nèi)核的功能。
    發(fā)表于 09-17 14:40 ?1362次閱讀
    <b class='flag-5'>linux</b><b class='flag-5'>內(nèi)核</b>參數(shù)設(shè)置_<b class='flag-5'>linux</b><b class='flag-5'>內(nèi)核</b>的功能有哪些

    最硬核的Linux內(nèi)核文章

    來源 :頭條號(hào)@Linux學(xué)習(xí)教程,冰凌塊兒 01 前言 本文主要講解什么是Linux內(nèi)核,以及通過多張圖片展示Linux內(nèi)核的作用與功能,
    的頭像 發(fā)表于 10-19 17:46 ?2096次閱讀
    最硬核的<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>文章

    快速理解什么是Linux內(nèi)核以及Linux內(nèi)核的內(nèi)容

    01 前言 本文主要講解什么是Linux內(nèi)核,以及通過多張圖片展示Linux內(nèi)核的作用與功能,以便于讀者能快速理解什么是Linux
    的頭像 發(fā)表于 10-21 12:02 ?4258次閱讀
    快速理解什么是<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>以及<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>的內(nèi)容

    如何使用Linux內(nèi)核實(shí)現(xiàn)USB驅(qū)動(dòng)程序框架

    Linux內(nèi)核提供了完整的USB驅(qū)動(dòng)程序框架。USB總線采用樹形結(jié)構(gòu),在一條總線上只能有唯一的主機(jī)設(shè)備。 Linux內(nèi)核主機(jī)和設(shè)備兩個(gè)
    發(fā)表于 11-06 17:59 ?20次下載
    如何使用<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>實(shí)現(xiàn)USB驅(qū)動(dòng)程序框架

    Linux環(huán)境編程:應(yīng)用到內(nèi)核

    Linux環(huán)境編程:應(yīng)用到內(nèi)核資料下載。
    發(fā)表于 06-01 14:51 ?18次下載

    軟件角度分析linux內(nèi)核USB子系統(tǒng)的熱插拔過程

    本文軟件角度分析linux內(nèi)核USB子系統(tǒng)的熱插拔過程,以實(shí)際分析思路和過程行文,基于linux內(nèi)核
    的頭像 發(fā)表于 01-15 09:28 ?5418次閱讀

    linux內(nèi)核源代碼詳解

     在安裝好的Linux系統(tǒng)中,內(nèi)核的源代碼位于/ust/src/linux.如果是GNU網(wǎng)站下載的Linux
    發(fā)表于 09-06 17:01 ?4次下載

    C++在Linux內(nèi)核開發(fā)中爭議到成熟

    Linux 內(nèi)核郵件列表中一篇已有六年歷史的老帖近日再次引發(fā)激烈討論 —— 主題是建議將 Linux 內(nèi)核的開發(fā)語言 C 轉(zhuǎn)換為更現(xiàn)代的
    的頭像 發(fā)表于 01-31 14:11 ?588次閱讀
    C++在<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>開發(fā)中<b class='flag-5'>從</b>爭議到成熟