中文字幕 另类精品,亚洲欧美一区二区蜜桃,日本在线精品视频免费,孩交精品乱子片免费

<sup id="3hn2b"></sup>

    1. <sub id="3hn2b"><ol id="3hn2b"></ol></sub><legend id="3hn2b"></legend>

      1. <xmp id="3hn2b"></xmp>

      2. 新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > 深度介紹:Linux內(nèi)核是如何工作的

        深度介紹:Linux內(nèi)核是如何工作的

        作者: 時間:2017-06-06 來源:網(wǎng)絡 收藏
          本文發(fā)表于 Format magazine雜志,作者從技術深度上解釋了 Kernel是如何工作的。相信對開發(fā)者來說有不小的幫助。

          牛津字典中對一詞的定義是:較軟的、通常是一個堅果可食用的部分。當然還有第二種定義:某個東西核心或者最重要的部分。對Linux來說,它的Kernel無疑屬于第二種解釋。讓我們來看看這個重要的東西是如何工作的,先從一點理論說起。

          廣義地來說就是一個軟件,它在硬件和運行在計算機上的應用程序之間提供了一個層。嚴格點從計算機科學的角度來說,Linux中的Kernel指的是Linus Torvalds在90年代初期寫的那點代碼。

          所有的你在Linux各版本中看到的其他東西--Bash shell、KDE窗口管理器、web瀏覽器、X服務器、Tux Racer以及所有的其他,都不過是運行在Linux上的應用而已,而不是操作系統(tǒng)自身的一部分。為了給大家一個更加直觀的感覺,我來舉個例子,比如 RHEL5的安裝大概要占據(jù)2.5GB的硬盤空間(具體多大當然視你的選擇安裝來定),在這其中,以及它的各個模塊組件,只有47MB,所占比例約為2%。

          在kernel內(nèi)部

          那么kernel到底是如何工作的呢?如下面的圖表。Kernel通過許多的進入端口也就是我們從技術角度所說的系統(tǒng)調(diào)用,來使得運行在它上面的應用程序可用。Kernel使用的系統(tǒng)調(diào)用比如讀和寫來提供你硬件的抽象(abstraction)。

        本文引用地址:http://www.antipu.com.cn/article/201706/349392.htm  從程序員的視角來看,這些看起來只是普通的功能調(diào)用,然而實際上系統(tǒng)調(diào)用在處理器的操作模式上,從用戶空間到Kernel空間有一個明顯的切換。同時,系統(tǒng)調(diào)用提供了一個Linux虛擬機,可以被認為是對硬件的抽象。

          Kernel提供的更明顯的抽象之一是文件系統(tǒng)。舉例來說,這里有一段短的程序是用C寫的,它打開了一個文件并將內(nèi)容拷貝到標準的輸出:

        #include fcntl.h>
        int main()
        {
        int fd, count; char buf[1000];
        fd=open(mydata, O_RDONLY);
        count = read(fd, buf, 1000);
        write(1, buf, count);
        close(fd);
        }

          在這里,你可以看到四個系統(tǒng)調(diào)用的例子:打開、讀、寫和關閉。不談這段程序語法的細節(jié),重點是:通過這些系統(tǒng)調(diào)用Linux Kernel提供了一個文件的錯覺,而實際上它不過是一堆數(shù)據(jù)有了個名字,這樣一來你就不必去與硬件底層的堆棧、分區(qū)、頭和指針、分區(qū)等交涉了,而是直接以例子中的方式與硬件交流,這也就是我們所說的抽象(abstraction),將底層的東西以更易懂的方式表達出來。


          臺前幕后

          系統(tǒng)文件是Kernel提供的較為明顯的一種抽象。還有一些特性不是這么的明顯,比如進程調(diào)度。任何一個時間,都可能有好幾個進程或者程序等待著運行。 Kernel的時間調(diào)度給每個進程分配CPU時間,所以就一段時間內(nèi)來說,我們會有種錯覺:電腦同一時間運行好幾個程序。這是另外一個C程序:

        #include stdlib.h>
        main()
        {
        if (fork()) {
        write(1, Parentn, 7);
        wait(0);
        exit(0);
        }
        else {
        write(1, Childn, 6);
        exit(0);
        }
        }
          在這個程序中創(chuàng)建了一個新進程,而原來的進程(父進程)和新進程(子進程)都編寫了標準輸出然后結束。注意系統(tǒng)調(diào)用fork(), exit() 以及 wait()執(zhí)行程序的創(chuàng)建、結束和各自同步。這是進程管理和調(diào)度中最典型的簡單調(diào)用。

          Kernel還有一個更加不易見到的功能,連程序員都不易察覺,那就是存儲管理。每個程序運行得都好像它有個自己的地址空間來調(diào)用一樣,實際上它跟其他進程一樣共享計算機的物理存儲,如果系統(tǒng)運行的存儲過低,它的地址空間甚至會被磁盤的交互區(qū)暫時寄用。存儲管理的另外一個方面是防止一個進程訪問其他進程的地址空間--對于多進程操作系統(tǒng)來說這是很必要的一個防范措施。

          Kernel同樣還配置網(wǎng)絡鏈接協(xié)議比如IP、TCP和UDP等,它們在網(wǎng)絡上提供機器對機器(machine-to-machine)和進程對進程(ess-to-ess)的通信。這里又會造成一種假象,即TCP在兩個進程之間提供了一個固定連接--就好像連接兩個電話的銅線一樣,實際中卻并沒有固定的連接,特殊的引用協(xié)議比如FTP、DNS和HTTP是通過用戶級程序來實施的,而并非Kernel的一部分。

          Linux(像之前的)在安全方面口碑很好,這是因為Kernel跟蹤記錄了每個運行進程的user ID和group ID,每次當一個應用企圖訪問資源(比如打開一個文件來寫入)的時候,Kernel就會核對文件上的訪問許可然后做出允許/禁止的命令。這種訪問控制模式最終對整個Linux系統(tǒng)的安全作用很大。

          Kernel還提供了一大套模塊的集合,其功能包括如何處理與硬件設備交流的諸多細節(jié)、如何從磁盤讀取一個分區(qū)、如果從網(wǎng)絡接口卡獲取數(shù)據(jù)包等。有時我們稱這些為設備驅(qū)動。

          模塊化的Kernel

          現(xiàn)在我們隊Kernel是做什么的已經(jīng)有了一些了解,讓我們再來簡單看下它的物理組成。早期版本的Linux Kernel是整體式的,也就是說所有的部件都靜態(tài)地連接成一個(很大的)執(zhí)行文件。

          相比較而言,現(xiàn)在的Linux Kernel是模塊化的:許多功能包含在模塊內(nèi),然后動態(tài)地載入kernel中。這使得kernel的很小,而且在運行kernel時可以不必reboot就能載入和替代模塊。

          Kernel的在boot time時從位于/boot 目錄的一個文件加載進存儲中,通常這個/boot 目錄會被叫做KERNELVERSION,KERNELVERSION與kernel版本有關。(如果你想知道你的kernel版本是什么,運行命令行顯示系統(tǒng)信息-r。)kernel的模塊位于目錄/lib/modules/KERNELVERSION之下,所有的組件都會在kernel安裝時被拷貝。


          管理模塊

          大部分情況下,Linux管理它的模塊不需要你的幫忙,但是如果必要的時候有命令行可以來手動檢查和管理模塊。比如,為了查清楚當前到底哪個模塊在載入kernel。這里有一個輸出的例子:

        # lsmod
        pcspkr 4224 0
        hci_usb 18204 2
        psmouse 38920 0
        bluetooth 55908 7 rfcomm,l2cap,hci_usb
        yenta_socket 27532 5
        rsrc_nonstatic 14080 1 yenta_socket
        isofs 36284 0

          輸出的內(nèi)容包括:模塊的名字、大小、使用次數(shù)和依賴于它的模塊列表。使用次數(shù)對防止卸載當前活躍的模塊非常總要。Linux只允許使用次數(shù)為零的模塊被移除。

          你可以使用modprobe來手動加載和卸載模塊,(還有兩個命令行叫做insmod和rmmod,但modprobe更易于使用因為它自動移除了模塊依賴)。比如lsmod的輸出在我們的電腦上顯示了一個名叫isofs的卸載模塊,它的使用次數(shù)是零而且沒有依賴模塊,(isofs是一個模塊,它支持CD 上使用的ISO系統(tǒng)文件格式)這種情況下,kernel會允許我們卸載模塊:

        # modprobe -r isofs

          現(xiàn)在,isofs不再顯示在Ismod的輸出中,kernel由此節(jié)省了36,284字節(jié)的存儲。如果你放入CD并且讓它自動安裝,kernel將自動重新載入isofs模塊,而且isofs的使用次數(shù)增加到1次。如果這時候你還試圖移除模塊,就不會成功了因為它正在被使用:

        # modprobe -r isofs
        FATAL: Module isofs is in use.

          Lsmod只是列出了當前被載入的模塊,modprobe則將列出所有可用的模塊,它實際上輸出了/lib/modules/KERNELVERSION目錄下所有的模塊,名單會很長!

          實際上,使用modprobe來手動加載一個模塊并不常見,但確實可以通過modprobe命令行來對模塊設置參數(shù),例如:

        # modprobe usbcore blinkenlights=1

          我們并不是在創(chuàng)建blinkenlights,而是usbcore模塊的實參數(shù)。
          那么如何知道一個模塊會接受什么參數(shù)呢?一個比較好的方法是使用modinfo命令,它列出了關于模塊的種種信息。這里有一個關于模塊snd-hda-intel的例子

        # modinfo snd-hda-intel
        filename: /lib/modules/2.6.20-16-generic/kernel/sound/pci/hda/snd-hda-intel.ko
        description: Intel HDA driver
        license: GPL
        srcversion: A3552B2DF3A932D88FFC00C
        alias: pci:v000010DEd0000055Dsv*sd*bc*sc*i*
        alias: pci:v000010DEd0000055Csv*sd*bc*sc*i*
        depends: snd-pcm,snd-page-alloc,snd-hda-codec,snd
        vermagic: 2.6.20-16-generic SMP mod_unload 586
        parm: index:Index value for Intel HD audio interface. (int)
        parm: id:ID string for Intel HD audio interface. (charp)
        parm: model:Use the given board model. (charp)
        parm: position_fix:Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size). (int)
        parm: probe_mask:Bitmask to probe codecs (default = -1). (int)
        parm: single_cmd:Use single command to communicate with codecs (for debugging only). (bool)
        parm: enable_msi:Enable Message Signaled Interrupt (MSI) (int)
        parm: enable:bool

          對我們來說比較有興趣的以parm開頭的那些部分:顯示了模塊所接受的參數(shù)。這些描述都比較簡明,如果想要更多的信息,那就安裝kernel的源代碼,在類似于/usr/src/KERNELVERSION/Documentation的目錄下你會找到。

          里面會有一些有趣的東西,比如文件/usr/src/KERNELVERSION/Documentation/sound/alsa/ALSA- Configuration.txt描述的是被許多ALSA聲音模塊承認的參數(shù);/usr/src/KERNELVERSION /Documentation/kernel-parameters.txt這個文件也很有用。

          前幾天在Ubuntu論壇有一個例子,說的是如何將參數(shù)傳遞到一個模塊(詳見https://help.ubuntu.com/community /HdaIntelSoundHowto)。實際上問題的關鍵是snd-hda-intel參數(shù)在正確驅(qū)動聲音硬件時需要一點操作,而且在boot time加載時會中止。解決方法的一部分是將probe_mask=1選項賦給模塊,如果你是手動加載模塊,你需要輸入:

        # modprobe snd-hda-intel probe_mask=1

          更有可能,你在文件/etc/modprobe.conf中放置這樣類似的一行:options snd-hda-intel probe_mask=1

          這告訴modprobe每次在加載snd-hda-intel模塊時包含probe_mask=1選項?,F(xiàn)在的有些Linux版本將這一信息分離進/etc/modprobe.d下的不同文件中了,而不是放入modprobe.conf中。


          /系統(tǒng)文件

          Linux kernel同樣通過/proc系統(tǒng)文件來展示了許多細節(jié)。為了說明/proc,我們首先需要擴展我們對于文件的理解。除了認為文件就是存儲在硬盤或者 CD或者存儲空間上的持久信息之外,我們還應當把它理解為任何可以通過傳統(tǒng)系統(tǒng)調(diào)用如:打開、讀、寫、關閉等訪問的信息,當然它也可以被常見的程序訪問。

          /proc之下的文件完全是kernel虛擬的一個部分,給我們一個視角可以看到kernel內(nèi)部的數(shù)據(jù)結構。實際上,許多Linux的報告工具均能夠很好地呈現(xiàn)在/proc下的文件中尋到的格式化版本的信息。比如,一列/proc/modules將展示一列當前加載的模塊。

          同樣的,/proc/meminfo提供了關于虛擬存儲系統(tǒng)當前狀態(tài)的更多細節(jié)信息,而類如vmstat的工具則是以一種更加可理解的方式提供了相同的一些信息;/proc/net/arp顯示了系統(tǒng)ARP cache的當前內(nèi)容,從命令行來說,arp -a顯示的也是相同的信息。

          尤其有意思的是/proc/sys下的文件。/proc/sys/net/ipv4/ip_forward下的設置告訴我們kernel是否將轉(zhuǎn)發(fā)IP數(shù)據(jù)包,也就是說是否扮演網(wǎng)關的作用?,F(xiàn)在,kernel告訴我們這是關閉的:

        # cat /proc/sys/net/ipv4/ip_forward
        0

          當你發(fā)現(xiàn)你可以對這些文件寫入的時候,你會覺得更加有意思。繼續(xù)舉例來說:

        # echo 1 > /proc/sys/net/ipv4/ip_forward

          將在運行的kernel中打開IP 轉(zhuǎn)發(fā)(IP forwarding)

          除了使用cat和echo來檢查和更正/proc/sys下的設置以外,你也可以使用sysctl命令:

        # sysctl net.ipv4.ip_forward
        net.ipv4.ip_forward = 0

        這等同于:
        # cat /proc/sys/net/ipv4/ip_forward
        0

        也等同于:
        # sysctl -w net.ipv4.ip_forward=1
        net.ipv4.ip_forward = 1

        還等同于:
        # echo 1 > /proc/sys/net/ipv4/ip_forward

          需要注意的是,以這種方式你所做的設置改變只能影響當前運行的kernel的,當reboot的時候就不再有效。如果想讓設置永久有效,將它們放置在 /etc/sysctl.conf文件中。在boot time時,sysctl將自動重新確定它在此文件下找到的任何設置。

        /etc/sysctl.conf下的代碼行大概是這樣的:net.ipv4.ip_forward=1
          性能調(diào)優(yōu)(performance tuning)

          有這樣一個說法:/proc/sys下可寫入的參數(shù)孕育了整個Linux性能調(diào)優(yōu)的亞文化。我個人覺得這種說法有點過夸,但這里會有幾個你確實很想一試的例子:Oracle 10g的安裝說明( www.oracle.com/technology/obe/obe10gdb/install/linuxpreinst /linuxpreinst.htm)要求你設置一組參數(shù),包括:kernel.shmmax=2147483648 這將公用存儲器的大小設置為2GB。(公用存儲器是處理期內(nèi)的通信機制,允許存儲單元在多個進程的地址空間內(nèi)同時可用)

          IBM 'Redpaper'在Linux性能和調(diào)優(yōu)方面的說明(www.redbooks.ibm.com/abstracts/redp4285.html)在調(diào)教/proc/sys下的參數(shù)方面給出了不少建議,包括:vm.swappiness=100 這個參數(shù)控制著存儲頁如何被交換到磁盤。

          一些參數(shù)可以被設置從而提高安全性,如net.ipv4.icmp_echo_ignore_broadcasts=1 它告訴kernel不必響應ICMP請求,從而使得你的網(wǎng)絡免受類如Smurf攻擊之類的拒絕服務器(denial-of-service)型攻擊。
        net.ipv4.conf.all.rp_filter=1 則是告訴kernel加強入站過濾(ingress filtering)和出站過濾(egress filtering)

          那么有沒有一個說明能涵蓋這所有的參數(shù)?好吧,這有一行命令:# sysctl -a 它將展示所有的參數(shù)名字和當前值。列表很長,但是你無法知道這些參數(shù)是做什么的。另外比較有用的參考是Red Hat Enterprise Linux Reference Guide,對此有整章節(jié)的描述,你可以從www.redhat.com/docs/manuals/enterprise 上下載。


        評論


        相關推薦

        技術專區(qū)

        關閉