第一篇:關(guān)于分析今天保定百度百度愛(ài)問(wèn)愛(ài)第3章C54x DSP系統(tǒng)硬件結(jié)構(gòu)DSP芯片
關(guān)于分析今天保定百度百度愛(ài)問(wèn)愛(ài)第3章C54x DSP系統(tǒng)硬件結(jié)構(gòu)DSP芯片.txt
-你腳踏倆只船,你劃得真漂亮。-每個(gè)說(shuō)不想戀愛(ài)的人 心里都裝著一個(gè)不可能的人。我心疼每一個(gè)不快樂(lè)卻依然在笑的孩子。(有沒(méi)有那么一個(gè)人,看透我在隱身,知道我在等人。的的的地方地方愛(ài)的規(guī)格愛(ài)你啊好文章第3章 C54x DSP系統(tǒng)硬件結(jié)構(gòu)
DSP芯片是一種特殊結(jié)構(gòu)的微處理器,為了快速地實(shí)現(xiàn)數(shù)字信號(hào)處理運(yùn)算,采用了流水線指令執(zhí)行結(jié)構(gòu)和相應(yīng)的并行處理結(jié)構(gòu),可在一個(gè)周期內(nèi)對(duì)數(shù)據(jù)進(jìn)行高速的算術(shù)運(yùn)算和邏輯運(yùn)算。本章主要介紹C54x DSP芯片的硬件結(jié)構(gòu),重點(diǎn)對(duì)芯片的引腳功能、CPU結(jié)構(gòu)、內(nèi)部存儲(chǔ)器、片內(nèi)外設(shè)電路、系統(tǒng)控制以及內(nèi)、外部總線進(jìn)行討論。3.1 C54x DSP的基本架構(gòu) TMS320 C54x DSP(簡(jiǎn)稱(chēng)C54x)是TI公司為實(shí)現(xiàn)低功耗、高速實(shí)時(shí)信號(hào)處理而專(zhuān)門(mén)設(shè)計(jì)的16位定點(diǎn)數(shù)字信號(hào)處理器。其內(nèi)核包含在第1章已經(jīng)討論過(guò)的哈佛結(jié)構(gòu)和高級(jí)算術(shù)特點(diǎn)中。另外,C54x還具有多總線結(jié)構(gòu)以及強(qiáng)大的片上外設(shè),具有高度的操作靈活性和運(yùn)行速度,適應(yīng)遠(yuǎn)程通信等實(shí)時(shí)嵌入式應(yīng)用的需要,現(xiàn)已廣泛地應(yīng)用于無(wú)線通信系統(tǒng)中。3.1.1 C54x DSP的基本結(jié)構(gòu)圖
一塊DSP芯片上集成CPU、片內(nèi)存儲(chǔ)器、外圍電路、總線以及外部總線接口。圖3-1所示為T(mén)MS320C54x基本結(jié)構(gòu)框圖,它包含了主要模塊和總線結(jié)構(gòu)。圖3-2所示為T(mén)MS320C54x功能結(jié)構(gòu)圖。與傳統(tǒng)微處理器相比較,DSP最顯著的結(jié)構(gòu)特點(diǎn)是具有高效存取數(shù)據(jù)、單周期乘法器和零開(kāi)銷(xiāo)硬件循環(huán)等。3.1.2 C54x DSP的主要特征
1.具有快速處理性能的CPU部分 CPU是DSP芯片中的核心部分,CPU內(nèi)的硬件構(gòu)成決定其指令系統(tǒng)的性能。采用了流水線指令執(zhí)行結(jié)構(gòu)和相應(yīng)的并行處理結(jié)構(gòu),可在一個(gè)周期內(nèi)對(duì)數(shù)據(jù)進(jìn)行高速的算術(shù)運(yùn)算和邏輯運(yùn)算,TMS320C54x的CPU包括以下幾部分:
(1)先進(jìn)的多總線結(jié)構(gòu),包括1條程序總線、3條數(shù)據(jù)總線、4條地址總線和外設(shè)總線;(2)40位算術(shù)邏輯單元(ALU),包括1個(gè)40位的桶形移位寄存器和2個(gè)獨(dú)立的40位累加器;
(3)17×17的并行乘法器,并與1個(gè)40位的專(zhuān)用加法器配合,用于非流水線的單周期乘/累加操作;DSP芯片技術(shù)及工程實(shí)例第3章 C54x DSP系統(tǒng)硬件結(jié)構(gòu)圖3-1 TMS320C54x基本結(jié)構(gòu)框圖
圖3-2 TMS320C54x功能結(jié)構(gòu)圖
(4)比較、選擇和存儲(chǔ)單元,用于維特比運(yùn)算中的加/比較選擇;(5)指數(shù)編碼器,可以在單周期內(nèi)計(jì)算40位累加器的指數(shù)值;
(6)2個(gè)地址生成器,包括8個(gè)輔助寄存器和2個(gè)輔助寄存器算術(shù)單元;(7)雙內(nèi)核結(jié)構(gòu)(只適用于C5420).2.具有哈佛結(jié)構(gòu)的存儲(chǔ)器系統(tǒng)
(1)具有獨(dú)立的程序存儲(chǔ)器和數(shù)據(jù)存儲(chǔ)器,可同時(shí)訪問(wèn),使許多處理運(yùn)算比傳統(tǒng)的馮·諾依曼結(jié)構(gòu)有效得多。
(2)具有192K字可尋址存儲(chǔ)空間,包括片內(nèi)、外64K字程序存儲(chǔ)空間,片內(nèi)、外64K字?jǐn)?shù)字存儲(chǔ)空間和片外64K字的I/O空間。其中一些型號(hào)DSP的程序存儲(chǔ)器空間可擴(kuò)展至8M字,例如TMS320C548、TMS320C549、TMS320C5402、TMS320C5410和TMS320C5420.(3)提供一定容量的片內(nèi)存儲(chǔ)器,片內(nèi)存儲(chǔ)器配置因型而異,包括片內(nèi)ROM和RAM,通過(guò)內(nèi)部多總線,CPU可以同時(shí)、快速地訪問(wèn)它們,以實(shí)現(xiàn)并行處理。但對(duì)于外部存儲(chǔ)器,DSP提供了外部接口,它與內(nèi)部多總線結(jié)構(gòu)復(fù)接,但外部只有一組I/O接口線,所以不能在單周期內(nèi)并行實(shí)現(xiàn)讀寫(xiě)操作。3.片內(nèi)外設(shè)和專(zhuān)用電路
除了DSP內(nèi)核外,DSP芯片上還需配置一些外設(shè)專(zhuān)用器件。這些器件可以與DSP內(nèi)核平行操作,只占用很小的內(nèi)核指令周期,依靠這些器件無(wú)縫出入DSP處理內(nèi)核的能力,可大大提高DSP處理數(shù)據(jù)的能力。TMS320C54x的片內(nèi)外設(shè)和專(zhuān)用電路采用模塊化的結(jié)構(gòu)設(shè)計(jì),常見(jiàn)的外設(shè)包括以下幾種。
(1)可編程軟件等待狀態(tài)發(fā)生器。(2)可編程分區(qū)轉(zhuǎn)換邏輯電路。
(3)可采用內(nèi)部振蕩器或外部時(shí)鐘源的片內(nèi)鎖相環(huán)(PLL)時(shí)鐘發(fā)生器。
(4)外部總線接口可以禁止或允許外部數(shù)據(jù)總線、地址總線和控制線的輸出。(5)數(shù)據(jù)總線具有總線保持功能。(6)可編程定時(shí)器。
(7)8位并行主機(jī)接口(HPI),有些產(chǎn)品還包括擴(kuò)展的8位并行主機(jī)接口(HPI8)和16位并行主機(jī)接口(HPI16).(8)片內(nèi)的串行口按不同的型號(hào)分為全雙工串口(支持8位和16位數(shù)據(jù)傳送)、時(shí)分多路(TDM)串口和緩沖(BSP)串口。
C54x系列定點(diǎn)DSP芯片共享同樣的CPU內(nèi)核和總線結(jié)構(gòu),但每一種器件片內(nèi)存儲(chǔ)器的配置和片內(nèi)外設(shè)不盡相同。表3-1列出了TMS320C54x系列DSP基本配置匯總。表3-1 TMS320C54x系列DSP基本配置匯總表型 號(hào)電壓/VcoreI/O片內(nèi)存儲(chǔ)器RAM/ KBROM/ KBDAT/ PRO/B外 設(shè)McBSPTimerHPIDMAMIPS封 裝C54011.83.384128K/2M228位6通道50144LQFP/ 144BGAC54021.6/ 1.83.3328/32128K/2M/ 128K/16M2/31/28位6通道100/ 160144LQFP/ 144BGAC54041.53.332128128K/16M328/16位6通道120144LQFP/ 144BGA續(xù)表型 號(hào)電壓/VcoreI/O片內(nèi)存儲(chǔ)器RAM/ KBROM/ KBDAT/ PRO/B外 設(shè)McBSPTimerHPIDMAMIPS封 裝C54071.63.380256128K/16M328/16位6通道120144LQFP/ 144BGAC54091.5~
1.83.36432128K/16M318/16位6通道80~ 160144LQFP/ 144BGAC54101.5~
2.53.312832128K/16M318/16位6通道100~ 160144LQFP/ 144BGAC54161.5/ 1.63.325632128K/16M318/16位6通道120/ 160144LQFP/ 144BGAC54201.83.32000128K/16M6216位12通道200144LQFP/ 144BGA4.指令系統(tǒng)
在TMS320C54x的指令系統(tǒng)中,具有單指令重復(fù)和塊指令重復(fù)操作指令,32位長(zhǎng)操作數(shù)指令,同時(shí)讀入2個(gè)或3個(gè)操作數(shù)的算術(shù)指令。支持存儲(chǔ)器塊傳送指令,能并行存儲(chǔ)和并行加載的算術(shù)指令,支持條件存儲(chǔ)指令及中斷快速返回指令。5.執(zhí)行速度
對(duì)TMS320C54x而言,其執(zhí)行單周期定點(diǎn)指令時(shí)間為25/20/15/12.5/10ns(對(duì)應(yīng)每秒指令數(shù)分別為40/50/66/80/100MIPS).6.電源和功耗
TMS320C54x DSP芯片可采用5V、3.3V、3V和1.5V、1.8V或2.5V的超低電壓供電。而且其功耗可采用下降指令I(lǐng)DLE1、IDLE2和IDLE3來(lái)控制,以便使DSP工作在節(jié)電模式下可控制關(guān)斷CLKOUT信號(hào)。7.芯片仿真功能 具有符合IEEE 1149.1標(biāo)準(zhǔn)的片內(nèi)仿真JTAG接口,其主要功能是用于與主機(jī)相連接,實(shí)現(xiàn)芯片的仿真與測(cè)試。3.2 總線結(jié)構(gòu)
按照結(jié)構(gòu)來(lái)區(qū)分,又可將總線分成內(nèi)部總線和外部總線,本節(jié)只介紹內(nèi)部總線,外部總線的結(jié)構(gòu)和功能將在3.8節(jié)介紹。
為了提高CPU高度的并行性,達(dá)到最大的處理能力,例如在單周期內(nèi)完成算術(shù)、邏輯和位操作等運(yùn)算,TMS320C54x DSP片內(nèi)采用多總線結(jié)構(gòu),用8條總線,可同時(shí)對(duì)程序指令和數(shù)據(jù)進(jìn)行雙訪問(wèn),這8條16位的總線包括4條程序/數(shù)據(jù)總線和4條地址總線。另外,CPU訪問(wèn)片內(nèi)外設(shè)是通過(guò)在片雙向總線來(lái)實(shí)現(xiàn)的,如圖3-2所示的功能結(jié)構(gòu)圖。正是這種改進(jìn)型哈佛總線結(jié)構(gòu),形成了支持高速指令執(zhí)行的硬件基礎(chǔ)。
(1)程序總線(PB): 傳送來(lái)自程序存儲(chǔ)器的指令代碼和立即數(shù)。
(2)3組數(shù)據(jù)總線(CB、DB和EB): 負(fù)責(zé)將片內(nèi)的各種元器件相互連接,如CPU、數(shù)據(jù)地址產(chǎn)生邏輯、程序地址產(chǎn)生邏輯、片內(nèi)外設(shè)和數(shù)據(jù)存儲(chǔ)器等。其中,CB和DB總線傳送從存儲(chǔ)器讀出的數(shù)據(jù),即“讀”操作使用的數(shù)據(jù)總線;EB總線傳送向存儲(chǔ)器寫(xiě)入的數(shù)據(jù),即“寫(xiě)”操作使用的數(shù)據(jù)總線。
(3)地址總線(PAB、CAB、DAB、EAB): 負(fù)責(zé)傳送執(zhí)行指令所需的地址。
(4)在片雙向總線: TMS320C54x用一組雙向的片內(nèi)總線訪問(wèn)片內(nèi)外設(shè),這組總線輪流使用DB和EB與CPU連接。用這組總線進(jìn)行讀/寫(xiě)操作需要兩個(gè)或更多的周期,具體所需周期數(shù)取決于片內(nèi)外設(shè)的結(jié)構(gòu)。
TMS320C54x能利用兩個(gè)輔助寄存器算術(shù)單元(ARAU0和ARAU1)在同一個(gè)周期內(nèi)生成兩個(gè)數(shù)據(jù)存儲(chǔ)器地址,可實(shí)現(xiàn)片內(nèi)RAM 的雙訪問(wèn)功能。
表3-2列出了各種不同類(lèi)型的總線訪問(wèn)形式。從表中看到,C54x器件在任何給定的機(jī)器周期內(nèi)可執(zhí)行4個(gè)并行存儲(chǔ)器操作: 1次取指、讀取2個(gè)操作數(shù)和寫(xiě)1個(gè)操作數(shù)?;蛲ㄟ^(guò)CB、DB、PB總線同時(shí)取操作數(shù),可在一個(gè)機(jī)器周期內(nèi)完成從數(shù)據(jù)存儲(chǔ)器讀雙數(shù)據(jù)同時(shí)從程序存儲(chǔ)器讀一個(gè)常數(shù)的3個(gè)操作數(shù)讀取,而片上外設(shè)的讀、寫(xiě)則是通過(guò)DB和EB總線輪流與CPU連接完成,所以使用這組總線進(jìn)行讀/寫(xiě)操作需要兩個(gè)或更多的周期。表3-2 C54x DSP讀/寫(xiě)操作占用總線情況讀/寫(xiě)方式地 址 總 線PABCABDABEAB程序總線
PB數(shù) 據(jù) 總 線CBDBEB程序讀√√程序?qū)憽獭虇螖?shù)據(jù)讀√√雙數(shù)據(jù)讀√√√√32位長(zhǎng)數(shù)據(jù)讀√(hw)√(lw)√(hw)√(lw)單數(shù)據(jù)寫(xiě)√√數(shù)據(jù)讀/數(shù)據(jù)寫(xiě)√√√√雙數(shù)據(jù)讀/系數(shù)讀√√√√√√外設(shè)讀√√外設(shè)寫(xiě)√√3.3 存儲(chǔ)器結(jié)構(gòu) TMS320C54x DSP存儲(chǔ)器采用改進(jìn)型哈佛結(jié)構(gòu)。與馮·諾依曼結(jié)構(gòu)的存儲(chǔ)器相比較,哈佛結(jié)構(gòu)的程序/數(shù)據(jù)總線和空間是分開(kāi)的,馮·諾依曼結(jié)構(gòu)的程序/數(shù)據(jù)總線和空間是合二為一的,而改進(jìn)型哈佛結(jié)構(gòu)的部分程序/數(shù)據(jù)空間可交叉,因此提供了高度的并行性。3.3.1 DSP存儲(chǔ)器空間的劃分 C54x DSP的存儲(chǔ)空間共192K字,由3個(gè)獨(dú)立可選的存儲(chǔ)空間組成,包括64K字的程序存儲(chǔ)空間、64K字的數(shù)據(jù)存儲(chǔ)空間和64K字的I/O空間。其中有些型號(hào)芯片的程序空間還可以進(jìn)一步擴(kuò)展。
存儲(chǔ)器分為片內(nèi)存儲(chǔ)器和片外存儲(chǔ)器。片內(nèi)存儲(chǔ)器有3種類(lèi)型: 雙訪問(wèn)RAM(DARAM)、單訪問(wèn)RAM(SARAM)和ROM.RAM總是安排到數(shù)據(jù)存儲(chǔ)空間,但也可以配置在程序存儲(chǔ)空間。C54x片上還有26個(gè)映射到數(shù)據(jù)存儲(chǔ)空間的CPU寄存器和外設(shè)寄存器。ROM一般映射到程序存儲(chǔ)空間,也可以部分地映射到數(shù)據(jù)存儲(chǔ)空間。在TMS320C54x DSP中,片外存儲(chǔ)器主要包括程序存儲(chǔ)器、數(shù)據(jù)存儲(chǔ)器、I/O空間。與片外存儲(chǔ)器相比,片內(nèi)存儲(chǔ)器不需插入等待狀態(tài),成本低,功耗低。但是,片外存儲(chǔ)器具有尋址較大存儲(chǔ)空間的能力,而片內(nèi)存儲(chǔ)器尋址存儲(chǔ)空間較小。C54x通過(guò)設(shè)置處理器工作方式狀態(tài)寄存器(PMST)中的3個(gè)狀態(tài)位MP/MC、OVLY和DROM(詳見(jiàn)3.4.1節(jié)),可以很方便地“使能”和“禁止”程序與數(shù)據(jù)空間中的片內(nèi)存儲(chǔ)器。(1)MP/MC位
MP/MC位決定是否使用片內(nèi)ROM.若MP/MC=0,稱(chēng)微計(jì)算機(jī)模式,片內(nèi)ROM使能并能夠訪問(wèn)。若MP/MC=1,稱(chēng)微處理器模式,表示片內(nèi)ROM無(wú)法訪問(wèn)。(2)OVLY位
OVLY位決定是否讓數(shù)據(jù)存儲(chǔ)器映射到程序存儲(chǔ)器空間。若OVLY=0,片內(nèi)RAM只映射到數(shù)據(jù)存儲(chǔ)空間。
若OVLY=1,片內(nèi)RAM同時(shí)映射到程序和數(shù)據(jù)存儲(chǔ)空間。(3)DROM位
DROM位決定是否讓部分程序存儲(chǔ)器映射到數(shù)據(jù)存儲(chǔ)器空間。若DROM=0,片內(nèi)ROM不映射到數(shù)據(jù)存儲(chǔ)空間。若DROM=1,部分片內(nèi)ROM映射到數(shù)據(jù)存儲(chǔ)空間。DROM位的用法與MP/MC位的用法無(wú)關(guān)。不同的C54x的數(shù)據(jù)和程序存儲(chǔ)區(qū)分配并不完全相同。圖3-3(a)所示為T(mén)MS320C549存儲(chǔ)器空間分配圖,圖3-3(b)所示為T(mén)MS320C5416存儲(chǔ)器空間分配圖,從圖中可以看到在任何一個(gè)存儲(chǔ)空間內(nèi),RAM、ROM都可以駐留在片內(nèi)或者片外,但需要通過(guò)對(duì)3個(gè)狀態(tài)位MP/MC、OVLY和DROM的設(shè)置來(lái)配置。圖3-3 存儲(chǔ)器空間分配圖 圖3-3(續(xù))
所有C54x DSP器件提供一定數(shù)量的片內(nèi)ROM和RAM, DSP有兩種類(lèi)型的RAM,包括雙尋址RAM(DARAM)和單尋址RAM(SARAM)。表3-3列出了不同C54x系列DSP 片內(nèi)各種存儲(chǔ)器的配置。
1.片內(nèi)ROM 片內(nèi)ROM是程序存儲(chǔ)器的一部分,對(duì)某些DSP器件來(lái)說(shuō),也可是數(shù)據(jù)存儲(chǔ)空間的一部分,如C5402。當(dāng)MP/MC設(shè)置為0時(shí),可以映射到程序存儲(chǔ)空間的ROM為4KB;當(dāng)DROM設(shè)置為1時(shí),可以映射到數(shù)據(jù)存儲(chǔ)器空間的ROM為4KB。不同芯片的片內(nèi)可用ROM容量是不一樣的,見(jiàn)表3-3。對(duì)于ROM少的DSP器件(2KB), ROM中含有自舉加載器,在程序啟動(dòng)時(shí),將用戶(hù)的代碼從慢的外部ROM、串口,或JTAG加載到內(nèi)部存儲(chǔ)器,這樣可以加快程序的運(yùn)行速度。對(duì)于具有較大ROM的器件,部分ROM可以映射到數(shù)據(jù)和程序空間,用戶(hù)提供的代碼或數(shù)據(jù)以目標(biāo)文件格式寫(xiě)入ROM, TI公司可以將程序掩膜到該ROM中。2.片內(nèi)雙尋址RAM(DARAM)所謂DARAM,就是在一個(gè)指令周期內(nèi),CPU可對(duì)其進(jìn)行讀和寫(xiě)兩次存取操作,DARAM由塊組成,CPU能在每個(gè)周期內(nèi)對(duì)同一塊DARAM進(jìn)行讀和寫(xiě)。DARAM總是映射在數(shù)據(jù)存儲(chǔ)器空間,用于存儲(chǔ)數(shù)據(jù),當(dāng)OVLY設(shè)置為1時(shí),它也可同時(shí)映射在程序存儲(chǔ)器空間,用于存儲(chǔ)程序代碼。表3-3 常見(jiàn)的C54x系列DSP片內(nèi)存儲(chǔ)器配置KB存儲(chǔ)器類(lèi)型C541C542C543C545C546C548C549C5402C5416C5420ROM***程序ROM***程序/數(shù)據(jù)ROM800161600400DARAM***SARAM***3.片內(nèi)單尋址RAM(SARAM)在一個(gè)指令周期內(nèi)只能進(jìn)行一次讀或?qū)懖僮?。SARAM也由塊組成,與DARAM一樣,SARAM總是映射在數(shù)據(jù)存儲(chǔ)器空間,用于存儲(chǔ)數(shù)據(jù),當(dāng)OVLY設(shè)置為1時(shí),也可同時(shí)映射在程序存儲(chǔ)器空間,用于存儲(chǔ)程序代碼。4.存儲(chǔ)器映射寄存器
CPU內(nèi)部專(zhuān)用寄存器和片上外設(shè)寄存器總是映射在數(shù)據(jù)存儲(chǔ)器的0頁(yè)上,對(duì)它們的訪問(wèn)很簡(jiǎn)單,存儲(chǔ)器映射訪問(wèn)提供了一種方便途徑,用于寄存器的存儲(chǔ)和恢復(fù),也用于累加器與其他寄存器之間的信息傳遞。3.3.2 程序存儲(chǔ)器
程序存儲(chǔ)器空間存放要執(zhí)行的指令和執(zhí)行中所用的系數(shù)表。C54x DSP可以尋址64 K字的程序存儲(chǔ)空間。但也有一些型號(hào)的DSP可以擴(kuò)展到8 M字,如C548、C549、C5410、C5402和C5420。下面分別講述程序存儲(chǔ)器的組織、片內(nèi)ROM 的安排、擴(kuò)展程序存儲(chǔ)器等內(nèi)容。1.程序存儲(chǔ)器空間的配置
程序存儲(chǔ)器空間由片內(nèi)和片外程序存儲(chǔ)器組成。如前所述,片內(nèi)程序空間的組織主要通過(guò)設(shè)置MP/MC、OVLY位來(lái)實(shí)現(xiàn)。表3-4列出了各種C54x芯片片內(nèi)程序存儲(chǔ)器配置情況。MP/MC和OVLY 位決定了哪個(gè)片內(nèi)存儲(chǔ)器在程序空間中可用。例如,當(dāng)OVLY設(shè)置為1時(shí),DARAM或SARAM才能被配置到程序存儲(chǔ)器空間;而只有當(dāng)MP/MC設(shè)置為0時(shí),片內(nèi)ROM才可用。MP/MC是DSP的一個(gè)外部引腳,設(shè)置MP/MC狀態(tài)有兩種方法,一種是直接給MP/MC引腳低電平或高電平,當(dāng)DSP器件復(fù)位時(shí),MP/MC引腳的邏輯狀態(tài)被傳送到PMST寄存器的MP/MC位。另一種方法是用戶(hù)通過(guò)軟件來(lái)設(shè)置或清除PMST寄存器的MP/MC位,以便禁止或使能片內(nèi)ROM。如果片內(nèi)存儲(chǔ)器配置到程序存儲(chǔ)器中,則芯片在訪問(wèn)程序存儲(chǔ)器時(shí)會(huì)自動(dòng)訪問(wèn)這些存儲(chǔ)單元。當(dāng)PAGEN產(chǎn)生了一個(gè)不在片內(nèi)存儲(chǔ)器的地址時(shí),會(huì)自動(dòng)使用一個(gè)外部總線操作。C54x器件程序存儲(chǔ)器空間配置圖如圖3-3(a)和圖3-3(b)所示。表3-4 TSM320C54x芯片片內(nèi)程序存儲(chǔ)器配置KB型 號(hào)ROMDARAM(OVLY=1)SARAM(OVLY=1)TMS320C541285-TMS320C542210-TMS320C543210-TMS320C545486-TMS320C546486-TMS320C5482824TMS320C54916824TMS320C5402416-TMS320C541616856TMS320C5420-32168 2.片內(nèi)ROM 的組織和內(nèi)容
為了增強(qiáng)處理器的性能,將片內(nèi)ROM再細(xì)分為若干塊,這樣就可以在片內(nèi)ROM的一個(gè)塊內(nèi)取指的同時(shí)又在別的塊中讀數(shù)據(jù)。圖3-4所示為各種C54x器件的片內(nèi)ROM分塊圖。根據(jù)C54x器件的不同,ROM可以組織為2KB、4KB或8KB的塊。圖3-4 C54x 器件片內(nèi)ROM分塊圖
(1)對(duì)于2K-ROM器件,其ROM 塊為2K字。
(2)對(duì)于4K-ROM和28K-ROM 器件,其ROM塊為4K字。(3)對(duì)于16K-ROM和48K-ROM器件,其ROM塊為8K字。C54x的片內(nèi)ROM容量有大(28K或48K字)有?。?K或4K字),但對(duì)于程序存儲(chǔ)器空間的最高2K字程序空間(F800h~FFFFh),容量大的片內(nèi)ROM(C541/C545/C546)可以把 阿道夫 的 范德薩 啊訂單式
第二篇:關(guān)于分析今天長(zhǎng)安保定百度愛(ài)問(wèn)愛(ài)學(xué)位論文寫(xiě)作方法學(xué)位論文.
的的范德薩的地方愛(ài)的規(guī)格愛(ài)你啊好文章梁慧星:學(xué)位論文寫(xiě)作方法(2):
學(xué)位論文的結(jié)構(gòu)
三、學(xué)位論文的結(jié)構(gòu)
答辯委員會(huì)成員或委員會(huì)外的專(zhuān)家對(duì)碩士、博士論文作鑒定、寫(xiě)評(píng)語(yǔ),有一個(gè)內(nèi)容是就論文結(jié)構(gòu)表態(tài)。一篇合格的學(xué)位論文,要求結(jié)構(gòu)合理??隙ǖ脑u(píng)語(yǔ)是:本文結(jié)構(gòu)合理、邏輯嚴(yán)謹(jǐn)、層次清晰。什么叫“結(jié)構(gòu)合理”?結(jié)構(gòu)合理就是指論文的“層次清晰”、“邏輯嚴(yán)密”。這就要求了解論文的一般結(jié)構(gòu),這里注重講碩士論文、博士論文的結(jié)構(gòu)。
學(xué)術(shù)論文的結(jié)構(gòu):
目錄
序言
導(dǎo)論
本論
結(jié)論
參考文獻(xiàn)目錄
后記
上述結(jié)構(gòu)中,導(dǎo)論、本論、結(jié)論三部分構(gòu)成論文的本體;目錄、序言、參考文獻(xiàn)目錄和后記,是附屬部分。最重要的當(dāng)然是本體。一篇完整的學(xué)位論文,其本體由導(dǎo)論、本論、結(jié)論三部分構(gòu)成。有沒(méi)有特殊的,有特殊的,所謂特殊,無(wú)非是在一般結(jié)構(gòu)基礎(chǔ)上省略了其中的某個(gè)部分,或者省略結(jié)論,或者省略導(dǎo)論,但無(wú)論如何不能省略本論。如果以重要性為標(biāo)準(zhǔn)進(jìn)行劃分,則導(dǎo)論和結(jié)論屬于組成部分,本論屬于本質(zhì)部分。例如一個(gè)人,頭和軀干是本質(zhì)部分,四肢是組成部分。沒(méi)有手臂,甚至手腳都沒(méi)有,不影響人這個(gè)事物的存在,仍然是人;但沒(méi)有頭和軀干,光有四肢就不成其為人。同理,省略了導(dǎo)論、結(jié)論,不影響學(xué)術(shù)論文的本質(zhì),但學(xué)術(shù)論文的完整性大大受到損害,專(zhuān)家作鑒定會(huì)寫(xiě)上一句:結(jié)構(gòu)不完整。當(dāng)然,學(xué)術(shù)論文不可能沒(méi)有本論,假設(shè)沒(méi)有本論,就不成其為學(xué)術(shù)論文。
可見(jiàn),本論部分特別重要,答辯委員會(huì)成員評(píng)價(jià)學(xué)位論文結(jié)構(gòu)合理不合理,注重的是本論部分。
下面對(duì)各部分作簡(jiǎn)要說(shuō)明:
(一)導(dǎo)論
導(dǎo)論起什么作用?導(dǎo)論的作用在于引起讀者的閱讀興趣。讀者拿到一篇學(xué)術(shù)論文,通常好多萬(wàn)字、二三十萬(wàn)字,是否值得花費(fèi)寶貴的時(shí)間,光看題目還難以判斷,總是首先讀導(dǎo)論,希望從導(dǎo)論的內(nèi)容判斷本文是否有閱讀價(jià)值,是否值得花費(fèi)時(shí)間閱讀。
導(dǎo)論的內(nèi)容,通常是交待課題,本文究竟要研究一個(gè)什么課題,這個(gè)課題的產(chǎn)生背景,說(shuō)明作者為什么要研究這個(gè)課題,它有什么理論意義和現(xiàn)實(shí)意義。如果是博士論文,通常還要交待所采用的研究方法,交待論文的大體結(jié)構(gòu)。
實(shí)例1:
博士論文:合同自由與公序良俗
第一章 導(dǎo)論
(一)選題背景及意義
(二)研究狀況和文獻(xiàn)綜述
(三)研究方法和主要內(nèi)容
實(shí)例2:
博士論文:國(guó)際貨物貿(mào)易中的補(bǔ)貼與反補(bǔ)貼法律問(wèn)題研究
導(dǎo)論
(一)本文研究的目的和意義
(二)本文研究范圍
(三)素材選取與研究方法
(四)體例安排
(二)結(jié)論
學(xué)術(shù)論文應(yīng)當(dāng)有結(jié)論,是學(xué)術(shù)研究的規(guī)律性決定的。學(xué)術(shù)研究是一個(gè)過(guò)程,有其始端和終端。導(dǎo)論是始端,結(jié)論是終端。結(jié)論表明一項(xiàng)科學(xué)研究的結(jié)束。同時(shí),一項(xiàng)研究當(dāng)有其研究結(jié)果。最終得到一個(gè)什么研究結(jié)果,應(yīng)當(dāng)在結(jié)論部分作出概括。如果還有遺留問(wèn)題沒(méi)有解決,也應(yīng)在結(jié)論部分指出。
從學(xué)位論文答辯的角度講,論文要經(jīng)專(zhuān)家鑒定,寫(xiě)出評(píng)語(yǔ)。答辯委員會(huì)成員也要審讀論文,寫(xiě)出評(píng)語(yǔ)??紤]到一篇博士學(xué)位論文通常二十多萬(wàn)字,甚至三十多萬(wàn)字,專(zhuān)家教授通常不可能一口氣讀完??偸亲x幾頁(yè),放下了,又讀幾頁(yè),有什么事情又放下了。經(jīng)過(guò)好多次才斷續(xù)讀完,讀到末尾,前面的內(nèi)容已經(jīng)模糊、記不清了。不可否認(rèn),有的評(píng)定人因時(shí)間關(guān)系不可能讀完全文,閱讀了導(dǎo)論部分,翻閱、選讀幾個(gè)章節(jié),然后就寫(xiě)評(píng)語(yǔ)。如果有一個(gè)結(jié)論,概括本文的研究結(jié)果、作者的基本學(xué)術(shù)見(jiàn)解、本研究結(jié)果的理論意義和實(shí)踐價(jià)值,對(duì)于審定人作出總的評(píng)價(jià)有莫大的幫助。這對(duì)于論文最后能否通過(guò)答辯,有極重大的意義。切不可掉以輕心!
實(shí)例:
博士論文:合同自由與公序良俗
第六章 結(jié)論
(一)總結(jié)
(二)論文的基本觀點(diǎn)
(三)論文的主要?jiǎng)?chuàng)新點(diǎn)
(四)論文的局限和不足
有的學(xué)位論文以立法建議代替結(jié)論,這大抵屬于制度型選題,研究某一項(xiàng)法律制度,研究最后得到的基本學(xué)術(shù)見(jiàn)解或結(jié)論,表現(xiàn)為建議我國(guó)立法機(jī)關(guān)制定某一法律或?qū)ΜF(xiàn)行法作修改,并形成了立法或修改的基本設(shè)想甚至條文草案。另外,也有以結(jié)束語(yǔ)代替結(jié)論的。以立法建議代替結(jié)論,以結(jié)束語(yǔ)代替結(jié)論,不等于沒(méi)有結(jié)論。省略結(jié)論,影響論文結(jié)構(gòu)的完整性,完整性是合理性的一個(gè)方面,因此沒(méi)有結(jié)論將影響論文結(jié)構(gòu)的合理性。
(三)本論
本論是一篇學(xué)位論文的本質(zhì)部分,沒(méi)有本論就不成其為一篇論文。就象沒(méi)有頭和軀干不能成其為人一樣。本論的內(nèi)容是研究過(guò)程的反映,應(yīng)當(dāng)寫(xiě)什么,自然不用我在這里說(shuō)。這里只是介紹本論部分的結(jié)構(gòu)安排。評(píng)價(jià)一篇論文的結(jié)構(gòu)是否合理,主要是針對(duì)本論部分的結(jié)構(gòu)是否合理。
1、本論部分的結(jié)構(gòu)
大體上有五種:
總分結(jié)構(gòu)
三分結(jié)構(gòu)
四分結(jié)構(gòu)
編章結(jié)構(gòu)
章節(jié)結(jié)構(gòu)
總分結(jié)構(gòu),實(shí)際是分為兩個(gè)部分,稱(chēng)為總論與分論。實(shí)際上,是哲學(xué)上的“一般”與“特殊”、“共性”與“個(gè)性”的關(guān)系。有關(guān)本課題的一般理論、共同理論,在總論部分;然后分別研究本課題內(nèi)部各特殊部分或特殊問(wèn)題,叫做分論。實(shí)際是“二分結(jié)構(gòu)”:總論、分論。然后總論再分為若干部分(章),分論再分若干部分(章)。如果將總論、分論作為兩編,每編下分若干章,這就是“二分結(jié)構(gòu)”加“編章結(jié)構(gòu)”。有的博士論文,在總論、分論之前再設(shè)緒論,研究本課題的前提性的問(wèn)題,作為另一個(gè)部分,稱(chēng)為緒論編,包括若干章。這樣就變成“三分結(jié)構(gòu)”加“編章結(jié)構(gòu)”??梢哉f(shuō)幾乎所有的選題,都有總論與分論的劃分,都可采用“二分結(jié)構(gòu)”加“編章結(jié)構(gòu)”。但是,如果屬于一般理論、共同理論的內(nèi)容太少,不足以再分為若干章,就會(huì)出現(xiàn)這樣的情況:總論編只有一章,分論編包括若干章,顯得不協(xié)調(diào)、不成比例。因此可不設(shè)編,直接采用“章節(jié)結(jié)構(gòu)”,第一章實(shí)際是總論,從第二章起實(shí)際是分論。下面舉一些實(shí)例。
采“四分結(jié)構(gòu)”的實(shí)例:
蔣新苗的博士論文:國(guó)際收養(yǎng)法律制度研究 第一編 導(dǎo)論,包括第一、二章;
第二編 國(guó)際收養(yǎng)中的國(guó)際私法問(wèn)題,包括第三、四章;
第三編 國(guó)際收養(yǎng)法的統(tǒng)一化進(jìn)程,包括第五、六章;
第四編 中國(guó)與國(guó)際收養(yǎng)法統(tǒng)一化進(jìn)程,包括第七、八、九章。
須說(shuō)明的是,第一編導(dǎo)論,內(nèi)容實(shí)際是緒論。緒論是本論的一部,導(dǎo)論不是本論的一部。本文省略了結(jié)論。
采“三分結(jié)構(gòu)”的實(shí)例1:
傅靜坤的博士后論文:契約沖突法論
第一部分 契約沖突法的基本原則和規(guī)范,包括第一、二章;
第二部分 統(tǒng)一國(guó)際契約實(shí)體法與統(tǒng)一國(guó)際契約沖突法,包括第三、四章;
第三部分 區(qū)際契約沖突法,包括第五章。
(本文省略了結(jié)論)
采“三分結(jié)構(gòu)”的實(shí)例2:
沈涓的博士論文:中國(guó)區(qū)際沖突法研究
第一編 中國(guó)區(qū)際沖突法的歷史與現(xiàn)狀,包括第一至三章;
第二編 中國(guó)區(qū)際沖突法的方法與規(guī)則,包括第四至五章;
第三編 中國(guó)區(qū)際法律關(guān)系沖突的調(diào)整,包括第六至十一章。
(本文省略結(jié)論)
2、總分結(jié)構(gòu)
這種結(jié)構(gòu)最為常見(jiàn),通常先劃分為總論與分論兩大部分,然后各部分再分若干章;或設(shè)總論編、分論編,然后各編再分若干章;或不設(shè)編,總論作為第一章,分論分為若干章。實(shí)際是總分結(jié)構(gòu)加編章結(jié)構(gòu)。多數(shù)博士論文、碩士論文采用這樣的結(jié)構(gòu)。
實(shí)例:
肖厚國(guó)的博士論文:物權(quán)變動(dòng)研究
(導(dǎo)論)
第一章 物權(quán)變動(dòng)的基本理論
第二章 物權(quán)變動(dòng)的立法主義
(一)第三章 物權(quán)變動(dòng)的立法主義
(二)第四章 不動(dòng)產(chǎn)物權(quán)變動(dòng)的公示
(一)第五章 不動(dòng)產(chǎn)物權(quán)變動(dòng)的公示
(二)第六章 動(dòng)產(chǎn)物權(quán)變動(dòng)
第七章 善意取得 第八章 取得時(shí)效
(結(jié)束語(yǔ))
本論實(shí)際上分為“總論”與“分論”兩大部分,“總論”再分為“物權(quán)變動(dòng)的基本理論”(第一章)與“物權(quán)變動(dòng)的立法主義”(第二、三章)兩部分;“分論”分為“積極的物權(quán)變動(dòng)”與“消極的物權(quán)變動(dòng)”兩部分,其中“積極的物權(quán)變動(dòng)”,再分為“不動(dòng)產(chǎn)物權(quán)變動(dòng)”(第四、五章)與“動(dòng)產(chǎn)物權(quán)變動(dòng)”(第六章)兩部分;“消極的物權(quán)變動(dòng)”,再分為“善意取得”(第七章)與“取得時(shí)效”(第八章)兩部分。屬于典型的“總分結(jié)構(gòu)+章節(jié)結(jié)構(gòu)”。
不合理的結(jié)構(gòu):
如果本論分為兩大塊,下面不再劃分章節(jié),或者本論僅有兩章,屬于單純的二分結(jié)構(gòu),應(yīng)當(dāng)認(rèn)為結(jié)構(gòu)不合理。為什么這樣的結(jié)構(gòu)不合理?首先是不合習(xí)慣。其次是美學(xué)上的考慮。一篇論文,前面一個(gè)序言,后面一個(gè)結(jié)語(yǔ),本論部分就兩章,第一章、第二章。如果序言、結(jié)語(yǔ)都省略了,一篇論文就兩塊,第一部分,第二部分,或者第一章、第二章,這不好看。要進(jìn)一步追問(wèn)為什么?也難以回答??赡苁翘舭濉O旅媾e實(shí)例。
實(shí)例1:
碩士論文題目:作者精神權(quán)利性質(zhì)探討
第一部分 概述
第二部分 作者精神權(quán)利性質(zhì)探討
論文前面沒(méi)有導(dǎo)言,后面沒(méi)有結(jié)論,本論就兩部分,很不合理。
實(shí)例2:
一篇碩士論文
序言
第一章
第二章
結(jié)語(yǔ)
前有一個(gè)序言,后有一個(gè)簡(jiǎn)短的結(jié)語(yǔ),中間本論部分就兩章,屬于結(jié)構(gòu)不合理。
3、關(guān)于切題
關(guān)于本論的結(jié)構(gòu),無(wú)論采取哪一種結(jié)構(gòu)模式,其共同的要求是:緊扣題目,亦即我們平常所謂“切題”。這主要從每部分的標(biāo)題來(lái)體現(xiàn)。
從上引博士論文的結(jié)構(gòu),我們看到,每一個(gè)標(biāo)題,都緊扣住題目。如物權(quán)變動(dòng)研究一文,第一至第六章的標(biāo)題都有“物權(quán)變動(dòng)”一語(yǔ),第七、八兩章的標(biāo)題雖然沒(méi)有“物權(quán)變動(dòng)”四個(gè)字,但“善意取得”和“取得時(shí)效”是物權(quán)變動(dòng)的具體形式??梢?jiàn),所謂切題,所謂緊扣題目,往往通過(guò)在本論各部分標(biāo)題中“反復(fù)出現(xiàn)”論文題目中的“關(guān)鍵詞語(yǔ)”來(lái)體現(xiàn)。反之,如果本論各標(biāo)題與論文題目無(wú)關(guān),找不到論文題目的關(guān)鍵詞語(yǔ),我們就會(huì)覺(jué)得不切題,沒(méi)有緊扣題目。下面舉例。
實(shí)例1:
博士論文題目:論私法對(duì)國(guó)際法的影響
第一章 萬(wàn)民法與國(guó)際法
第二章 人或主體
第三章 領(lǐng)土主權(quán)與所有權(quán)
第四章 條約與契約
評(píng)論:
在各部分標(biāo)題中,沒(méi)有出現(xiàn)論文題目中的關(guān)鍵詞語(yǔ)“私法”和“國(guó)際法”。從各部分的標(biāo)題,讀者很難理解該部分內(nèi)容與題目間是否有密切的關(guān)聯(lián)。這就是沒(méi)有緊扣題目,或者說(shuō)不切題。
實(shí)例2:
博士論文題目:現(xiàn)代商人法研究
其本論分三章:
第二章 現(xiàn)代商人法產(chǎn)生和發(fā)展的歷史過(guò)程
第三章 現(xiàn)代商人法的適用及其法律效力
第四章 現(xiàn)代商人法與沖突法及國(guó)際仲裁法的完善和發(fā)展
評(píng)論:
題目中的關(guān)鍵詞語(yǔ)是“現(xiàn)代商人法”,我們看到本論部分每一個(gè)標(biāo)題都重復(fù)“現(xiàn)代商人法”一語(yǔ),使讀者覺(jué)得各部分內(nèi)容與題目的關(guān)系非常緊密,扣得很緊,這就叫“切題”。
4、小結(jié)
從上述本論部分的結(jié)構(gòu)安排,我們可以看到,博士論文采用總分結(jié)構(gòu)加編章結(jié)構(gòu),或者采用章節(jié)結(jié)構(gòu)的最常見(jiàn),這類(lèi)結(jié)構(gòu)安排系以“章”為單位,碩士論文也以章節(jié)結(jié)構(gòu)最常見(jiàn),也有的用“部分”為單位,“部分”下面以一、二、三、四為序。是否可以作出這樣一個(gè)判斷:
無(wú)論以“章”或“部分”為單位,本論部分所劃分的單位至少應(yīng)在三個(gè)以上,例如不少于三章或三個(gè)部分。否則,就叫結(jié)構(gòu)不合理。
5、邏輯關(guān)系 以上僅指對(duì)結(jié)構(gòu)安排的形式要求。在此基礎(chǔ)上,還有對(duì)邏輯性的要求。指本論部分的結(jié)構(gòu)安排要具有一定的邏輯關(guān)系。大體有下面三種邏輯關(guān)系:
第一種 總分關(guān)系
第二種 并立關(guān)系
第三種 遞進(jìn)關(guān)系
第一種:總分關(guān)系
關(guān)于本課題的一般性問(wèn)題、一般理論、基本理論、基本原則的內(nèi)容,屬于總論。特殊問(wèn)題、特殊理論、具體制度、具體問(wèn)題、構(gòu)成條件、實(shí)際運(yùn)用等內(nèi)容,屬于分論。總論與分論之間,是一般與個(gè)別、普遍與特殊的關(guān)系,通??傉摬糠謶?yīng)當(dāng)在前,分論部分應(yīng)當(dāng)在后。無(wú)論采用總分結(jié)構(gòu)或者編章結(jié)構(gòu)、章節(jié)結(jié)構(gòu),都要求總論與分論有清晰的界限,不能混淆,總論內(nèi)容寫(xiě)完再安排分論,分論部分不能插入總論的內(nèi)容,不能顛倒順序,一般不能先分論后總論,應(yīng)當(dāng)先總論后分論。
其規(guī)則是:先總、后分。
第二種:并列關(guān)系
如果采用總分結(jié)構(gòu),總論部分與分論部分,已具有并列的意義,總論下面的各章、分論下面的各章,也可以是并列的關(guān)系,即各章的內(nèi)容應(yīng)當(dāng)處在同一層次。采用編章結(jié)構(gòu),各編的內(nèi)容可以是并列的關(guān)系,例如緒論編、總論編、分論編,編下面的各章可以是并列關(guān)系。
其規(guī)則是:位階同一
實(shí)例1:
肖厚國(guó)的博士論文:物權(quán)變動(dòng)研究
第一章 物權(quán)變動(dòng)的基本理論
第二章 物權(quán)變動(dòng)的立法主義
(一)第三章 物權(quán)變動(dòng)的立法主義
(二)第四章 不動(dòng)產(chǎn)物權(quán)變動(dòng)的公示
(一)第五章 不動(dòng)產(chǎn)物權(quán)變動(dòng)的公示
(二)第六章 動(dòng)產(chǎn)物權(quán)變動(dòng)
第七章 善意取得
第八章 取得時(shí)效
其結(jié)構(gòu)屬于典型的并列關(guān)系,而且是多層次的并列關(guān)系。第一個(gè)層次是總論(第1、2、3章)與分論(第4、5、6、7、8章)的并列;第二個(gè)層次是總論下面物權(quán)變動(dòng)的基本理論(第1章)與物權(quán)變動(dòng)的立法主義(第2、3章)的并列,分論下面積極的物權(quán)變動(dòng)(第4、5、6章)與消極的物權(quán)變動(dòng)(第7、8章)的并列;第三個(gè)層次是不動(dòng)產(chǎn)物權(quán)變動(dòng)(第4、5章)、動(dòng)產(chǎn)物權(quán)變動(dòng)(第6章)、善意取得(第7章)、取得時(shí)效(第8章)的并列。
實(shí)例2:
楊松的博士論文:國(guó)際貨幣基金協(xié)定研究
本論分五章:
第四章 國(guó)際收支平衡的法律制度研究
第五章 國(guó)際儲(chǔ)備的法律制度研究
第六章 匯兌安排國(guó)際法律制度研究
第七章 外匯管制法律問(wèn)題研究
第八章 基金協(xié)定的監(jiān)督與磋商機(jī)制研究
其結(jié)構(gòu)也屬于典型的并列關(guān)系。
第三種:遞進(jìn)關(guān)系
采編章結(jié)構(gòu),在一編之下的各章可以是遞進(jìn)關(guān)系。采章節(jié)結(jié)構(gòu),各章之間也可以是遞進(jìn)關(guān)系。章下面的節(jié),也可以是遞進(jìn)關(guān)系。就一篇博士論文而言,可能各編之間是并列關(guān)系,各編下面的章是遞進(jìn)關(guān)系,或者總論編下面的各章是并列關(guān)系,分論編下面各章是遞進(jìn)關(guān)系?;蛘卟煽偡纸Y(jié)構(gòu)不設(shè)編,總論僅一章,從第二章開(kāi)始是分論,分論各章是遞進(jìn)關(guān)系。至于章下面的各節(jié)之間的關(guān)系,當(dāng)然可以某些章下面的各節(jié)之間是并列關(guān)系,某些章下面的各節(jié)之間是遞進(jìn)關(guān)系。
這里有一個(gè)要求,某編下面的各章,或者某章下面的各節(jié),如果采遞進(jìn)關(guān)系,就一定是遞進(jìn)關(guān)系,不能混淆。不能出現(xiàn)這樣的情況,一編有五章,其中一、二、三、五章顯然是遞進(jìn)關(guān)系,中間第四章與各章不構(gòu)成遞進(jìn)關(guān)系,或者一章下面若干節(jié),其中幾節(jié)似乎是遞進(jìn)關(guān)系,中間又有幾節(jié)似乎是并列關(guān)系。
遞進(jìn)關(guān)系有三種不同形態(tài):
時(shí)間上的遞進(jìn)關(guān)系
空間上的遞進(jìn)關(guān)系
純粹邏輯上的遞進(jìn)關(guān)系
(1)時(shí)間上的遞進(jìn)關(guān)系
時(shí)間上的遞進(jìn)關(guān)系,是指在時(shí)間上由遠(yuǎn)到近,先從該制度的歷史說(shuō)起,從古羅馬法說(shuō)起,中世紀(jì)有什么變化,近代有何發(fā)展,直到現(xiàn)在的現(xiàn)狀,實(shí)際是采歷史研究方法。法制史研究論文,大體體現(xiàn)這樣的遞進(jìn)關(guān)系。在部門(mén)法,例如民法碩士、博士論文中,也常常采用歷史研究方法,因此在論文的某個(gè)部分會(huì)反映時(shí)間上的遞進(jìn)關(guān)系,通常在緒論或總論部分,或者某一章下面的節(jié),不大可能一篇民法論文各章之間都反映時(shí)間上的遞進(jìn)關(guān)系。
這種遞進(jìn)關(guān)系,要求嚴(yán)格按照時(shí)間的先后順序,如果出現(xiàn)時(shí)間先后順序的錯(cuò)亂,就叫層次不清、邏輯混亂。
其規(guī)則是:時(shí)間愈早愈在前,時(shí)間愈近愈在后。
(2)空間上的遞進(jìn)關(guān)系
此所謂“空間”實(shí)際上包括兩種情形:一是地域上的空間;一是抽象的空間。無(wú)論屬于地域上的空間,或者抽象的空間,都要求“由外到內(nèi)”,先討論外部的問(wèn)題,后討論內(nèi)部的問(wèn)題。先研究外國(guó)的制度、發(fā)展、經(jīng)驗(yàn)教訓(xùn),再討論本國(guó)的制度、發(fā)展、構(gòu)成、適用、存在問(wèn)題及對(duì)策等;或者先討論該制度的外部關(guān)系,產(chǎn)生原因、背景、哲學(xué)思想、政策取向、功能等,然后進(jìn)入該制度內(nèi)部,討論其構(gòu)成要件、法律效果、解釋適用等。
空間上的遞進(jìn)關(guān)系,要求區(qū)分內(nèi)外,先外后內(nèi)。如果外部問(wèn)題未討論完就進(jìn)入內(nèi)部問(wèn)題的討論,中途再反過(guò)來(lái)討論外部問(wèn)題,或者一開(kāi)始討論本國(guó)制度,中間突然插入外國(guó)制度的探討,然后再回到本國(guó)制度的研究,就叫層次不清、邏輯混亂。
其規(guī)則是:先外、后內(nèi)。
(3)純粹邏輯上的遞進(jìn)關(guān)系
所謂純粹邏輯上的遞進(jìn)關(guān)系,是指在邏輯上由抽象到具體。先從概念、定義說(shuō)起,解釋其含義,探討其內(nèi)涵、外延,確定其適用范圍,分析適用條件、法律效果。通常采用法律解釋學(xué)的研究方法,就反映這種遞進(jìn)關(guān)系。要求符合從抽象到具體的邏輯順序,愈抽象的問(wèn)題愈在前,愈具體的問(wèn)題愈在后,否則就叫層次不清、邏輯混亂。
其規(guī)則是:愈抽象愈在前,愈具體愈在后。
實(shí)例:
碩士論文:最高額抵押權(quán)研究
第一部分 最高額抵押權(quán)的意義
第二部分 最高額抵押權(quán)的歷史演進(jìn)
第三部分 最高額抵押權(quán)的設(shè)定
第四部分 最高額抵押權(quán)的效力
第五部分 最高額抵押權(quán)的確定
第六部分 最高額抵押權(quán)的消滅
其第一、二部分屬于總論;第三至第六部分屬于分論。其分論的結(jié)構(gòu)顯然符合純粹邏輯的遞進(jìn)關(guān)系。須注意的是,在一篇論文中,尤其是長(zhǎng)篇專(zhuān)題研究論文、碩士論文、博士論文,不是只反映一種遞進(jìn)關(guān)系形態(tài),可能某一編、某一章內(nèi)部是時(shí)間上的遞進(jìn)關(guān)系,另外的編、章內(nèi)部是邏輯上的遞進(jìn)關(guān)系。
關(guān)于本論部分的邏輯關(guān)系,還有一個(gè)要求是要有重點(diǎn),避免等分式、無(wú)重點(diǎn)、面面俱到和過(guò)分枝蔓。我上研究生的時(shí)候,研究生院院長(zhǎng)溫濟(jì)澤教授作報(bào)告,講到學(xué)術(shù)論文寫(xiě)作多次引用前人的詩(shī)句:“刪繁就簡(jiǎn)三秋樹(shù),領(lǐng)異標(biāo)新二月花”。前一句就是指,文章的結(jié)構(gòu),要避免過(guò)分枝蔓,要突出重點(diǎn)。
下面舉不合邏輯的實(shí)例:
實(shí)例1:
碩士論文:著作權(quán)若干問(wèn)題研究
一、著作權(quán)的成因、發(fā)展和不同制度比較;
二、我國(guó)著作權(quán)制度的歷史、現(xiàn)狀和立法構(gòu)想;
三、著作權(quán)若干問(wèn)題的具體探究。
評(píng)論:
問(wèn)題在于邏輯關(guān)系混亂,第一部分的成因、發(fā)展、不同制度比較與第二部分的歷史、現(xiàn)狀是重復(fù)的;立法構(gòu)想應(yīng)該在整個(gè)研究完成之后提出,卻安排在第二部分,全部研究未完成,尤其對(duì)著作權(quán)的若干基本問(wèn)題還未研究清楚,就提出立法構(gòu)想,也不合邏輯。
實(shí)例2:
碩士論文:論新聞侵權(quán)為題的碩士論文
第一章 新聞侵權(quán)概述
第二章 新聞侵害名譽(yù)權(quán)的民事責(zé)任
第三章 新聞侵害隱私權(quán)的民事責(zé)任
第四章 新聞侵害肖像權(quán)的民事責(zé)任
第五章 新聞侵權(quán)民事責(zé)任主體
第六章 新聞侵權(quán)損害的救濟(jì)方式
評(píng)論:
問(wèn)題在于總分顛倒,第二、三、四章屬于分論,卻安排在前面,第五章新聞侵權(quán)的責(zé)任主體和第六章救濟(jì)方式應(yīng)當(dāng)屬于總論,卻安排在后面。
實(shí)例3:
碩士論文:論企業(yè)集團(tuán)的法律地位
一、企業(yè)集團(tuán)產(chǎn)生的客觀必然性;
二、企業(yè)集團(tuán)的概念;
三、企業(yè)集團(tuán)的類(lèi)型及其規(guī)范化;
四、企業(yè)集團(tuán)的法律地位是由其內(nèi)外關(guān)系決定的;
五、問(wèn)題與對(duì)策。
評(píng)論:
問(wèn)題是各部分邏輯關(guān)系混亂。連什么是企業(yè)集團(tuán)都未介紹,一開(kāi)頭就講客觀必然性,不合思維習(xí)慣和邏輯。思維習(xí)慣和邏輯是,先講“是什么”,再講“為什么”。概念屬于“是什么”,本應(yīng)當(dāng)在前面,卻安排在第二部分。客觀必然性屬于“為什么”,本應(yīng)當(dāng)在后面。第四部分是一個(gè)完整的句子,與標(biāo)題不合,標(biāo)題不能是句子,再說(shuō)也與其他部分不協(xié)調(diào)。
實(shí)例4:
碩士論文:論時(shí)效制度
一、對(duì)時(shí)效制度的歷史考察
二、關(guān)于消滅時(shí)效效力的探討
三、我國(guó)民法是否需要設(shè)立取得時(shí)效制度
四、對(duì)完善我國(guó)民法時(shí)效制度的設(shè)想
五、時(shí)效完成后義務(wù)人的履行
六、除斥期間
評(píng)論:
同樣邏輯混亂,第三、四部分交叉、重復(fù),層次不清,第六部分除斥期間屬于課題之外的問(wèn)題。
實(shí)例5:
碩士論文:論民法的締約過(guò)失責(zé)任
一、締約過(guò)失責(zé)任的由來(lái)
二、締約過(guò)失責(zé)任的幾個(gè)基本理論問(wèn)題
三、英美法系的締約過(guò)失責(zé)任――非合同義務(wù)
四、締約過(guò)失責(zé)任的新發(fā)展與合同預(yù)備性文件的效力
五、我國(guó)締約過(guò)失責(zé)任的理論與實(shí)踐
評(píng)論:
存在的問(wèn)題是邏輯混亂:“締約過(guò)失責(zé)任”是否包括英美法系的締約過(guò)失責(zé)任?如果回答是肯定的,則何以單獨(dú)論及英美法系的締約過(guò)失責(zé)任,而未專(zhuān)門(mén)論及大陸法系的締約過(guò)失責(zé)任?如果回答是否定的,即締約過(guò)失責(zé)任僅指大陸法系的制度,則何以在研究過(guò)程的中間,突然提出英美法系的締約過(guò)失責(zé)任問(wèn)題?
實(shí)例6: 碩士論文:保證責(zé)任研究
一、保證責(zé)任的成立;
二、保證責(zé)任的性質(zhì);
三、保證責(zé)任的范圍;
四、保證責(zé)任的方式;
五、保證責(zé)任的期間;
六、保證責(zé)任的消滅。
評(píng)論:
相對(duì)而言,成立、范圍、方式、期間、消滅都是具體的,唯性質(zhì)是抽象的。而將性質(zhì)安排在成立之后、范圍等之前,違背了“愈抽象愈在前”的規(guī)則,造成邏輯混亂。如果在前面設(shè)一個(gè)部分:保證責(zé)任概述,在其中論及責(zé)任性質(zhì),就合乎邏輯了。
實(shí)例7:
碩士論文:融資性租賃合同研究
一、融資性租賃合同的概念及特征;
二、融資性租賃合同的訂立及條款;
三、融資性租賃合同的擔(dān)保;
四、融資性租賃合同責(zé)任。
評(píng)論:
按照思維的邏輯習(xí)慣,一提到合同的訂立,馬上會(huì)想到合同的生效、合同的履行,這也正是事物本身的邏輯。但本文在論及訂立之后,卻未論及合同的生效、合同的履行等問(wèn)題,而僅研究合同的擔(dān)保。其邏輯難謂合理、嚴(yán)密。
實(shí)例8:
碩士論文:論農(nóng)地承包經(jīng)營(yíng)權(quán)
第一部分 農(nóng)地承包經(jīng)營(yíng)權(quán)的基本特點(diǎn)和主要缺點(diǎn)
第二部分 農(nóng)地承包經(jīng)營(yíng)權(quán)的革新
(一)第三部分 農(nóng)地承包經(jīng)營(yíng)權(quán)的革新
(二)第四部分 他國(guó)(地區(qū))農(nóng)地使用制度與農(nóng)業(yè)發(fā)展的經(jīng)驗(yàn)介紹
第五部分 農(nóng)地承包經(jīng)營(yíng)權(quán)規(guī)范化建構(gòu)的制約因素及其發(fā)展態(tài)勢(shì)分析
第六部分 農(nóng)地承包經(jīng)營(yíng)權(quán)目標(biāo)模式的建構(gòu)
評(píng)論:
問(wèn)題是,先講中國(guó),后講外國(guó),最后再來(lái)講中國(guó),違反先外國(guó)后本國(guó)的空間上的遞進(jìn)關(guān)系。邏輯關(guān)系是混亂的。
實(shí)例9:
碩士論文:加害給付研究
第一章 德國(guó)法中的積極侵害債權(quán)
第二章 中國(guó)法的加害給付
第三章 加害給付的構(gòu)成要件及法律效果
第四章 民事責(zé)任競(jìng)合概述及責(zé)任比較
第五章 外國(guó)民事責(zé)任競(jìng)合處理
第六章 中國(guó)法的責(zé)任競(jìng)合
評(píng)論:
問(wèn)題是題目確定的研究范圍不能涵蓋第四、五、六章的“民事責(zé)任競(jìng)合”,各章之間邏輯關(guān)系不清。
實(shí)例10:
碩士論文:我國(guó)合同解除制度立法研究:
第一章 關(guān)于合同解除的歷史考察
第二章 我國(guó)現(xiàn)行合同法關(guān)于合同解除的規(guī)定及其問(wèn)題
第三章 合同解除的概念和意義
第四章 解除權(quán)的性質(zhì)、種類(lèi)與發(fā)生原因
第五章 行使法定解除權(quán)的原因
第六章 行使解除權(quán)的方法
第七章 合同解除的效力
第八章 合同解除權(quán)的消滅
評(píng)論:
問(wèn)題主要是第二章我國(guó)現(xiàn)行合同法關(guān)于我國(guó)合同解除的規(guī)定及其問(wèn)題,本應(yīng)當(dāng)安排在本文最后予以分析并提出對(duì)策建議,卻安排在第二章,不符合邏輯思維順序和習(xí)慣,破壞了其他各章從遠(yuǎn)到近、從抽象到具體的遞進(jìn)關(guān)系。
6、對(duì)各部分標(biāo)題的要求
第一項(xiàng)要求:標(biāo)題應(yīng)當(dāng)是名詞或名詞性短語(yǔ),不能是一個(gè)句子
第二項(xiàng)要求:標(biāo)題只確定本部分的研究對(duì)象,不表達(dá)作者觀點(diǎn)
第三項(xiàng)要求:標(biāo)題應(yīng)明確、簡(jiǎn)短而忌冗長(zhǎng)
第四項(xiàng)要求:標(biāo)題應(yīng)當(dāng)出現(xiàn)題目中的關(guān)鍵詞
第五項(xiàng)要求:同一層次的各標(biāo)題應(yīng)相互協(xié)調(diào)
實(shí)例1:
博士論文:荷蘭國(guó)際私法研究
第一章 荷蘭國(guó)際私法概述
第二章 荷蘭與國(guó)際私法統(tǒng)一化
第三章 荷蘭國(guó)際私法法典化編纂
評(píng)論:
我們看到各章的標(biāo)題,都是名詞性短語(yǔ),而不是句子,符合第一項(xiàng)要求;各標(biāo)題只是確定本章研究對(duì)象或范圍,而不表達(dá)作者觀點(diǎn),符合第二項(xiàng)要求;各標(biāo)題符合明確、簡(jiǎn)短而不冗長(zhǎng)的第三項(xiàng)要求;論文題目中的關(guān)鍵詞,亦即“動(dòng)賓結(jié)構(gòu)”中的名詞“國(guó)際私法”,在各章標(biāo)題中重復(fù)出現(xiàn),這也就是所謂“切題”,符合第四項(xiàng)要求;各標(biāo)題結(jié)構(gòu)、長(zhǎng)短比較協(xié)調(diào),符合第五項(xiàng)要求。
再看其中第一章下面的各節(jié):
第一節(jié) 荷蘭國(guó)際私法的概念
第二節(jié) 荷蘭國(guó)際私法的淵源
第三節(jié) 荷蘭國(guó)際私法的性質(zhì)
第四節(jié) 荷蘭國(guó)際私法的歷史發(fā)展
同樣符合關(guān)于標(biāo)題的五項(xiàng)要求。
實(shí)例2:
博士論文為例:責(zé)任保險(xiǎn)論
第一章 責(zé)任保險(xiǎn)概述
第二章 責(zé)任保險(xiǎn)的分類(lèi)
第三章 責(zé)任保險(xiǎn)合同
第四章 責(zé)任保險(xiǎn)人的給付責(zé)任
第五章 責(zé)任保險(xiǎn)的第三人
第六章(責(zé)任保險(xiǎn)的)抗辯與和解的控制
第七章 責(zé)任保險(xiǎn)人的抗辯義務(wù)
第八章 責(zé)任保險(xiǎn)與再保險(xiǎn)
評(píng)論:
同樣符合上述五項(xiàng)要求。須補(bǔ)充的是,在章節(jié)標(biāo)題設(shè)計(jì)上,可能出現(xiàn)在一個(gè)標(biāo)題中有兩個(gè)名詞性短語(yǔ),亦即一個(gè)章、節(jié)可以有兩個(gè)或三個(gè)研究對(duì)象。在節(jié)以下層次的標(biāo)題,第三項(xiàng)要求,可以不象章、節(jié)(特別是章)那樣嚴(yán)格。再就是,有的論文章標(biāo)題似未重復(fù)論文題目中的關(guān)鍵詞,而直接采用論文題目關(guān)鍵詞的下位概念,以作為各章標(biāo)題的賓語(yǔ)短語(yǔ)。
實(shí)例3:
博士論文為例:國(guó)際貨幣基金協(xié)定研究 第四章 國(guó)際收支平衡的法律制度研究
第五章 國(guó)際儲(chǔ)備的法律制度研究
第六章 匯兌安排國(guó)際法律制度研究
第七章 外匯管制法律問(wèn)題研究
第八章 基金協(xié)定的監(jiān)督與磋商機(jī)制研究
評(píng)論:
實(shí)際上可以認(rèn)為,各章標(biāo)題中省略了論文題目中的關(guān)鍵詞“國(guó)際貨幣基金協(xié)定”:
第五章(國(guó)際貨幣基金協(xié)定中的)國(guó)際收支平衡的法律制度研究
第六章(國(guó)際貨幣基金協(xié)定中的)國(guó)際儲(chǔ)備的法律制度研究
第七章(國(guó)際貨幣基金協(xié)定中的)匯兌安排國(guó)際法律制度研究
第八章(國(guó)際貨幣基金協(xié)定中的)外匯管制法律問(wèn)題研究
第九章(國(guó)際貨幣)基金協(xié)定的監(jiān)督與磋商機(jī)制研究
不適當(dāng)?shù)膶?shí)例1:
博士論文:論私法對(duì)國(guó)際法的影響
第一章 萬(wàn)民法與國(guó)際法
第二章 人或主體
第三章 領(lǐng)土主權(quán)與所有權(quán)
第四章 條約與契約
評(píng)論:
問(wèn)題是不符合關(guān)于標(biāo)題的第三項(xiàng)要求:各章標(biāo)題中沒(méi)有出現(xiàn)論文題目中的關(guān)鍵詞,因此給人的印象是不切題。如果對(duì)各章標(biāo)題的文字作一些調(diào)整,效果就會(huì)不同:
第一章 萬(wàn)民法與國(guó)際法
第二章 私法主體與國(guó)際法主體
第三章 私法所有權(quán)與國(guó)際法領(lǐng)土主權(quán)
第四章 私法契約與國(guó)際法條約
不適當(dāng)?shù)膶?shí)例2:
碩士論文:論物權(quán)立法
其第三部分 我國(guó)現(xiàn)實(shí)歷史條件下物權(quán)立法之必要性研討
第一節(jié) 建立我國(guó)完整統(tǒng)一的物權(quán)制度是馬克思所有權(quán)理論的必然要求
第二節(jié) 建立完整統(tǒng)一的物權(quán)制度是我國(guó)現(xiàn)經(jīng)濟(jì)基礎(chǔ)的客觀要求
第三節(jié) 建立完整而統(tǒng)一的物權(quán)制度是我國(guó)現(xiàn)實(shí)司法實(shí)務(wù)更有利于保護(hù)公民法人的合法權(quán)益的客觀要求
評(píng)論:
存在的問(wèn)題是,標(biāo)題不是一個(gè)名詞性短語(yǔ),而是一個(gè)完整的句子,違背第一項(xiàng)要求;不是確定各節(jié)研究對(duì)象、研究范圍,而是直接表達(dá)作者觀點(diǎn),違背第二項(xiàng)要求;各標(biāo)題十分冗長(zhǎng),第三節(jié)標(biāo)題長(zhǎng)達(dá)41個(gè)字,顯然違背第四項(xiàng)要求;第一節(jié)標(biāo)題“建立我國(guó)完整統(tǒng)一的”,第二節(jié)標(biāo)題“建立完整統(tǒng)一的”,第三節(jié)標(biāo)題“建立完整而統(tǒng)一的”,甚不協(xié)調(diào),違背第五項(xiàng)要求。
如果作下述調(diào)整,效果將會(huì)改觀:
第一節(jié) 從馬克思所有權(quán)理論看我國(guó)物權(quán)立法
第二節(jié) 從現(xiàn)實(shí)經(jīng)濟(jì)基礎(chǔ)看我國(guó)物權(quán)立法
第三節(jié) 從公民法人合法權(quán)益保護(hù)看我國(guó)物權(quán)立法
結(jié)語(yǔ)
碩士論文、博士論文的結(jié)構(gòu),除導(dǎo)論、本論、結(jié)論三部分外,前面必須有目錄,還可以有序言。后面必須有參考著作目錄,可以再寫(xiě)個(gè)后記。后記的內(nèi)容沒(méi)有一定之規(guī),通常是致謝及發(fā)感慨。
阿道夫 的 范德薩 啊訂單式
第三篇:關(guān)于分析今天長(zhǎng)安保定百度愛(ài)問(wèn)愛(ài)第2章代碼初識(shí) 本章首先從較高層次
的的范德薩的地方愛(ài)的規(guī)格愛(ài)你啊好文章第2章 代 碼 初 識(shí)
本章首先從較高層次介紹Linux內(nèi)核源程序的概況,這些都是大家關(guān)心的一些基本特點(diǎn)。隨后將簡(jiǎn)要介紹一些實(shí)際代碼。最后介紹如何編譯內(nèi)核。2.1 Linux內(nèi)核源程序的部分特點(diǎn)
在過(guò)去的一段時(shí)期,Linux內(nèi)核同時(shí)使用C語(yǔ)言和匯編語(yǔ)言來(lái)實(shí)現(xiàn)。這兩種語(yǔ)言需要一定的平衡:C語(yǔ)言編寫(xiě)的代碼移植性較好、易于維護(hù),而匯編語(yǔ)言編寫(xiě)的程序則速度較快。一般只有在速度是關(guān)鍵因素或者一些因平臺(tái)相關(guān)特性而產(chǎn)生的特殊要求(例如直接和內(nèi)存管理硬件進(jìn)行通訊)時(shí)才使用匯編語(yǔ)言。
正如實(shí)際中所做的,即使內(nèi)核并未使用C++的對(duì)象特性,部分內(nèi)核也可以在g++(GNU的C++編譯器)下進(jìn)行編譯。同其他面向?qū)ο蟮木幊陶Z(yǔ)言相比較,相對(duì)而言C++的開(kāi)銷(xiāo)是較低的,但是對(duì)于內(nèi)核開(kāi)發(fā)人員來(lái)說(shuō),這已經(jīng)是太多了。
內(nèi)核開(kāi)發(fā)人員不斷發(fā)展編程風(fēng)格,形成了Linux代碼獨(dú)有的特色。本節(jié)將討論其中的一些問(wèn)題。
2.1.1 gcc特性的使用
Linux內(nèi)核被設(shè)計(jì)為必須使用GNU的C編譯器gcc來(lái)編譯,而不是任何一種C編譯器都可以使用。內(nèi)核代碼有時(shí)要使用gcc特性,本書(shū)將陸續(xù)介紹其中的一部分。一些gcc特有代碼只是簡(jiǎn)單地使用gcc語(yǔ)言擴(kuò)展,例如允許在C(不只是C++)中使用inline關(guān)鍵字指示內(nèi)聯(lián)函數(shù)。也就是說(shuō),代碼中被調(diào)用的函數(shù)在每次函數(shù)調(diào)用時(shí)都會(huì)被擴(kuò)充,因而就可以節(jié)約實(shí)際函數(shù)調(diào)用的開(kāi)銷(xiāo)。
一般情況下,代碼的編寫(xiě)方式比較復(fù)雜。因?yàn)閷?duì)于某些類(lèi)型的輸入,gcc能夠產(chǎn)生比其他輸入效率更高的執(zhí)行代碼。從理論上講,編譯器可以?xún)?yōu)化具有相同功能的兩種對(duì)等的方法,并且得到相同的結(jié)果。因此,代碼的編寫(xiě)方式是無(wú)關(guān)緊要的。但在實(shí)際上,用某種方法編寫(xiě)所產(chǎn)生的代碼要比用另外一些方法編寫(xiě)所產(chǎn)生的代碼執(zhí)行速度快許多。內(nèi)核開(kāi)發(fā)人員知道怎樣才能產(chǎn)生更高效的執(zhí)行代碼,這不斷地在他們編寫(xiě)的代碼中反映出來(lái)。例如,考慮內(nèi)核中經(jīng)常使用的goto語(yǔ)句—為了提高速度,內(nèi)核中經(jīng)常大量使用這種一般要避免使用的語(yǔ)句。在本書(shū)中所包含的不到40 000行代碼中,一共有500多條goto語(yǔ)句,大約是每80行一個(gè)。除匯編文件外,精確的統(tǒng)計(jì)數(shù)字是接近每72行一個(gè)goto語(yǔ)句。公平地說(shuō),這是選擇偏向的結(jié)果:比例如此高的原因之一是本書(shū)中涉及的是內(nèi)核源程序的核心,在這里速度比其他因素都需要優(yōu)先考慮。整個(gè)內(nèi)核的比例大概是每260行一個(gè)goto語(yǔ)句。然而,這仍然是我不再使用Basic進(jìn)行編程以來(lái)見(jiàn)過(guò)的使用goto頻率最高的地方。
代碼必需受特定編譯器限制的特性不僅與普通應(yīng)用程序的開(kāi)發(fā)有很大不同,而且也不同于大多數(shù)內(nèi)核的開(kāi)發(fā)。大多數(shù)的開(kāi)發(fā)人員使用C語(yǔ)言編寫(xiě)代碼來(lái)保持較高的可移植性,即使在編寫(xiě)操作系統(tǒng)時(shí)也是如此。這樣做的優(yōu)點(diǎn)是顯而易見(jiàn)的,最為重要的一點(diǎn)是一旦出現(xiàn)更好的編譯器,程序員們可以隨時(shí)進(jìn)行更換。
內(nèi)核對(duì)于gcc特性的完全依賴(lài)使得內(nèi)核向新的編譯器上移植更加困難。最近Linus對(duì)這一問(wèn)題在有關(guān)內(nèi)核的郵件列表上表明了自己的觀點(diǎn):“記住,編譯器只是一個(gè)工具。”這是對(duì)依賴(lài)于gcc特性的一個(gè)很好的基本思想的表述:編譯器只是為了完成工作。如果通過(guò)遵守標(biāo)準(zhǔn)還不能達(dá)到工作要求,那么就不是工作要求有問(wèn)題,而是對(duì)于標(biāo)準(zhǔn)的依賴(lài)有問(wèn)題。
在大多數(shù)情況下,這種觀點(diǎn)是不能被人所接受的。通常情況下,為了保證和程序語(yǔ)言標(biāo)準(zhǔn)的一致,開(kāi)發(fā)人員可能需要犧牲某些特性、速度或者其他相關(guān)因素。其他的選擇可能會(huì)為后期開(kāi)發(fā)造成很大的麻煩。
但是,在這種特定的情況下,Linus是正確的。Linux內(nèi)核是一個(gè)特例,因?yàn)槠鋱?zhí)行速度要比向其他編譯器的可移植性遠(yuǎn)為重要。如果設(shè)計(jì)目標(biāo)是編寫(xiě)一個(gè)可移植性好而不要求快速運(yùn)行的內(nèi)核,或者是編寫(xiě)一個(gè)任何人都可以使用自己喜歡的編譯器進(jìn)行編譯的內(nèi)核,那么結(jié)論就可能會(huì)有所不同了;而這些恰好不是Linux的設(shè)計(jì)目標(biāo)。實(shí)際上,gcc幾乎可以為所有能夠運(yùn)行Linux的CPU生成代碼,因此,對(duì)于gcc的依賴(lài)并不是可移植性的嚴(yán)重障礙。在第3章中我們將對(duì)內(nèi)核設(shè)計(jì)目標(biāo)進(jìn)行詳細(xì)說(shuō)明。2.1.2 內(nèi)核代碼習(xí)慣用語(yǔ)
內(nèi)核代碼中使用了一些顯著的習(xí)慣用語(yǔ),本節(jié)將介紹常用的幾個(gè)。當(dāng)通讀源代碼時(shí),真正重要的問(wèn)題并不在這些習(xí)慣用語(yǔ)本身,而是這種類(lèi)型的習(xí)慣用語(yǔ)的確存在,而且是不斷被使用和發(fā)展的。如果你需要編寫(xiě)內(nèi)核代碼,你應(yīng)該注意到內(nèi)核中所使用的習(xí)慣用語(yǔ),并把這些習(xí)慣用語(yǔ)應(yīng)用到你的代碼中。當(dāng)通讀本書(shū)(或者代碼)時(shí),看看你還能找到多少習(xí)慣用語(yǔ)。為了討論這些習(xí)慣用語(yǔ),我們首先需要對(duì)它們進(jìn)行命名。為了便于討論,筆者創(chuàng)造了這些名字。而在實(shí)際中,大家不一定非要參考這些用語(yǔ),它們只是對(duì)內(nèi)核工作方式的描述而已。一個(gè)普通的習(xí)慣用語(yǔ),筆者稱(chēng)之為“資源獲取”(resource acquisition idiom)。在這個(gè)用語(yǔ)中,一個(gè)函數(shù)必須實(shí)現(xiàn)一系列資源的獲取,包括內(nèi)存、鎖等等(這些資源的類(lèi)型未必相同)。只有成功地獲取當(dāng)前所需要的資源之后,才能處理后面的資源請(qǐng)求。最后,該函數(shù)還必須釋放所有已經(jīng)獲取的資源,而不必考慮沒(méi)有獲取的資源。
我采用“錯(cuò)誤變量”這一用語(yǔ)(error variable idiom)來(lái)輔助說(shuō)明資源獲取用語(yǔ),它使用一個(gè)臨時(shí)變量來(lái)記錄函數(shù)的期望返回值。當(dāng)然,相當(dāng)多的函數(shù)都能實(shí)現(xiàn)這個(gè)功能。但是錯(cuò)誤變量的不同點(diǎn)在于它通常是用來(lái)處理由于速度的因素而變得非常復(fù)雜的流程控制中的問(wèn)題。錯(cuò)誤變量有兩個(gè)典型的值,0(表示成功)和負(fù)數(shù)(表示有錯(cuò))。
這兩個(gè)用語(yǔ)結(jié)合使用,我們就可以十分自然地得到符合模式的代碼如下:
(注意變量err是使用錯(cuò)誤變量的一個(gè)明確實(shí)例,同樣,諸如out之類(lèi)的標(biāo)號(hào)則指明了資源獲取用語(yǔ)的使用。)
如果執(zhí)行到標(biāo)號(hào)out2,則都已經(jīng)獲取了r1和r2資源,而且也都需要進(jìn)行釋放。如果執(zhí)行到標(biāo)號(hào)out1(不管是順序執(zhí)行還是使用goto語(yǔ)句進(jìn)行跳轉(zhuǎn)到),則r2資源是無(wú)效的(也可能剛被釋放),但是r1資源卻是有效的,而且必需在此將其釋放。同理,如果標(biāo)號(hào)out能被執(zhí)行,則r1和r2資源都無(wú)效,err所返回的是錯(cuò)誤或成功標(biāo)志。
在這個(gè)簡(jiǎn)單的例子中,對(duì)err的一些賦值是沒(méi)有必要的。在實(shí)踐中,實(shí)際代碼必須遵守這種模式。這樣做的原因主要在于同一行中可能包含有多種測(cè)試,而這些測(cè)試應(yīng)該返回相同的錯(cuò)誤代碼,因此對(duì)錯(cuò)誤變量統(tǒng)一賦值要比多次賦值更為簡(jiǎn)單。雖然在這個(gè)例子中對(duì)于這種屬性的必要性并不非常迫切,但是我還是傾向于保留這種特點(diǎn)。有關(guān)的實(shí)際應(yīng)用可以參考sys_shmctl(第21654行),在第9章中還將詳細(xì)介紹這個(gè)例子。2.1.3 減少#if和#ifdef的使用
現(xiàn)在的Linux內(nèi)核已經(jīng)移植到不同的平臺(tái)上,但是我們還必須解決移植過(guò)程中所出現(xiàn)的問(wèn)題。大部分支持各種不同平臺(tái)的代碼由于包含許多預(yù)處理代碼而已經(jīng)變得非常不規(guī)范,例如: 這個(gè)例子試圖實(shí)現(xiàn)操作系統(tǒng)的可移植性,雖然Linux關(guān)注的焦點(diǎn)很明顯是實(shí)現(xiàn)代碼在各種CPU上的可移植性,但是二者的基本原理是一致的。對(duì)于這類(lèi)問(wèn)題來(lái)說(shuō),預(yù)處理器是一種錯(cuò)誤的解決方式。這些雜亂的問(wèn)題使得代碼晦澀難懂。更為糟糕的是,增加對(duì)新平臺(tái)的支持有可能要求重新遍歷這些雜亂分布的低質(zhì)量代碼段(實(shí)際上你很難能找到這類(lèi)代碼段的全部)。與現(xiàn)有方式不同的是,Linux一般通過(guò)簡(jiǎn)單函數(shù)(或者是宏)調(diào)用來(lái)抽象出不同平臺(tái)間的差異。內(nèi)核的移植可以通過(guò)實(shí)現(xiàn)適合于相應(yīng)平臺(tái)的函數(shù)(或宏)來(lái)實(shí)現(xiàn)。這樣不僅使代碼的主體簡(jiǎn)單易懂,而且在移植的過(guò)程中還可以比較容易地自動(dòng)檢測(cè)出你沒(méi)有注意到的內(nèi)容:如引用未聲明函數(shù)時(shí)會(huì)出現(xiàn)鏈接錯(cuò)誤。有時(shí)用預(yù)處理器來(lái)支持不同的體系結(jié)構(gòu),但這種方式并不常用,而相對(duì)于代碼風(fēng)格的變化就更是微不足道了。
順便說(shuō)一下,我們可以注意到這種解決方法和使用用戶(hù)對(duì)象(或者C語(yǔ)言中充滿函數(shù)指針的struct結(jié)構(gòu))來(lái)代替離散的switch語(yǔ)句處理不同類(lèi)型的方法十分相似。在某些層次上,這些問(wèn)題和解決方法是統(tǒng)一的。
可移植性的問(wèn)題并不僅限于平臺(tái)和CPU的移植,編譯器也是一個(gè)重要的問(wèn)題。此處為了簡(jiǎn)化,假設(shè)Linux只使用gcc來(lái)編譯。由于Linux只使用同一個(gè)編譯器,所以就沒(méi)有必要使用#if塊(或者#ifdef塊)來(lái)選擇不同的編譯器。
內(nèi)核代碼主要使用#ifdef來(lái)區(qū)分需要編譯或不需要編譯的部分,從而對(duì)不同的結(jié)構(gòu)提供支持。例如,代碼經(jīng)常測(cè)試SMP宏是否定義過(guò),從而決定是否支持SMP機(jī)。2.2 代碼樣例
了解Linux代碼風(fēng)格最好的方法就是實(shí)際研究一下它的部分代碼。即使你不完全理解本節(jié)所討論代碼的細(xì)節(jié)也無(wú)關(guān)緊要,畢竟本節(jié)的主要目的不是理解代碼,一些讀者可以只對(duì)本節(jié)進(jìn)行瀏覽。本節(jié)的主要目的是讓讀者對(duì)Linux代碼進(jìn)行初步了解,為今后的工作提供必要基礎(chǔ)。該討論將涉及部分廣泛使用的內(nèi)核代碼。2.2.1 printk printk(25836行)是內(nèi)核內(nèi)部消息日志記錄函數(shù)。在出現(xiàn)諸如內(nèi)核檢測(cè)到其數(shù)據(jù)結(jié)構(gòu)出現(xiàn)不一致的事件時(shí),內(nèi)核會(huì)使用printk把相關(guān)信息打印到系統(tǒng)控制臺(tái)上。對(duì)于printk的調(diào)用一般分為如下幾類(lèi):
?緊急事件(emergency)—例如,panic函數(shù)(25563行)多次使用了printk。當(dāng)內(nèi)核檢測(cè)到發(fā)生不可恢復(fù)的內(nèi)部錯(cuò)誤時(shí)就會(huì)調(diào)用panic函數(shù),然后盡其所能地安全關(guān)閉計(jì)算機(jī)。這個(gè)函數(shù)中調(diào)用printk以提示用戶(hù)系統(tǒng)將要關(guān)閉。
?調(diào)試—從3816行開(kāi)始的#ifdef塊使用printk來(lái)打印SMP邏輯單元(box)中每一個(gè)處理器的相關(guān)配置信息,但是此過(guò)程只有在使用SMP_DEBUG標(biāo)志編譯代碼的情況下才能夠被執(zhí)行。?普通信息—例如,當(dāng)機(jī)器啟動(dòng)時(shí),內(nèi)核必須估計(jì)系統(tǒng)速度以確保設(shè)備驅(qū)動(dòng)程序能夠忙等待(busy-wait)一個(gè)精確的極短周期。計(jì)算這種估計(jì)值的函數(shù)名為calibrate_delay(19654行),它既在19661行使用printk聲明馬上開(kāi)始計(jì)算,又在19693行報(bào)告計(jì)算結(jié)果。另外,在第4章將詳細(xì)的介紹calibrate_delay函數(shù)。
如果你已經(jīng)瀏覽過(guò)這些參照行,你可能已經(jīng)注意到printk和printf的參數(shù)十分類(lèi)似:一個(gè)格式化字符串,后跟零個(gè)或者多個(gè)參數(shù)加入字符串中。格式化字符串可能是以一組“
從14946行開(kāi)始的#define塊說(shuō)明了這些特殊序列,這些定義可以幫助調(diào)用者正確區(qū)分對(duì)printk的調(diào)用。簡(jiǎn)單地說(shuō),我稱(chēng)日志等級(jí)0到4為“緊急事件”,等級(jí)5到等級(jí)6為“普通信息”,等級(jí)7自然就是我所說(shuō)的“調(diào)試”(這種分類(lèi)方法并不意味著其他更好的分類(lèi)方法沒(méi)有用處,而只是目前我們還不關(guān)心它而已)。在上面討論的基礎(chǔ)上,我們研究一下代碼本身。printk 25836:參數(shù)fmt是printf類(lèi)型的格式化字符串。如果你對(duì)“...”部分的內(nèi)容不熟悉,那就 需要參閱一本好的C語(yǔ)言參考書(shū)(在其索引中查找“變參函數(shù),variadic function”)。另外,在安裝的GNU/Linux中的stdarg幫助里也包含了一個(gè)有關(guān)變參函數(shù)的簡(jiǎn)明描述,在這兒只需要敲入“man stdarg”就可以看到。簡(jiǎn)單地說(shuō),“...”部分提示編譯器fmt后面可能緊跟著數(shù)量不定的任何類(lèi)型的參數(shù)。由于這些參數(shù)在編譯的時(shí)候還沒(méi)有類(lèi)型和名字,內(nèi)核使用由三個(gè)宏va_start、va_arg和va_end組成的特殊組及一個(gè)特殊類(lèi)型—va_list對(duì)它們進(jìn)行處理。25842:msg_level記錄了當(dāng)前消息的日志等級(jí)。它是靜態(tài)的,這看起來(lái)可能會(huì)有些奇怪—為什么下一次對(duì)printk的調(diào)用需要記錄日志等級(jí)呢?問(wèn)題的答案是只有打印出新行(n)或者賦給一個(gè)新的日志等級(jí)序列以后,當(dāng)前消息才會(huì)結(jié)束。這樣,通過(guò)在包含消息結(jié)束的新行里調(diào)用printk,就保證了在多個(gè)短期沖突的情況下,調(diào)用者只打印唯一一個(gè)長(zhǎng)消息。
25845:在SMP邏輯單元中,內(nèi)核可能試圖從不同的CPU向控制臺(tái)同時(shí)打印信息(有時(shí)在單處理機(jī)(UP)邏輯單元中也會(huì)發(fā)生同樣問(wèn)題,但由于中斷還未被覆蓋掉,所以問(wèn)題也并不十分明顯)。如果不進(jìn)行任何協(xié)同的話,結(jié)果就將處于完全無(wú)法讓人了解的雜亂無(wú)章的狀態(tài),每個(gè)消息的各個(gè)部分都和其他消息的各個(gè)部分混雜交織在一起。
相反,內(nèi)核使用旋轉(zhuǎn)鎖(spin-lock)來(lái)控制對(duì)控制臺(tái)的訪問(wèn)。旋轉(zhuǎn)鎖將在第10章進(jìn)行深入介紹。
如果你對(duì)flags 在傳送給spin_lock_irqsave之前為什么不對(duì)它初始化感到疑惑,請(qǐng)不要擔(dān)心:spin_lock_irqsave(對(duì)于不同的版本請(qǐng)分別參看12614行,12637行,12716行和12837行)是一個(gè)宏,而不是一個(gè)函數(shù)。該宏實(shí)際上是將值寫(xiě)入flags中,而不是從flags中讀出值(在25895行中,存儲(chǔ)在flags中的信息被spin_unlock_irqrestore回讀,請(qǐng)參看12616行,12639行,12728行和12841行)。
25846:初始化變量args,該變量代表printk參數(shù)中的“...”部分。25848:調(diào)用內(nèi)核自身的vsprintf(為節(jié)省空間而省略)實(shí)現(xiàn)。該函數(shù)的功能與標(biāo)準(zhǔn)vsprintf函數(shù)非常相似,向buf中寫(xiě)入格式化文本(25634行)并返回寫(xiě)入字符串的長(zhǎng)度(長(zhǎng)度不包括最后一位終止字符0字節(jié))。很快,你將可以看到為什么這種機(jī)制會(huì)忽略buf的前三個(gè)字符。(正如25847行的注釋中所述)我們應(yīng)該注意到在這里并沒(méi)有采取嚴(yán)格的措施來(lái)保證緩沖器不會(huì)過(guò)載。這里系統(tǒng)假定1024個(gè)字符長(zhǎng)度的buf已經(jīng)足夠使用(參閱25634行)。如果內(nèi)核在這里能夠使用vsnprintf函數(shù)的話,情況就會(huì)好許多。然而,vsnprintf還有另外一個(gè)參數(shù)限制了它能夠?qū)懭刖彌_器的字符長(zhǎng)度。
25849:計(jì)算buf中最近使用的元素,調(diào)用va_end終止對(duì)“...”參數(shù)的處理。
25851:開(kāi)始格式化消息的循環(huán)。其中存在一個(gè)內(nèi)部循環(huán)能夠處理更多內(nèi)容(這一點(diǎn)隨后就能看到),因此,每次內(nèi)循環(huán)開(kāi)始,都開(kāi)始一個(gè)新的打印行。由于通常情況下printk只用于打印單行,所以在每次調(diào)用中,這種循環(huán)通常只執(zhí)行一次。
25853:如果預(yù)先不知道消息的日志等級(jí),printk會(huì)檢查當(dāng)前行是否以日志等級(jí)序列開(kāi)頭。25860:如果不是,buf中開(kāi)始未使用的三個(gè)字符就能夠起作用了(第一次以后的每次循環(huán),都會(huì)覆蓋部分消息文本,但是這樣并不會(huì)引起問(wèn)題,因?yàn)檫@里的文本只是前面行中的一部分,它們已經(jīng)被打印過(guò),而且以后也不再需要了)。這樣,就可以將日志等級(jí)插入buf中。25866:此處有如下屬性:p指向日志等級(jí)序列(消息文本緊隨其后),msg指向消息文本—請(qǐng)注意25852行和25865行中對(duì)msg的賦值。
由于已知p用來(lái)指示日志等級(jí)序列的開(kāi)頭—該日志等級(jí)序列可能是由函數(shù)自身所創(chuàng)建的,日志等級(jí)可以從p中抽出并存到msg_level中。25868:沒(méi)有檢測(cè)到新行,清空l(shuí)ine_feed標(biāo)志。
25869:這是前面談到過(guò)的內(nèi)循環(huán),循環(huán)將運(yùn)行到本行結(jié)束(也就是檢測(cè)到新行標(biāo)志)或者緩沖器的末尾為止。
25870:除了將消息打印到控制臺(tái)之外,printk還能夠記錄最近打印的長(zhǎng)度為L(zhǎng)OG_ BUF_LEN的字符組(LOG_BUF_LEN為16K,請(qǐng)參看25632行)。如果在控制臺(tái)打開(kāi)之前,內(nèi)核就已經(jīng)調(diào)用printk,則顯然不能在控制臺(tái)上正確打印消息,但是這些消息將被盡可能地存儲(chǔ)到log_buf中(25656行)。當(dāng)控制臺(tái)打開(kāi)以后,緩存在log_buf中的數(shù)據(jù)就可以轉(zhuǎn)儲(chǔ)并在控制臺(tái)上打印出來(lái),請(qǐng)參看25988行。
log_buf是一個(gè)循環(huán)緩沖器,log_start和log_size變量(25657行和25646行)分別記錄當(dāng)前緩沖器的開(kāi)始位置和長(zhǎng)度。本行中的按位與(AND)操作實(shí)際上是快速求模(%)運(yùn)算,它的正確性依賴(lài)于LOG_BUF_LEN的值是2的冪。25872:保存變量跟蹤記錄循環(huán)日志的值。顯然,日志大小會(huì)不斷增長(zhǎng),直至達(dá)到LOG_BUF_LEN的值為止。此后,log_size將保持不變,而插入新字符將導(dǎo)致log_start的增長(zhǎng)。
25878:請(qǐng)注意logged_chars(25658行)記錄從機(jī)器啟動(dòng)之后由printk寫(xiě)入的所有字符的長(zhǎng)度,它在每次循環(huán)中都會(huì)被更新,而不是在循環(huán)結(jié)束后才改變一次?;谕瑯拥牡览恚琹og_start和log_size的處理方式也是一樣。這實(shí)際上是一種優(yōu)化的時(shí)機(jī),本書(shū)將在結(jié)束對(duì)函數(shù)的介紹之后再對(duì)它進(jìn)行詳細(xì)討論。
25879:消息被分為若干行,這當(dāng)然要使用新行標(biāo)志符來(lái)進(jìn)行分割。一旦內(nèi)核檢測(cè)到新行標(biāo)志符,就寫(xiě)入一個(gè)完整行,從而內(nèi)循環(huán)的執(zhí)行也可以提前終止。25884:在這里我們先不考慮內(nèi)部循環(huán)是否會(huì)提前退出,從msg到p的字符序列是專(zhuān)門(mén)提供給控制臺(tái)使用的(這種字符序列我稱(chēng)之為行,但是不要忘了,這里的行可能并不意味著新行終止,因?yàn)閎uf也許還沒(méi)有終止)。如果該行的日志等級(jí)高于系統(tǒng)控制臺(tái)定義的日志等級(jí),而且當(dāng)前又有控制臺(tái)可供打印,那么就能夠正確打印該行。(記住,printk可能在所有控制臺(tái)打開(kāi)之前就已經(jīng)被調(diào)用過(guò)了。)
如果在該消息塊中沒(méi)有發(fā)現(xiàn)日志等級(jí)序列,并且在前面的printk調(diào)用中也沒(méi)有對(duì)msg_level賦值,那么本行中的msg_level就是-1。由于console_loglevel總不小于1(除非root通過(guò)sysctl接口鎖定),于是總是可以打印這些行。
25886:本行應(yīng)該能夠被打印。printk通過(guò)遍歷打開(kāi)的控制臺(tái)驅(qū)動(dòng)鏈表告知每一個(gè)控制臺(tái)驅(qū)動(dòng)去打印當(dāng)前行設(shè)備驅(qū)動(dòng)在本書(shū)的討論范圍之外,因此,控制臺(tái)驅(qū)動(dòng)代碼則并不包含在內(nèi))。25888:請(qǐng)注意這里消息文本的開(kāi)頭使用的是msg而不是p,這樣就在沒(méi)有日志等級(jí)序列的情況下寫(xiě)入消息了。然而,日志等級(jí)序列已經(jīng)被存儲(chǔ)到log_buf緩沖器中了。這樣就使后來(lái)能夠訪問(wèn)log_buf以獲取消息日志等級(jí)的代碼(請(qǐng)參看25998行),不會(huì)再產(chǎn)生顯示混亂信息序列的現(xiàn)象。
25892:如果內(nèi)層for循環(huán)發(fā)現(xiàn)一新行,那么buf中的剩余字符(如果有的話)將被認(rèn)為是新的消息,因此msg_level會(huì)被重置。但是無(wú)論怎樣,外層循環(huán)都會(huì)持續(xù)到buf清空為止。25895:釋放在25845行獲取的控制臺(tái)鎖(console lock)。
25896:?jiǎn)拘训却粚?xiě)入控制臺(tái)日志的所有進(jìn)程。注意即使沒(méi)有文本被實(shí)際寫(xiě)入任何控制臺(tái),這個(gè)過(guò)程也仍然會(huì)發(fā)生。這樣處理是正確的,因?yàn)闊o(wú)論是否要往控制臺(tái)中寫(xiě)入文本,等待進(jìn)程實(shí)際上都是在等待從log_buf中讀出信息。在25748行,進(jìn)程被轉(zhuǎn)入休眠狀態(tài)以等待log_buf的活動(dòng)。在休眠、喚醒和等待隊(duì)列中所使用的機(jī)制將在下一節(jié)中進(jìn)行討論。25897:返回日志中寫(xiě)入的字符長(zhǎng)度。
如果對(duì)于每個(gè)字符的處理工作都能減少一點(diǎn),那么從25869行開(kāi)始的for循環(huán)就執(zhí)行得更快一點(diǎn)。當(dāng)循環(huán)存在時(shí),我們可以通過(guò)只在循環(huán)退出時(shí)將logged_chars更新一次來(lái)稍微提高運(yùn)行速度。然而我們還可以通過(guò)其他努力來(lái)提高速度。由于我們可以預(yù)知消息的長(zhǎng)度,因此log_size和log_start可以到最后再增長(zhǎng)。讓我們來(lái)實(shí)驗(yàn)一下這樣能否提高速度,下面是一段經(jīng)過(guò)理想優(yōu)化的代碼:
請(qǐng)注意循環(huán)通常只需要執(zhí)行一次,只有在log_buf末尾寫(xiě)入信息需要折行時(shí)才會(huì)多次執(zhí)行。因而log_size和log_buf只需要更新一次(或者當(dāng)寫(xiě)入需要換行時(shí)是兩次)。
這時(shí)速度的確提高了,但是有兩個(gè)原因使我們并不能這樣做。首先,內(nèi)核可能有自己特有的memcpy函數(shù),我們必須確保對(duì)memcpy的調(diào)用不會(huì)再次進(jìn)入對(duì)printk的調(diào)用(有一部分內(nèi)核移植版定義了自己特有的速度較快的memcpy函數(shù)版本,因此所有的移植都要在這一點(diǎn)上保持一致)。如果memecpy調(diào)用printk來(lái)報(bào)告失敗,那么就有可能觸發(fā)無(wú)限循環(huán)。
然而在這一點(diǎn)上也并不是真的無(wú)藥可救。使用這種解決方案的最大問(wèn)題在于該內(nèi)核循環(huán)的形式中也要留意新行標(biāo)志符,因此使用memcpy將整個(gè)消息拷貝到log_buf中是不正確的:如果此處存在新行,我們將無(wú)法對(duì)其進(jìn)行處理。
我們可以試驗(yàn)一個(gè)一箭雙雕的辦法。下面這種替代的嘗試雖然可能比前面那種初步解決方法速度要慢,但是它保持了內(nèi)核版本的語(yǔ)意:
(請(qǐng)注意gcc的優(yōu)化器十分靈敏,它足以能檢測(cè)到循環(huán)內(nèi)部的表達(dá)式log_buf+LOG_BUF_LEN并沒(méi)有改變,因此在上面的循環(huán)中試圖手工加速計(jì)算是沒(méi)有任何效果的。)
不幸的是,這種方法并不能比現(xiàn)在的內(nèi)核版本在速度上快許多,而且那樣會(huì)使得代碼晦澀難懂(如果你編寫(xiě)過(guò)更新log_size和log_start的代碼,你就能清楚地了解這一點(diǎn))。你可以自己決定這種折衷是否值得。然而無(wú)論怎樣,我們學(xué)到了一些東西,通常,不管成功與否,改進(jìn)內(nèi)核代碼都可以加深你對(duì)內(nèi)核工作原理的理解。2.2.2 等待隊(duì)列
前一節(jié)我們?cè)?jiǎn)要的提到進(jìn)程(也就是正在運(yùn)行的程序)可以轉(zhuǎn)入休眠狀態(tài)以等待某個(gè)特定事件,當(dāng)該事件發(fā)生時(shí)這些進(jìn)程能夠被再次喚醒。內(nèi)核實(shí)現(xiàn)這一功能的技術(shù)要點(diǎn)是把等待隊(duì)列(wait queue)和每一個(gè)事件聯(lián)系起來(lái)。需要等待事件的進(jìn)程在轉(zhuǎn)入休眠狀態(tài)后插入到隊(duì)列中。當(dāng)事件發(fā)生之后,內(nèi)核遍歷相應(yīng)隊(duì)列,喚醒休眠的任務(wù)讓它投入運(yùn)行狀態(tài)。任務(wù)負(fù)責(zé)將自己從等待隊(duì)列中清除。
等待隊(duì)列的功能強(qiáng)大得令人吃驚,它們被廣泛應(yīng)用于整個(gè)內(nèi)核中。更重要的是,實(shí)現(xiàn)等待隊(duì)列的代碼量并不大。1.wait_queue結(jié)構(gòu)
18662:簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu)就是等待隊(duì)列節(jié)點(diǎn),它包含兩個(gè)元素: ?task—指向struct task_struct結(jié)構(gòu)的指針,它代表一個(gè)進(jìn)程。從16325行開(kāi)始的struct task_struct結(jié)構(gòu)將在第7章中進(jìn)行介紹。
?next—指向隊(duì)列中下一節(jié)點(diǎn)的指針。因而,等待隊(duì)列實(shí)際上是一個(gè)單鏈表。
通常,我們用指向等待隊(duì)列隊(duì)首的指針來(lái)表示等待隊(duì)列。例如,printk使用的等待隊(duì)列l(wèi)og_wait(25647行)。2.wait_event 16840:通過(guò)使用這個(gè)宏,內(nèi)核代碼能夠使當(dāng)前執(zhí)行的進(jìn)程在等待隊(duì)列wq中等待直至給定condition(可能是任何的表達(dá)式)得到滿足。
16842:如果條件已經(jīng)為真,當(dāng)前進(jìn)程顯然也就無(wú)需等待了。16844:否則,進(jìn)程必須等待給定條件轉(zhuǎn)變?yōu)檎?。這可以通過(guò)調(diào)用__wait_event來(lái)實(shí)現(xiàn)(16824行),我們將在下一節(jié)介紹它。由于__wait_event已經(jīng)同wait_event分離,已知條件為假的部分內(nèi)核代碼可以直接調(diào)用__wait_queue,而不用通過(guò)宏來(lái)進(jìn)行冗余的(特別是在這些情況下)測(cè)試,實(shí)際上也沒(méi)有代碼會(huì)真正這樣處理。更為重要的是,如果條件已經(jīng)為真,wait_event會(huì)跳過(guò)將進(jìn)程插入等待隊(duì)列的代碼。
注意wait_event的主體是用一個(gè)比較特殊的結(jié)構(gòu)封閉起來(lái)的:
奇怪的是,這個(gè)小技巧并沒(méi)有得到應(yīng)有的重視。這里的主要思路是使被封閉的代碼能夠像一個(gè)單句一樣使用??紤]下面這個(gè)宏,該宏的目的是如果p是一個(gè)非空指針,則調(diào)用free: 除非你在如下所述的情況下使用FREE1,否則所有調(diào)用都是正確有效的: FREE1經(jīng)擴(kuò)展以后,else就和錯(cuò)誤的if(FREE1的if)聯(lián)系在一起。有些程序員通過(guò)如下途徑解決這種問(wèn)題:
這兩種方法都不盡人意,程序員在調(diào)用宏以后自然而然使用的分號(hào)會(huì)把擴(kuò)展信息弄亂。以FREE2為例,在宏展開(kāi)之后,為了使編譯器能更準(zhǔn)確地識(shí)別,我們還需要進(jìn)行一定的縮進(jìn)調(diào)節(jié),最終代碼如下所示:
這樣就會(huì)引起語(yǔ)法錯(cuò)誤—else和任何一個(gè)if都不匹配。FREE3從本質(zhì)上講也存在同樣的問(wèn)題。而且在研究問(wèn)題產(chǎn)生原因的同時(shí),就能夠明白為什么宏體里是否包含if是無(wú)關(guān)緊要的。不管宏體內(nèi)部?jī)?nèi)容如何,只要使用一組括號(hào)來(lái)指定宏體,就會(huì)碰到相同的問(wèn)題。
引入do/while(0)技巧能夠克服前面所出現(xiàn)的所有問(wèn)題,現(xiàn)在我們可以編寫(xiě)FREE4。
將FREE4和其他宏一樣插入相同代碼之后,宏展開(kāi)后其代碼如下所示(為清晰起見(jiàn),我們?cè)俅握{(diào)整了縮進(jìn)格式):
這段代碼當(dāng)然可以正確執(zhí)行。編譯器能夠優(yōu)化這個(gè)偽循環(huán),舍棄循環(huán)控制,因此執(zhí)行代碼并沒(méi)有速度的損失,我們也從而得到了能夠?qū)崿F(xiàn)理想功能的宏。
雖然這是一個(gè)可以接受的解決方案,但是我們不能不提到的是編寫(xiě)函數(shù)要比編寫(xiě)宏好得多。不過(guò)如果你不能提供函數(shù)調(diào)用所需的開(kāi)銷(xiāo),那么就需要使用內(nèi)聯(lián)函數(shù)。這種情況雖然在內(nèi)核中經(jīng)常出現(xiàn),但是在其他地方就要少得多。(不可否認(rèn),當(dāng)使用C++、gcc或者任何實(shí)現(xiàn)了將要出現(xiàn)的修正版ISO標(biāo)準(zhǔn)C的編譯器時(shí),這種方案只是一種選擇,就是最后為C增加內(nèi)聯(lián)函數(shù)。)
3.__wait_event 16824:__wait_event使當(dāng)前進(jìn)程在等待隊(duì)列wq中等待,直至condition為真。16829:通過(guò)調(diào)用add_wait_queue(16791行),局部變量__wait可以被鏈接到隊(duì)列上。注意__wait是在堆棧中而不是在內(nèi)核堆中分配空間,這是內(nèi)核中常用的一種技巧。在宏運(yùn)行結(jié)束之前,__wait就已經(jīng)被從等待隊(duì)列中移走了,因此等待隊(duì)列中指向它的指針總是有效的。16830:重復(fù)分配CPU給另一個(gè)進(jìn)程直至條件滿足,這一點(diǎn)將在下面幾節(jié)中討論。16831:進(jìn)程被置為T(mén)ASK_UNINTERRUPTIBLE狀態(tài)(16190行)。這意味著進(jìn)程處于休眠狀態(tài),不應(yīng)被喚醒,即使是信號(hào)也不能打斷該進(jìn)程的休眠。信號(hào)在第6章中介紹,而進(jìn)程狀態(tài)則在第7章中介紹。
16832:如果條件已經(jīng)滿足,則可以退出循環(huán)。
請(qǐng)注意如果在第一次循環(huán)時(shí)條件就已經(jīng)滿足,那么前面一行的賦值就浪費(fèi)了(因?yàn)樵谘h(huán)結(jié)束之后進(jìn)程狀態(tài)會(huì)立刻被再次賦值)。__wait_event假定宏開(kāi)始執(zhí)行時(shí)條件還沒(méi)有得到滿足。而且,這種對(duì)進(jìn)程狀態(tài)變量state的延遲賦值也并沒(méi)有什么害處。在某些特殊情況下,這種方法還十分有益。例如當(dāng)__wait_event開(kāi)始執(zhí)行時(shí)條件為假,但是在執(zhí)行到16832行時(shí)就為真了。這種變化只有在為有關(guān)進(jìn)程狀態(tài)的代碼計(jì)算condition變量值時(shí)才會(huì)出現(xiàn)問(wèn)題。但是在代碼中這種情況我沒(méi)有發(fā)現(xiàn)。
16834:調(diào)用schedule(26686行,在第7章中討論)將CPU轉(zhuǎn)移給另一個(gè)進(jìn)程。直到進(jìn)程再次獲得CPU時(shí),對(duì)schedule的調(diào)用才會(huì)返回。這種情況只有當(dāng)?shù)却?duì)列中的進(jìn)程被喚醒時(shí)才會(huì)發(fā)生。
16836:進(jìn)程已經(jīng)退出了,因此條件必定已經(jīng)得到了滿足。進(jìn)程重置TASK_RUNNING的狀態(tài)(16188行),使其適合CPU運(yùn)行。
16837:通過(guò)調(diào)用remove_wait_queue(16814行)將進(jìn)程從等待隊(duì)列中移去。wait_event_interruptible和__wait_event_interruptible(分別參見(jiàn)16868行和16847)基本上與wait_event和__wait_event相同,但不同的是它們?cè)试S休眠的進(jìn)程可以被信號(hào)中斷。信號(hào)將在第6章中介紹。
請(qǐng)注意wait_event是被如下結(jié)構(gòu)所包含的。
和do/while(0)技巧一樣,這樣可以使被封閉起來(lái)的代碼能夠像一個(gè)單元一樣運(yùn)行。這樣的封閉代碼就是一個(gè)獨(dú)立的表達(dá)式,而不是一個(gè)獨(dú)立的語(yǔ)句。也就是說(shuō),它可以求值以供其他更復(fù)雜的表達(dá)式使用。發(fā)生這種情況的原因主要在于一些不可移植的gcc特有代碼的存在。通過(guò)使用這類(lèi)技巧,一個(gè)程序塊中的最后一個(gè)表達(dá)式的值將定義為整個(gè)程序塊的最終值。當(dāng)在表達(dá)式中使用wait_event_interruptible時(shí),執(zhí)行宏體后賦__ret的值為宏體的值(參見(jiàn)16873行)。對(duì)于有Lisp背景知識(shí)的程序員來(lái)說(shuō),這是個(gè)很常見(jiàn)的概念。但是如果你僅僅了解一點(diǎn)C和其他一些相關(guān)的過(guò)程性程序設(shè)計(jì)語(yǔ)言,你可能就會(huì)覺(jué)得比較奇怪。__wake_up 26829:該函數(shù)用來(lái)喚醒等待隊(duì)列中正在休眠的進(jìn)程。它由wake_up和wake_up_ interruptible調(diào)用(請(qǐng)分別參見(jiàn)16612行和16614行)。這些宏提供mode參數(shù),只有狀態(tài)滿足mode所包含的狀態(tài)之一的進(jìn)程才可能被喚醒。
26833:正如將在第10章中詳細(xì)討論的那樣,鎖(lock)是用來(lái)限制對(duì)資源的訪問(wèn),這在SMP邏輯單元中尤其重要,因?yàn)樵谶@種情況下當(dāng)一個(gè)CPU在修改某數(shù)據(jù)結(jié)構(gòu)時(shí),另一個(gè)CPU可能正在從該數(shù)據(jù)結(jié)構(gòu)中讀取數(shù)據(jù),或者也有可能兩個(gè)CPU同時(shí)對(duì)同一個(gè)數(shù)據(jù)結(jié)構(gòu)進(jìn)行修改,等等。在這種情況下,受保護(hù)的資源顯然是等待隊(duì)列。非常有趣的是所有的等待隊(duì)列都使用同一個(gè)鎖來(lái)保護(hù)。雖然這種方法要比為每一個(gè)等待隊(duì)列定義一個(gè)新鎖簡(jiǎn)單得多,但是這就意味著SMP邏輯單元可能經(jīng)常會(huì)發(fā)現(xiàn)自己正在等待一個(gè)實(shí)際上并不必須的鎖。
26838:本段代碼遍歷非空隊(duì)列,為隊(duì)列中正確狀態(tài)的每一個(gè)進(jìn)程調(diào)用wake_up_process(26356行)。如前所述,進(jìn)程(隊(duì)列節(jié)點(diǎn))在此可能并沒(méi)有從隊(duì)列中移走。這在很大程度上是由于即使隊(duì)列中的進(jìn)程正在被喚醒,它仍然可能希望繼續(xù)存在于等待隊(duì)列中,這一點(diǎn)正如我們?cè)赺_wait_event中發(fā)現(xiàn)的問(wèn)題一樣。2.2.3 內(nèi)核模塊
整個(gè)內(nèi)核并不需要同時(shí)裝入內(nèi)存。應(yīng)該確認(rèn),為保證系統(tǒng)能夠正常運(yùn)行,一些特定的內(nèi)核必須總是駐留在內(nèi)存中,例如,進(jìn)程調(diào)度代碼就必須常駐內(nèi)存。但是內(nèi)核其他部分,例如大部分的設(shè)備驅(qū)動(dòng)就應(yīng)該僅在內(nèi)核需要的時(shí)候才裝載,而在其他情況下則無(wú)需占用內(nèi)存。
舉例來(lái)說(shuō),只有在內(nèi)核真正和CD-ROM通訊時(shí)才需要使用完成內(nèi)核與CD-ROM通訊的設(shè)備驅(qū)動(dòng)程序,因此內(nèi)核可以被設(shè)置為在和設(shè)備通訊之前才裝載相應(yīng)代碼。內(nèi)核完成和設(shè)備的通訊之后可以將這部分代碼丟棄。也就是說(shuō),一旦代碼不再需要,就可以從內(nèi)存中移走。系統(tǒng)運(yùn)行過(guò)程中可以增減的這部分內(nèi)核稱(chēng)為內(nèi)核模塊。內(nèi)核模塊的優(yōu)點(diǎn)是可以簡(jiǎn)化內(nèi)核自身的開(kāi)發(fā)。假設(shè)你購(gòu)買(mǎi)了一個(gè)新的高速CD-ROM驅(qū)動(dòng)器,但是現(xiàn)有的CD-ROM驅(qū)動(dòng)程序并不支持該設(shè)備。你自然就希望增加對(duì)這種高速模式的支持以提高系統(tǒng)光驅(qū)設(shè)備的性能。如果作為內(nèi)核模塊來(lái)編譯驅(qū)動(dòng)程序,你的工作將會(huì)方便得多:編譯驅(qū)動(dòng)程序、加載到內(nèi)核、測(cè)試、卸載驅(qū)動(dòng)程序、修改驅(qū)動(dòng)程序、再次加載驅(qū)動(dòng)程序到內(nèi)核、測(cè)試,如此周而復(fù)始。如果你的驅(qū)動(dòng)程序是直接編輯在內(nèi)核中的,那么你就必須重新編譯整個(gè)內(nèi)核并且在每次修改驅(qū)動(dòng)程序之后重新啟動(dòng)機(jī)器。這樣慢得很多。
自然,你也必須留意內(nèi)核模塊。對(duì)于指明其他內(nèi)核模塊在磁盤(pán)上的駐留位置的那些模塊,一定不能從內(nèi)存中卸載,否則,內(nèi)核將只能通過(guò)訪問(wèn)磁盤(pán)來(lái)裝載處理磁盤(pán)訪問(wèn)的內(nèi)核模塊,這是不可能實(shí)現(xiàn)的。這也是我們要選擇把部分內(nèi)核作為模塊編譯還是直接編譯進(jìn)內(nèi)核使其常駐內(nèi)存的又一個(gè)原因。知道自己系統(tǒng)的設(shè)置方式,因而也就可以選擇正確使用的方式(如果為了確保安全,可以簡(jiǎn)單的忽略?xún)?nèi)核模塊系統(tǒng)的優(yōu)點(diǎn),而把所有的內(nèi)容都編譯到內(nèi)核里面)。內(nèi)核模塊會(huì)帶來(lái)一些速度上的損失,這是因?yàn)橐恍┍匦璧拇a現(xiàn)在并不在RAM中,必需要從磁盤(pán)讀入。但是整個(gè)系統(tǒng)的性能通常會(huì)有所提高,這主要是因?yàn)橥ㄟ^(guò)丟棄暫時(shí)不使用的模塊可以釋放出額外的RAM供應(yīng)用程序使用。如果這部分內(nèi)存被內(nèi)核所占用,應(yīng)用程序?qū)⒅荒芨宇l繁地進(jìn)行磁盤(pán)交換,而這種磁盤(pán)交換會(huì)顯著地降低應(yīng)用程序的性能(磁盤(pán)交換將在第8章中討論)。
內(nèi)核模塊還會(huì)帶來(lái)因復(fù)雜度的增加所造成的開(kāi)銷(xiāo),這是因?yàn)樵谙到y(tǒng)運(yùn)行的過(guò)程中,移進(jìn)移出部分內(nèi)核需要額外的代碼。然而,復(fù)雜度的開(kāi)銷(xiāo)是可以管理的。通過(guò)使用外部程序來(lái)代理一些必需的工作還可以更進(jìn)一步降低復(fù)雜度的開(kāi)銷(xiāo)(更為確切的說(shuō)法是,這樣做不是減少了復(fù)雜度的開(kāi)銷(xiāo),而是把復(fù)雜度的開(kāi)銷(xiāo)重新分配了一下)。這是對(duì)內(nèi)核模塊原理的一個(gè)小小的擴(kuò)展:即使是內(nèi)核的支持模塊,對(duì)于內(nèi)核來(lái)說(shuō)也只是外部的、部分可用的,只有在需要的時(shí)候才被裝入內(nèi)存。
通常用于這種目的程序稱(chēng)為modprobe。有關(guān)的modprobe代碼超出了本書(shū)的范圍,但是在Linux的每個(gè)發(fā)行版本中都包含有它。本節(jié)的剩余部分將討論同modprobe協(xié)同工作,以裝載內(nèi)核模塊的內(nèi)核代碼。1.request_module 24432:作為函數(shù)說(shuō)明之前的注釋?zhuān)瑀equest_module是一個(gè)函數(shù)。內(nèi)核的其他模塊在需要裝載其他內(nèi)核模塊的時(shí)候,都必須調(diào)用這個(gè)函數(shù)。就像內(nèi)核處理其他工作一樣,這種調(diào)用也是為當(dāng)前運(yùn)行的進(jìn)程進(jìn)行的。從進(jìn)程的角度來(lái)看,這種調(diào)用的請(qǐng)求通常是隱含的—正在執(zhí)行進(jìn)程其他請(qǐng)求的內(nèi)核可能會(huì)發(fā)現(xiàn),必須調(diào)入一個(gè)模塊才能夠完成該請(qǐng)求。例如,請(qǐng)參見(jiàn)10070行,這里是一些將在第7章中討論的代碼。
24446:以?xún)?nèi)核中的一個(gè)獨(dú)立進(jìn)程的形式執(zhí)行exec_modprobe函數(shù)(24384行)。這并不能只通過(guò)函數(shù)的簡(jiǎn)單調(diào)用實(shí)現(xiàn),因?yàn)閑xec_modprobe要繼續(xù)調(diào)用exec來(lái)執(zhí)行一個(gè)程序。因此,對(duì)函數(shù)exec_modprobe的簡(jiǎn)單調(diào)用將永遠(yuǎn)不會(huì)有返回。
這和使用fork以準(zhǔn)備exec調(diào)用十分類(lèi)似,你可以認(rèn)為kernel_thread對(duì)內(nèi)核來(lái)說(shuō)就是較低版本的fork,雖然兩者有很大不同。fork是從指定函數(shù)開(kāi)始執(zhí)行新的進(jìn)程,而不是從調(diào)用者的當(dāng)前位置開(kāi)始運(yùn)行。正如fork一樣,kernel_thread返回的值是新進(jìn)程的進(jìn)程號(hào)。24448:和fork一樣,從kernel_thread返回的負(fù)值表示內(nèi)部錯(cuò)誤。
24455:正如函數(shù)中論述的一樣,大部分的信號(hào)將因當(dāng)前進(jìn)程而被暫時(shí)阻塞。
24462:等待exec_modprobe執(zhí)行完畢,同時(shí)指出所需要的模塊是已經(jīng)成功裝入內(nèi)存,還是裝載失敗了。
24465:結(jié)束運(yùn)行,恢復(fù)信號(hào)。如果exec_modprobe返回錯(cuò)誤代碼,則打印錯(cuò)誤消息。2.exec_modprobe 24384:exec_modprobe運(yùn)行為內(nèi)核增加內(nèi)核模塊的程序。這里的模塊名是一個(gè)void*的指針,而不是char*的指針。原因簡(jiǎn)單說(shuō)來(lái)就是kernel_thread 產(chǎn)生的函數(shù)通常都使用void*指針參數(shù)。
24386:設(shè)置modprobe的參數(shù)列表和環(huán)境。modprobe_path(24363行)用來(lái)定位modprobe程序的位置。它可以通過(guò)內(nèi)核的sysctl特性來(lái)修改,這一點(diǎn)將在第11章中介紹(參見(jiàn)30388行)。這意味著root可以動(dòng)態(tài)選擇不同于/sbin/modprobe的程序來(lái)運(yùn)行,以適應(yīng)當(dāng)modprobe被安裝到其他地方或者使用修改過(guò)的modprobe替換掉了原有的modprobe之類(lèi)的情況。24400:(正如代碼中描述的一樣)出于安全性考慮,丟棄所有掛起的信號(hào)和信號(hào)句柄(handl-ers)。這里最重要的部分是對(duì)flush_signal_handlers的調(diào)用(28041行),它使用內(nèi)核默認(rèn)的信號(hào)句柄代替所有用戶(hù)定義的信號(hào)句柄。如果在此時(shí)有信號(hào)被傳送到內(nèi)核,它將獲得默認(rèn)響應(yīng)—通常是忽略信號(hào)或殺死進(jìn)程。但是不管怎樣都不會(huì)引起安全風(fēng)險(xiǎn)。由于該函數(shù)從觸發(fā)它的進(jìn)程中分離出來(lái)(如前所述),所以,不管原始進(jìn)程在此處是否改變其原來(lái)分配的信號(hào),句柄都不會(huì)產(chǎn)生任何影響。
24405:關(guān)閉調(diào)用進(jìn)程打開(kāi)的所有文件。最重要的是,這意味著modprobe程序不再?gòu)恼{(diào)用進(jìn)程中繼承標(biāo)準(zhǔn)輸入輸出和標(biāo)準(zhǔn)錯(cuò)誤。這很有可能會(huì)引起安全漏洞(這可能是在替代modprobe的程序中引起的問(wèn)題,但是modprobe本身實(shí)際上并不關(guān)心這個(gè)差異)。
24413:modprobe程序作為root運(yùn)行,它擁有root所擁有的所有權(quán)限。和整個(gè)內(nèi)核中其他地方一樣,請(qǐng)注意root使用用戶(hù)ID號(hào)0的假定在這里已經(jīng)被寫(xiě)入程序。用戶(hù)ID號(hào)和權(quán)能系統(tǒng)(capability system,在接下來(lái)的幾行中會(huì)用到)將在第7章中介紹。
24421:試圖執(zhí)行modprobe程序。如果嘗試失敗,內(nèi)核將使用printk打印錯(cuò)誤消息并返回錯(cuò)誤代碼。這里是可能產(chǎn)生printk的緩沖器過(guò)載的地點(diǎn)之一。module_name的長(zhǎng)度并沒(méi)有明確限制,就我們對(duì)該調(diào)用的看法而言,它可能長(zhǎng)達(dá)一百萬(wàn)個(gè)字符。為防止printk緩沖器過(guò)載,你必需遍歷所有對(duì)于該函數(shù)的調(diào)用(實(shí)際上是對(duì)request_module的調(diào)用),以保證每個(gè)調(diào)用者使用足夠短的、不會(huì)為printk造成麻煩的模塊名。
24427:當(dāng)execve成功執(zhí)行時(shí),它不會(huì)返回任何結(jié)果,因此本處是不可能執(zhí)行到的。但是編譯器卻并不知道這一點(diǎn),因此,此處使用了return語(yǔ)句以保證gcc不出錯(cuò)。
對(duì)于內(nèi)核的進(jìn)一步討論將超出本章的既定范圍,因此在這個(gè)問(wèn)題上我們到此為止。然而本書(shū)中也包括了其他必需的內(nèi)核代碼。在讀完第4章和第5章之后,也許你會(huì)希望再次仔細(xì)研讀一下這部分內(nèi)容。有關(guān)這個(gè)問(wèn)題的兩個(gè)文件是include/linux/module.h(從15529行開(kāi)始)和/kernel/module.c(從24476行開(kāi)始)。和sys_create_module(24586行)、sys_init_module(24637行)、sys_delete_module(24860行)和sys_query_module(25148行)四個(gè)函數(shù)需要特別注意一樣,struct module(15581行)也要特別引起注意。這些函數(shù)實(shí)現(xiàn)了modprobe及insmod、lsmod和rmmod所使用的系統(tǒng)調(diào)用,以完成模塊的裝載、定位和卸載。
內(nèi)核觸發(fā)直接回調(diào)內(nèi)核程序的現(xiàn)象看起來(lái)很令人奇怪。但是,實(shí)際上進(jìn)行的工作不止于此。例如,modprobe必須實(shí)際訪問(wèn)磁盤(pán)以搜尋要裝載的模塊。而且更為重要的一點(diǎn)是,這種方法賦予root對(duì)內(nèi)核模塊系統(tǒng)更多的控制能力。這主要是因?yàn)閞oot也可以運(yùn)行modprobe及相關(guān)程序。因此,root既可以手工裝載、查詢(xún)、卸載模塊,也可以由內(nèi)核自動(dòng)完成。2.3 配置與編譯內(nèi)核
你可能僅僅研讀、欣賞而并不修改Linux內(nèi)核源代碼。但是,更普遍的情況是,用戶(hù)有強(qiáng)烈的愿望去改進(jìn)內(nèi)核代碼并完成相應(yīng)的測(cè)試,這樣我們就需要知道如何重建內(nèi)核。本節(jié)就是要告訴你如何實(shí)現(xiàn)這一點(diǎn),而最終則歸結(jié)于如何把你所做的修改發(fā)行給別人,以使得每個(gè)人都能從你的工作中受益。2.3.1 配置內(nèi)核
編譯內(nèi)核的第一步就是配置內(nèi)核,這是增加或者減少對(duì)內(nèi)核特性的支持及修改內(nèi)核的一些特性的必要步驟。例如,你可以要求內(nèi)核為自己的聲卡指定一個(gè)不同的DMA通道。如果內(nèi)核配置和你的需要相同,那么你可以直接跳過(guò)本節(jié),否則請(qǐng)繼續(xù)閱讀以下內(nèi)容。為了完成內(nèi)核的配置,請(qǐng)先切換到root用戶(hù),然后轉(zhuǎn)入如下內(nèi)核源程序目錄: cd /usr/src/linux 接著敲入如下命令組: make config make menuconfig make xconfig 這三條命令都可以用來(lái)配置內(nèi)核,但它們發(fā)揮作用的方式各不相同:
?make config—三種方法中最簡(jiǎn)單也是最枯燥的一種。但是最基本的一點(diǎn)是,它可以適應(yīng)任何情況。通過(guò)為每一個(gè)內(nèi)核支持的特性向用戶(hù)提問(wèn)的方式來(lái)決定在內(nèi)核中需要包含哪些特性。對(duì)于大多數(shù)問(wèn)題,你只要回答y(yes,把該特性編譯進(jìn)內(nèi)核中)、m(作為模塊編譯)或者n(no,根本不對(duì)該特性提供支持)。在決定之前用戶(hù)應(yīng)該考慮清楚,因?yàn)檫@個(gè)過(guò)程是不可逆的。如果你在該過(guò)程中犯了錯(cuò)誤,就只能按Ctrl+C退出。你也可以敲入?以獲取幫助。圖2-1顯示了這種方法在X終端上運(yùn)行的情況。圖2-1 運(yùn)行中的make config 幸運(yùn)的是,這種方法還有一些智能。例如,如果你對(duì)SCSI支持回答no,那么系統(tǒng)就不會(huì)再詢(xún)問(wèn)你有關(guān)SCSI的細(xì)節(jié)問(wèn)題了。而且你可以只按回車(chē)鍵以接受默認(rèn)的選擇,也就是當(dāng)前的設(shè)置(因此,如果當(dāng)前內(nèi)核將對(duì)于SCSI的支持編譯進(jìn)了內(nèi)核,在這個(gè)問(wèn)題上按回車(chē)鍵就意味著繼續(xù)把對(duì)SCSI的支持編譯進(jìn)內(nèi)核中)。即使是這樣,大部分用戶(hù)還是寧愿使用另外的兩種方法。
?make menuconfig—一種基于終端的配置機(jī)制,用戶(hù)擁有通過(guò)移動(dòng)光標(biāo)來(lái)進(jìn)行瀏覽等功能。圖2-2顯示了在X終端上運(yùn)行的make menuconfig。雖然在控制臺(tái)上顯示的是彩色,但是在終端上的顯示仍然相當(dāng)單調(diào)。使用menuconfig必須要有相應(yīng)的ncurses類(lèi)庫(kù)。圖2-2 運(yùn)行中的make menuconfig ?make xconfig—這是我最喜歡的一種配置方式。只有你能夠在X server上用root用戶(hù)身份運(yùn)行X應(yīng)用程序時(shí),這種配置方式才可以使用(有些偏執(zhí)的用戶(hù)就不愿意使用這種方式)。你還必須擁有Tcl窗口系統(tǒng),這實(shí)際上還意味著你必須擁有Tcl、Tk以及一個(gè)正在運(yùn)行的X安裝程序。作為補(bǔ)償,用戶(hù)獲得的是更漂亮的、基于X系統(tǒng)的以及和menuconfig功能相同的配置方法。圖2-3顯示了在這種方法運(yùn)行過(guò)程中打開(kāi)“可裝載模塊支持(Loadable module support)”子窗口的情況。
圖2-3 運(yùn)行中的make xconfig 如上所述,這三種方法都實(shí)現(xiàn)了相同的功能:它們都生成在構(gòu)建內(nèi)核時(shí)使用的.config文件。而唯一的區(qū)別在于創(chuàng)建這個(gè)文件時(shí)的難易程度不同。2.3.2 構(gòu)建內(nèi)核
構(gòu)建內(nèi)核要做的工作要比配置內(nèi)核所做的工作少得多。雖然有幾種方式都能實(shí)現(xiàn)這一功能,但是選擇哪一種依賴(lài)于你希望怎樣對(duì)系統(tǒng)進(jìn)行設(shè)置。長(zhǎng)期以來(lái),我已經(jīng)形成了如下的習(xí)慣。雖然這種習(xí)慣比我所必須要做的略微多一些,但是它包含了所有基本的問(wèn)題。首先,如果你還不在內(nèi)核源程序目錄中,請(qǐng)先再次轉(zhuǎn)入這一目錄: cd /usr/src/linux 現(xiàn)在,切換到root用戶(hù),使用下面顯示的命令生成內(nèi)核?,F(xiàn)在在shell中敲入下面的命令,注意make命令因?yàn)榭臻g關(guān)系分成了兩行,但實(shí)際上這在shell輸入時(shí)是一個(gè)只有一行的命令: make dep clean zlilo boot modules modules_install 當(dāng)給出了如上多個(gè)目標(biāo)時(shí),除非前面所有的目標(biāo)都成功了,否則make能夠知道沒(méi)有必要繼續(xù)嘗試下面的目標(biāo)。因此,如果make能夠運(yùn)行結(jié)束,成功退出,那么這就意味著所有的目標(biāo)都正確構(gòu)建了。現(xiàn)在你可以重新啟動(dòng)機(jī)器以運(yùn)行新的內(nèi)核。2.3.3 備份的重要性
當(dāng)修改(fooling)內(nèi)核時(shí),你必須準(zhǔn)備一個(gè)能夠啟動(dòng)的備用內(nèi)核。實(shí)現(xiàn)該目的的一種方式是通過(guò)配置Linux加載程序(LILO)以允許用戶(hù)選擇啟動(dòng)的內(nèi)核映象,其中之一是從沒(méi)有修改過(guò)的內(nèi)核的備份(我總是這樣做的)。
如果你比較有耐心,那么你就可以使用zdisk目標(biāo)而不使用zlilo目標(biāo);它可以把能夠啟動(dòng)的內(nèi)核映象寫(xiě)入軟盤(pán)中。這樣你就可以通過(guò)在啟動(dòng)時(shí)插入軟盤(pán)的方式啟動(dòng)你的測(cè)試內(nèi)核;如果沒(méi)有插入軟盤(pán),則啟動(dòng)正常的內(nèi)核。
但是請(qǐng)注意:內(nèi)核模塊并沒(méi)有被裝載到軟盤(pán)中,它們實(shí)際上是裝在硬盤(pán)中的(除非你愿意承擔(dān)更多的麻煩)。因此,如果你弄亂了內(nèi)核模塊,即使是zdisk目標(biāo)也救不了你。實(shí)際上,上面提到的這兩種方法都存在這個(gè)問(wèn)題。雖然有比較好的解決方法可用,但是最簡(jiǎn)單的方法(也就是我所使用的方法)是把備份內(nèi)核作為嚴(yán)格獨(dú)立的內(nèi)核來(lái)編譯,而不使用可裝載模塊的支持。通過(guò)這種方法,即使我弄亂了內(nèi)核而不得不使用備份啟動(dòng)系統(tǒng),那么不管問(wèn)題是實(shí)驗(yàn)性?xún)?nèi)核不正確還是內(nèi)核模塊的原因都無(wú)關(guān)緊要。不管怎樣,在備份的內(nèi)核中已經(jīng)有我需要的所有東西了。
由于用戶(hù)所做的修改可能導(dǎo)致系統(tǒng)的崩潰,如損壞磁盤(pán)上的數(shù)據(jù)等等,并不僅僅只是打亂設(shè)備驅(qū)動(dòng)程序或文件系統(tǒng),在測(cè)試新內(nèi)核之前,備份系統(tǒng)的最新數(shù)據(jù)也是一個(gè)英明的決策(雖然設(shè)備驅(qū)動(dòng)程序的開(kāi)發(fā)不是本書(shū)的主題,但是必需指出的是,設(shè)備驅(qū)動(dòng)程序的缺陷可能會(huì)引起系統(tǒng)的物理?yè)p壞。例如顯示器是不能備份的,而且因價(jià)格昂貴而不易替換)。作為一個(gè)潛在的內(nèi)核黑客,你的最佳投資(當(dāng)然是讀過(guò)本書(shū)以后)是一個(gè)磁帶驅(qū)動(dòng)器和充足的磁帶。2.3.4 發(fā)布你的改進(jìn)
下面是有關(guān)發(fā)布你所做修改的一些基本規(guī)則:
?檢查最新發(fā)行版本,確保你所處理的不是已經(jīng)解決了的問(wèn)題。
?遵守Linux 內(nèi)核代碼編寫(xiě)的風(fēng)格。簡(jiǎn)要的說(shuō)就是8字符縮進(jìn)以及K&R括號(hào)風(fēng)格(if,else,for,while,switch或者do后面同一行中緊跟著開(kāi)括號(hào))。在內(nèi)核源程序目錄下面的文檔編寫(xiě)和代碼風(fēng)格文件給出了完整的規(guī)則,不過(guò)我們已經(jīng)介紹了其中的關(guān)鍵部分。注意本書(shū)中包含的源程序代碼為節(jié)省空間而進(jìn)行了大量的重新編輯,在該過(guò)程中我可能打破了其中的一些規(guī)則。
?獨(dú)立發(fā)行相對(duì)無(wú)關(guān)的修改。這樣,只想使用你所做的某部分修改的人就可以十分方便地獲得想要的東西,而不用一次檢驗(yàn)所有的修改內(nèi)容。
?讓使用你所做修改的用戶(hù)清楚他們可以從你的修改中獲取什么。同樣,你也應(yīng)該給出這些問(wèn)題的可信度。你是15min之前才匆匆完成你的修改,甚至還沒(méi)有時(shí)間對(duì)它們進(jìn)行編譯,還是已經(jīng)在你和你的朋友的系統(tǒng)中已長(zhǎng)期穩(wěn)定地運(yùn)行過(guò)這個(gè)修改?
假設(shè)現(xiàn)在你已經(jīng)準(zhǔn)備好發(fā)行自己的修改版本了,那么要做的第一步是建立一個(gè)說(shuō)明你所做的修改的文件。你可以使用diff程序自動(dòng)創(chuàng)建這個(gè)文件。結(jié)果或者被稱(chēng)為diffs,或者在Linux中更普遍的被稱(chēng)為補(bǔ)?。╬atch)。
發(fā)布的過(guò)程十分簡(jiǎn)單。假設(shè)原來(lái)沒(méi)有修改過(guò)的源程序代碼在linux-2.2.5目錄下,而你修改過(guò)的源程序代碼在linux-my目錄下,那么只要進(jìn)行如下的簡(jiǎn)單工作就可以了(只有在鏈接不存在的情況下才需要執(zhí)行l(wèi)n):
現(xiàn)在,輸出文件my.patch包含了其他用戶(hù)應(yīng)用這個(gè)修改程序時(shí)所需要的一切內(nèi)容。(警告:如上所述,兩個(gè)源程序間的所有差別都會(huì)包含在這個(gè)補(bǔ)丁文件中。diff不能區(qū)分修改部分之間的關(guān)系,所以就把它們都羅列了出來(lái)。)如果補(bǔ)丁文件相對(duì)較小,你可以使用郵件直接發(fā)往內(nèi)核郵件列表。如果補(bǔ)丁很大,那么就需要通過(guò)FTP或者Web站點(diǎn)發(fā)布。這時(shí)發(fā)給郵件列表的信件中就只需要包含一個(gè)URL。Linux內(nèi)核郵件列表的常見(jiàn)問(wèn)題解答(FAQ)文件位于http://004km.cn。
阿道夫 的 范德薩 啊訂單式