Linux共享內(nèi)存實(shí)例及文件映射編程及實(shí)現(xiàn)原理_第1頁
Linux共享內(nèi)存實(shí)例及文件映射編程及實(shí)現(xiàn)原理_第2頁
Linux共享內(nèi)存實(shí)例及文件映射編程及實(shí)現(xiàn)原理_第3頁
Linux共享內(nèi)存實(shí)例及文件映射編程及實(shí)現(xiàn)原理_第4頁
Linux共享內(nèi)存實(shí)例及文件映射編程及實(shí)現(xiàn)原理_第5頁
已閱讀5頁,還剩6頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、目錄(一)IPC共享內(nèi)存和文件映射的區(qū)別1(二)共享內(nèi)存實(shí)現(xiàn)流程總結(jié)1(三)存儲映射I/O(包含實(shí)現(xiàn)原理說明)2文件映射API補(bǔ)充4(四)IPC共享存儲(包含實(shí)現(xiàn)原理說明)6(五)共享內(nèi)存實(shí)現(xiàn)基本原理10(六)IPC共享內(nèi)存實(shí)現(xiàn)機(jī)制11(七)文件映射的實(shí)現(xiàn)機(jī)制13(一)IPC共享內(nèi)存和文件映射的區(qū)別1. 文件映射的頁框是磁盤文件高速緩存中的頁框,內(nèi)核線程pdflush會將頁框中的內(nèi)容回寫進(jìn)磁盤, 如果是私有映射類型,將會進(jìn)行寫時復(fù)制。而IPC共享內(nèi)存映射的是一種特殊文件系統(tǒng)中的文件高速緩存,它沒有相應(yīng)的磁盤映像。2. IPC共享內(nèi)存只存在于內(nèi)存中,系統(tǒng)重新啟動,數(shù)據(jù)將會丟失。而文件共享映射會將

2、數(shù)據(jù)寫回磁盤。3. IPC共享內(nèi)存的大小是在創(chuàng)建的時候指定,而且大小不能改變,而文件在創(chuàng)建時大小為0,此時還不能建立映射,文件的大小會間接的決定映射區(qū)的大小。例如文件的大小是123,而要求映射的區(qū)域大小是4096*2,但實(shí)際只會分配4096的映射空間,此時引用4096以后的線性空間將引起缺頁異常。4. 當(dāng)?shù)谝淮巫x取共享內(nèi)存時IPC共享內(nèi)存對象將分配一個新的頁框,而文件映射分配新頁框的同時會將磁盤中的數(shù)據(jù)寫入新頁框。5. IPC共享內(nèi)存不需要寫回磁盤操作,完全是為共享內(nèi)存而設(shè)計,所以使用效率會更高。6. IPC共享內(nèi)存對象必須調(diào)用shmctl()顯示的撤銷,否則會一直保留著,使用key或者id號

3、定位一個共享內(nèi)存對象,key和id號的對應(yīng)關(guān)系并不是固定的。例如,第一次使用key建立一個共享內(nèi)存對象為shm1對應(yīng)的id為id1,之后系統(tǒng)重新啟動,然后再使用key建立一個共享內(nèi)存對象shm2,對應(yīng)的id是id2,此時id2和id1是不同的。而文件映射使用相同的路徑將會定位相同的磁盤文件??偨Y(jié):IPC共享內(nèi)存和文件映射的實(shí)現(xiàn)機(jī)制是一樣的,文件映射的目的是加快對文件的讀寫速度,而IPC共享內(nèi)存就是為了共享內(nèi)存而設(shè)計的,所以效率會高一些。(二)共享內(nèi)存實(shí)現(xiàn)流程總結(jié)1. 建立一個線性區(qū)對象struct vm_area_struct 并加入進(jìn)程的內(nèi)存描述符current-mm中。函數(shù)mmap()和s

4、hmat()就是用于建立并注冊線性區(qū)對象,這個對象中的struct file *vm_file指向映射文件的文件對象,vm_page_prot是線性區(qū)中頁框的訪問許可權(quán)。但此時并未修改進(jìn)程的頁表,而是注冊相應(yīng)的缺頁異?;卣{(diào)函數(shù),注冊在對象的vm_ops。2. 當(dāng)進(jìn)程第一次訪問共享內(nèi)存區(qū)時,由于相應(yīng)的頁表還未填寫,將產(chǎn)生缺頁異常,并根據(jù)線性地址找到對應(yīng)的線性區(qū)對象,然后調(diào)用前邊注冊過的缺頁異常回調(diào)函數(shù),并根據(jù)vm_file文件對象和vm_page_prot的信息來填寫相應(yīng)的頁表項,最后重新執(zhí)行產(chǎn)生缺頁異常的代碼。說明:文件映射和IPC共享內(nèi)存映射的物理頁框都是磁盤文件的頁高速緩存中的,IPC共享

5、內(nèi)存使用一種特殊文件系統(tǒng),這個文件系統(tǒng)并沒有對應(yīng)的磁盤映像,只是復(fù)用了文件系統(tǒng)的框架。更詳細(xì)的內(nèi)容參見后邊的五,六,七節(jié)。下面3,4節(jié)是UNIX環(huán)境高級編程對文件映射和IPC共享內(nèi)存的講解,已經(jīng)說明的很詳細(xì)了,我在它的基礎(chǔ)上附加了一些內(nèi)核實(shí)現(xiàn)原理的說明,實(shí)現(xiàn)原理說明部分放在括號內(nèi)。(三)存儲映射I/O(包含實(shí)現(xiàn)原理說明)存儲映射I/O使一個磁盤文件與存儲空間中的一個緩存相映射。于是當(dāng)從緩存中取數(shù)據(jù),就相當(dāng)于讀文件中的相應(yīng)字節(jié)。與其類似,將數(shù)據(jù)存入緩存,則相應(yīng)字節(jié)就自動地寫入文件。這樣,就可以在不使用read和write的情況下執(zhí)行I/O。為了使用這種功能,應(yīng)首先告訴內(nèi)核將一個給定的文件映射到一

6、個存儲區(qū)域中。這是由mmap函數(shù)實(shí)現(xiàn)的。#include #include void * mmap(void addr, size_t len, int prot, int flag, int fd, off_t off) ;返回:若成功則為映射區(qū)的起始地址,若出錯則為- 1addr參數(shù)用于指定映射存儲區(qū)的起始地址。通常將其設(shè)置為0,這表示由系統(tǒng)選擇該映射區(qū)的起始地址。此函數(shù)的返回地址是:該映射區(qū)的起始地址。fd指定要被映射文件的描述符(fd用于定位是哪個磁盤文件的頁高速緩存)。在映射該文件到一個地址空間之前,先要打開該文件。len是映射的字節(jié)數(shù)。off是要映射字節(jié)在文件中的起始位移量(下面將

7、說明對off值有某些限制)。在說明其余參數(shù)之前,先看一下存儲映射文件的基本情況。圖12 - 12顯示了一個存儲映射文件。在此圖中,“起始地址”是mmap的返回值。在圖中,映射存儲區(qū)位于堆和棧之間:這屬于實(shí)現(xiàn)細(xì)節(jié),各種實(shí)現(xiàn)之間可能不同。prot參數(shù)說明映射存儲區(qū)的保護(hù)要求。見表12 - 8。對于映射存儲區(qū)所指定的保護(hù)要求與文件的open方法匹配。例如,若該文件是只讀打開的,那么對映射存儲區(qū)就不能指定PROT _WRITE。(對存儲映射區(qū)的保護(hù)是通過設(shè)置頁表項的保護(hù)標(biāo)志來實(shí)現(xiàn)的,如果頁表項的read/write標(biāo)志位為0,說明頁是只讀的,如果進(jìn)程試圖修改頁的內(nèi)容,將產(chǎn)生段錯誤,這些保護(hù)方案都是由C

8、PU硬件控制的)flag參數(shù)影響映射存儲區(qū)的多種屬性:? MAP_FIXED 返回值必須等于addr。因為這不利于可移植性,所以不鼓勵使用此標(biāo)志。如果未指定此標(biāo)志,而且addr非0,則內(nèi)核只把a(bǔ)ddr視為何處設(shè)置映射區(qū)的一種建議。通過將addr指定為0可獲得最大可移植性。? MAP_SHARED 這一標(biāo)志說明了本進(jìn)程對映射區(qū)所進(jìn)行的存儲操作的配置。此標(biāo)志指定存儲操作修改映射文件也就是,存儲操作相當(dāng)于對該文件write。(這里映射的頁是包含在文件的頁高速緩存中,用戶態(tài)進(jìn)程在讀寫磁盤的時候,內(nèi)核先在頁高速緩存中增加一個新頁,將所請求的磁盤塊寫入新頁,用戶態(tài)進(jìn)程從頁高速緩存中取出數(shù)據(jù)。如果要寫入數(shù)據(jù)

9、,也是要添加一個頁將磁盤中的數(shù)據(jù)寫入該頁,然后再將數(shù)據(jù)寫入該頁,內(nèi)核會在一定的時機(jī)對磁盤進(jìn)行更新。)(以上的頁高速緩存是組織在inode的i_mmaping對象中,對于一個磁盤文件唯一對應(yīng)一個磁盤inode,每個磁盤inode也唯一對應(yīng)一個內(nèi)核inode,也就是,每個磁盤文件只有一個頁高速緩存,如果兩個進(jìn)程映射的是同一個文件的頁高數(shù)緩存,則它們共享相同的物理頁)? MAP_PRIVATE 本標(biāo)志說明,對映射區(qū)的存儲操作導(dǎo)致創(chuàng)建該映射文件的一個副本。所有后來對該映射區(qū)的存訪都是存訪該副本,而不是原始文件。(這里內(nèi)核用到了寫時復(fù)制技術(shù),在相應(yīng)的頁表項中設(shè)置寫時復(fù)制標(biāo)志,當(dāng)進(jìn)程試圖修改該頁,內(nèi)核將會

10、產(chǎn)生缺頁異常,內(nèi)核就把該頁框進(jìn)行復(fù)制,并在進(jìn)程頁表中用復(fù)制的頁來替換原來的頁框,顯然這個新的頁框已經(jīng)不在頁高速緩存中了,對頁框的內(nèi)容進(jìn)行修改將不會寫回文件,其它進(jìn)程將無法共享這個頁框。如果本進(jìn)程還未進(jìn)行寫復(fù)制,而其它進(jìn)程修改了頁的內(nèi)容,本進(jìn)程是可以獲得更新后的數(shù)據(jù))因為映射文件的起動位移量受系統(tǒng)虛存頁長度的限制,那么如果映射區(qū)的長度不是頁長度的整數(shù)倍時,將如何呢?假定文件長12字節(jié),系統(tǒng)頁長為512字節(jié),則系統(tǒng)通常提供512字節(jié)的映射區(qū),其中后500字節(jié)被設(shè)0??梢孕薷倪@50字節(jié),但任何變動都不會在文件中反映出來。(這是由于內(nèi)核分配線性區(qū)和分配物理內(nèi)存都是以頁為單位)與映射存儲區(qū)相關(guān)有兩個信號

11、: SIGSEGV和SIGBUS。信號SIGSEGV通常用于指示進(jìn)程試圖存取它不能存取的存儲區(qū)。如果進(jìn)程企圖存數(shù)據(jù)到用mmap指定為只讀的映射存儲區(qū),那么也產(chǎn)生此信號。如果存取映射區(qū)的某個部分,而在存取時這一部分已不存在,則產(chǎn)生SIGBUS信號。例如,用文件長度映射一個文件,但在存訪該映射區(qū)之前,另一個進(jìn)程已將該文件截短。此時,如果進(jìn)程企圖存取對應(yīng)于該文件尾端部分的映射區(qū),則接收到SIGBUS信號。(對信號的實(shí)現(xiàn)機(jī)制有待進(jìn)一步分析)在fork之后,子進(jìn)程繼承存儲映射區(qū)(因為子進(jìn)程復(fù)制父進(jìn)程地址空間,而存儲映射區(qū)是該地址空間中的一部分),但是由于同樣的理由,exec后的新程序則不繼承此存儲映射區(qū)

12、。(關(guān)閉文件描述符也不影響存儲映射區(qū),磁盤文件的頁高速緩存并不會因為進(jìn)程的撤銷而撤銷,如果有足夠的空閑內(nèi)存,頁高速緩存中的頁將長期存在,使其它進(jìn)程再使用該頁時不再訪問磁盤。)進(jìn)程終止時,或調(diào)用了munmap之后,存儲映射區(qū)就被自動去除。關(guān)閉文件描述符fd并不解除映射區(qū)。(關(guān)閉存儲映射區(qū),只是撤銷進(jìn)程頁表中的相應(yīng)目錄項,并不影響頁高速緩存。)#include #include int munmap(void addr,size_t len) ;返回:若成功則為0,若出錯則為- 1munmap 并不影響被映射的對象也就是說,調(diào)用munmap并不使映射區(qū)的內(nèi)容寫到磁盤文件上。對于MAP_SHARED

13、區(qū)磁盤文件的更新,在寫到存儲映射區(qū)時按內(nèi)核虛存算法自動進(jìn)行。(pdflush內(nèi)核線程用于刷新臟頁)例子程序:#include #include #include #include #include #include int main(int argc, char *argv)int fd, i, counter;pid_t pid;char *area = NULL;if(fd = open(test, O_RDWR) )= 0)printf(open errorn);area = (char *)mmap(0, sizeof(long), PROT_READ | PROT_WRITE, MA

14、P_SHARED, fd, 0);printf(area:%pn, area);close(fd);*(area + 1) = c;文件映射API補(bǔ)充msync函數(shù)的使用原型:? #include ? int msync(const void *start, size_t length, int flags);msync函數(shù)用來把映像的文件寫入磁盤。調(diào)用msync可以用對內(nèi)存中的映像的更新寫入一個被映像的文件,被強(qiáng)行寫入到磁盤的內(nèi)存取從start指定的地址開始,寫入length個字節(jié)的數(shù)據(jù)。flags可以是下面的一個值或多個的邏輯“或”:? 1、MS_ASYNC 調(diào)度一次寫入操作然后返回? 2

15、、MS_SYNC 在msync返回前寫入數(shù)據(jù)? 3、MS_INVALIDATE 讓映像到同一文件的映像無效,以便用新數(shù)據(jù)更新它們(MS_INVALIDATE的作用是使映射的頁高速緩存中的內(nèi)容無效,重新從磁盤寫入數(shù)據(jù)到映射的頁高速緩存??梢允褂肕S_INVALIDATE來測試內(nèi)核是否進(jìn)行頁高速緩存數(shù)據(jù)的回寫磁盤操作,測試過程:寫一個字符到映射區(qū),然后使用MS_INVALIDATE使映射區(qū)的數(shù)據(jù)失效,并從磁盤寫入數(shù)據(jù),從測試結(jié)果看字符會被寫入磁盤,也就是說內(nèi)核幾乎在對映射區(qū)進(jìn)行寫入操作的同時就進(jìn)行了回寫磁盤操作)mprotect函數(shù)的使用mprotect函數(shù)修改在內(nèi)存映像上的保護(hù)模式。函數(shù)原型:?

16、 #include ? #include ? int mprotect(const void *start, size_t len, int prot);mprotect把自start開始的內(nèi)存區(qū)的保護(hù)模式修改為prot指定的值,如果執(zhí)行成功返回0,如果執(zhí)行失敗,mprotect返回-1,并且設(shè)置errno變量。port可以是PROT_READ(可讀)、PROT_WRITE(可寫)、PROT_EXEC(可執(zhí)行)、PROT_NONE(不可訪問)中的一個或多個(這里只是修改本進(jìn)程頁表中的訪問控制標(biāo)志,并不涉及物理頁,對其它進(jìn)程沒有影響)鎖定內(nèi)存原型:? #include int mlock(con

17、st void *start, size_t len);? int munlock(void *start, size_t len);? int mlockall(int flags);? int munlockall(void);以4上個函數(shù)是對指定的內(nèi)存映像加鎖和解鎖,其中mlockall的flags包括MCL_CURRENT和MCL_FUTURE。只有root權(quán)限才能使用它們。start指出被加鎖或解鎖的內(nèi)存區(qū),len指出加鎖或解鎖的內(nèi)存區(qū)大小。flags的值可以是MCL_CURRENT和MCL_FUTURE之一或者兩個都有。MCL_CURRENT在調(diào)用返回前請求鎖住所有內(nèi)存頁面,MCL

18、_FUTURE指出鎖住所有增加到進(jìn)程的地址空間的內(nèi)存頁面。(mlock的操作結(jié)果是vma的屬性,VM_LOCKED. 作用是被lock的內(nèi)存不參加swap,保證一直存在于內(nèi)存中.內(nèi)核中具體的策略執(zhí)行可以看函數(shù) swap_out_vma.當(dāng)使用exec的時候,lock失效. fork的子進(jìn)程也不繼承此屬性.對于實(shí)時進(jìn)程和安全程序,此調(diào)用很有意義.對于加密程序,密碼不會被dump到磁盤上. 但是lock并不能阻止系統(tǒng)休眠的時候內(nèi)存被存儲到磁盤.mlock,munlock的操作不可堆疊. 多次調(diào)用mlock的一段內(nèi)存也會被一次unlock操作解鎖.mlock/munlock指定的地址會被round

19、down到一個page的邊界.)mremap函數(shù)的使用mremap函數(shù)用于改變一個被映像的文件大小。原型:? #include ? void *mremap(void *old_addr, size_t old_len, size_t new_len, unsigned long flags);mremap用指定的flags把地址在old_addr的內(nèi)存映像大小從old_len調(diào)整為new_len,flags如果為MREMAP_MAYMOVE則調(diào)整此內(nèi)存映像的地址。成功返回新地址,失敗返回NULL。(內(nèi)核要做事情是:改變線性區(qū)對象的長度。內(nèi)核會檢查是否可以直接擴(kuò)大或者縮小線性區(qū)的大小,如果線性

20、對象相鄰的線性空間已經(jīng)被使用了,此時將沒法擴(kuò)大了,如果此時設(shè)置了MREMAP_MAYMOVE標(biāo)志,將會重新分配一塊新的線性空間,顯然這個空間的起始地址已經(jīng)改變)(四)IPC共享存儲(包含實(shí)現(xiàn)原理說明)IPC共享存儲允許兩個或多個進(jìn)程共享一給定的存儲區(qū)。因為數(shù)據(jù)不需要在客戶機(jī)和服務(wù)器之間復(fù)制,所以這是最快的一種IPC。使用共享存儲的唯一竅門是多個進(jìn)程之間對一給定存儲區(qū)的同步存取。若服務(wù)器將數(shù)據(jù)放入共享存儲區(qū),則在服務(wù)器做完這一操作之前,客戶機(jī)不應(yīng)當(dāng)去取這些數(shù)據(jù)。通常,信號量被用來實(shí)現(xiàn)對共享存儲存取的同步。調(diào)用的第一個函數(shù)通常是shmget,它獲得一個共享存儲標(biāo)識符。#include #inclu

21、de int shmget(key_t key, size_t size, int shmflg);如果參數(shù)key為 IPC_PRIVATE。則會建立新的共享內(nèi)存對象其大小由size(單位字節(jié)Byte)指定,如果key不為IPC_PRIVATE,并且存在鍵值為key的共享內(nèi)存對象,則返回所關(guān)聯(lián)的id號,如果不存在鍵值為key的共享內(nèi)存對象,那么系統(tǒng)會視參數(shù)shmflg是否有IPC_CREAT來決定是否新建一個共享內(nèi)存對象。(每個共享內(nèi)存對象都對應(yīng)一個目錄對象和一個inode對象,每個inode對象都包含一個address_space i_mapping對象,但是這些對象并沒有磁盤映像,而是為了

22、可以重復(fù)利用文件映射中提供的代碼,每個進(jìn)程映射的物理頁就存儲在i_mapping對象里。)(以上是一種特殊的文件系統(tǒng),它并沒有掛載在某個目錄下,只是為了方便實(shí)現(xiàn)共享內(nèi)存) size是要建立共享內(nèi)存的長度。所有的內(nèi)存分配操作都是以頁為單位的。實(shí)際的大小是((bytes進(jìn)位到4096整數(shù)倍)/4096 + 4) * 4096。(因為線性區(qū)和物理內(nèi)存的分配都是以頁為單位) shmflg主要和一些標(biāo)志有關(guān),其中有效的包括IPC_CREAT和IPC_EXCL,它們的功能與open()的O_CREAT和O_EXCL相當(dāng)。 IPC_CREAT 如果共享內(nèi)存不存在,則創(chuàng)建一個共享內(nèi)存,否則打開操作。 IPC_

23、EXCL 只有在共享內(nèi)存不存在的時候,新的共享內(nèi)存才建立,否則就產(chǎn)生錯誤。如果單獨(dú)使用IPC_CREAT,shmget()函數(shù)要么返回一個已經(jīng)存在的共享內(nèi)存的操作符,要么返回一個新建的共享內(nèi)存的標(biāo)識符。如果將IPC_CREAT和IPC_EXCL標(biāo)志一起使用,shmget()將返回一個新建的共享內(nèi)存的標(biāo)識符;如果該共享內(nèi)存已存在,或者返回-1。IPC_EXEL標(biāo)志本身并沒有太大的意義,但是和IPC_CREAT標(biāo)志一起使用可以用來保證所得的對象是新建的,而不是打開已有的對象。返回值成功返回共享內(nèi)存的標(biāo)識符;不成功返回-1,errno儲存錯誤原因。 EINVAL 參數(shù)size小于SHMMIN或大于S

24、HMMAX。 EEXIST 預(yù)建立key所致的共享內(nèi)存,但已經(jīng)存在。 EIDRM 參數(shù)key所致的共享內(nèi)存已經(jīng)刪除。 ENOSPC 超過了系統(tǒng)允許建立的共享內(nèi)存的最大值(SHMALL )。 ENOENT 參數(shù)key所指的共享內(nèi)存不存在,參數(shù)shmflg也未設(shè)IPC_CREAT位。 EACCES 沒有權(quán)限。 ENOMEM 核心內(nèi)存不足。struct shmid_ds shmid_ds數(shù)據(jù)結(jié)構(gòu)表示每個新建的共享內(nèi)存。當(dāng)shmget()創(chuàng)建了一塊新的共享內(nèi)存后,返回一個可以用于引用該共享內(nèi)存的shmid_ds數(shù)據(jù)結(jié)構(gòu)的標(biāo)識符。include/linux/shm.h struct shmid_ds s

25、truct ipc_perm shm_perm; /* operation perms */ int shm_segsz; /* 共享內(nèi)存的大小 */ _kernel_time_t shm_atime; /* 最后一次附加這個共享內(nèi)存的時間 */ _kernel_time_t shm_dtime; /*最后一次分離這個共享內(nèi)存的時間 */ _kernel_time_t shm_ctime; /*最后一次改變這個共享內(nèi)存結(jié)構(gòu)的時間*/ _kernel_ipc_pid_t shm_cpid; /* 建立這個共享內(nèi)存的進(jìn)程識別碼 */ _kernel_ipc_pid_t shm_lpid; /*最后

26、一個操作共享內(nèi)存的進(jìn)程識別碼*/ unsigned short shm_nattch; /* 附加這個共享內(nèi)存的進(jìn)程個數(shù) */ unsigned short shm_unused; /* compatibility */ void *shm_unused2; /* ditto - used by DIPC */ void *shm_unused3; /* unused */ ;struct ipc_perm 對于每個IPC對象,系統(tǒng)共用一個struct ipc_perm的數(shù)據(jù)結(jié)構(gòu)來存放權(quán)限信息,以確定一個ipc操作是否可以訪問該IPC對象。 struct ipc_perm _kernel_ke

27、y_t key; /共享內(nèi)存對象的key _kernel_uid_t uid; /共享內(nèi)存所屬的用戶識別碼(可以修改) _kernel_gid_t gid; /共享內(nèi)存所屬的組識別碼(可以修改) _kernel_uid_t cuid; /建立共享內(nèi)對象的用戶識別碼 _kernel_gid_t cgid; /建立共享內(nèi)對象的組識別碼 _kernel_mode_t mode; /這個共享內(nèi)存的讀寫權(quán)限(可以修改) unsigned short seq; /序號;shmctl函數(shù)對共享存儲段執(zhí)行多種操作。#include #include #include int shmctl(int shmid,

28、 int cmd, struct shmid_ds * buf) ;返回:若成功則為0,若出錯則為- 1cmd參數(shù)指定下列5種命令中一種,使其在shmid指定的段上執(zhí)行。? IPC_STAT 對此段取shmid_ds結(jié)構(gòu),并存放在由buf指向的結(jié)構(gòu)中。? IPC_SET按buf指向的結(jié)構(gòu)中的值設(shè)置與此段相關(guān)結(jié)構(gòu)中的下列三個字段:(只能修改這3個字段)shm_perm.uid、shm_perm.gid以及shm_perm.mode。此命令只能由下列兩種進(jìn)程執(zhí)行:一種是其有效用戶ID等于shm_perm.cuid或shm_perm.uid的進(jìn)程;另一種是具有超級用戶特權(quán)的進(jìn)程。? IPC_RMID

29、 從系統(tǒng)中刪除該共享存儲段。因為每個共享存儲段有一個連接計數(shù)(shm_nattch在shmid_ds結(jié)構(gòu)中),所以除非使用該段的最后一個進(jìn)程終止或與該段脫接,否則不會實(shí)際上刪除該存儲段。不管此段是否仍在使用,該段標(biāo)識符立即被刪除,所以不能再用shmat與該段連接。此命令只能由下列兩種進(jìn)程執(zhí)行:一種是其有效用戶ID等于shm_perm.cuid或shm_perm.uid的進(jìn)程;另一種是具有超級用戶特權(quán)的進(jìn)程。? SHM_LOCK鎖住共享存儲段。此命令只能由超級用戶執(zhí)行。? SHM_UNLOCK解鎖共享存儲段。此命令只能由超級用戶執(zhí)行。一旦創(chuàng)建了一個共享存儲段,進(jìn)程就可調(diào)用shmat將其連接到它的

30、地址空間中。#include #include #include void *shmat(int shmid, void *addr, int flag) ;返回:若成功則為指向共享存儲段的指針,若出錯則為- 1。共享存儲段連接到調(diào)用進(jìn)程的哪個地址上與addr參數(shù)以及在flag中是否指定SHM_RND位有關(guān)。(1) 如果addr為0,則此段連接到由內(nèi)核選擇的第一個可用地址上。(2) 如果addr非0,并且沒有指定SHM_RND,則此段連接到addr所指定的地址上。(3) 如果addr非0,并且指定了SHM_RND,則此段連接到( addr(addr mod SHMLBA))所表示的地址上。SH

31、M_RND命令的意思是:取整。SHMLBA的意思是:低邊界地址倍數(shù),它總是2的乘方。該算式是將地址向下取最近1個SHMLBA的倍數(shù)。除非只計劃在一種硬件上運(yùn)行應(yīng)用程序(這在當(dāng)今是不大可能的),否則不用指定共享段所連接到的地址。所以一般應(yīng)指定addr為0,以便由內(nèi)核選擇地址。如果在f l a g中指定了SHM_RDONLY位,則以只讀方式連接此段。否則以讀寫方式連接此段。(在進(jìn)程頁表項中設(shè)置只讀標(biāo)志,試圖修改該頁時將產(chǎn)生缺頁異常,這些都是由CPU的頁尋址硬件控制的)shmat的返回值是該段所連接的實(shí)際地址,如果出錯則返回1。當(dāng)對共享存儲段的操作已經(jīng)結(jié)束時,則調(diào)用shmdt脫接該段。注意,這并不從

32、系統(tǒng)中刪除其標(biāo)識符以及其數(shù)據(jù)結(jié)構(gòu)。該標(biāo)識符仍然存在,直至某個進(jìn)程(一般是服務(wù)器)調(diào)用shmctl(帶命令I(lǐng)P C_RMID)特地刪除它。(連接是進(jìn)程將共享內(nèi)存的物理頁加入進(jìn)程頁表,脫離是從頁表中撤銷該物理頁的信息,并不改變實(shí)際的物理頁)#include #include #include int shmdt(void * addr);返回:若成功則為0,若出錯則為- 1addr參數(shù)是以前調(diào)用shmat時的返回值。下面是和IPC共享內(nèi)存有關(guān)的內(nèi)核參數(shù),可以修改的。其中shmall是所有共享內(nèi)存段可以使用的最大頁個數(shù)shmmni是一個共享內(nèi)存段的最小字節(jié)數(shù)shmmax是一個共享內(nèi)存段的最大字節(jié)數(shù)下

33、面是顯示系統(tǒng)中已近建立的共享內(nèi)存對象其中bytes是申請共享內(nèi)存時使用的大小參數(shù),實(shí)際的大小是((bytes進(jìn)位到4096整數(shù)倍)/4096 + 4) * 4096。nattch是附加此共享內(nèi)存對象的進(jìn)程數(shù)。例子程序:#include #include #include #include #include #include #include #define KEY 4 #define SIZE 4096*3 int main(int argc, char *argv)int shmid = 0, ret = 0;char *shmaddr = 0;struct shmid_ds buf;shm

34、id = shmget(KEY, SIZE, IPC_CREAT | SHM_R);printf(id: %dn, shmid);shmaddr = (char *)shmat(shmid, NULL, 0);*(shmaddr + 4095*3) = c;shmdt(shmaddr); 使用ipcs m 查看建立的共享內(nèi)存對象:要理解IPC共享內(nèi)存和文件映射的實(shí)現(xiàn)機(jī)制,先要理解什么是共享內(nèi)存,共享內(nèi)存實(shí)現(xiàn)的基本原理是什么。(五)共享內(nèi)存實(shí)現(xiàn)基本原理CPU要訪問某塊內(nèi)存,必須要獲得內(nèi)存的物理地址。CPU集成有尋址硬件,會根據(jù)機(jī)器語言指令中提供的地址,執(zhí)行地址轉(zhuǎn)換,獲得的物理地址。CPU有兩種轉(zhuǎn)

35、換模式:1.實(shí)模式 2.保護(hù)模式。實(shí)模式下的物理地址 = 線性地址。保護(hù)模式下的物理地址 = 線性地址通過分頁機(jī)制轉(zhuǎn)化為物理地址。啟動保護(hù)模式:把CPU控制寄存器CR0中的最高位置1。CPU保護(hù)模式尋址方式:圖1 分頁機(jī)制尋址說明:CR3控制寄存器的值是物理地址。由于尋找的是頁框的物理地址,所以CR3,頁目錄和頁表中存儲的物理地址后12位都為0。也就是這12位的空間不存儲物理地址,而是用于訪問控制(可讀/可寫/CPU特權(quán)級別),指示對應(yīng)的頁是否存在等作用。在轉(zhuǎn)換過程中,出現(xiàn)以下情況之一將會引起也異常:涉及的頁目錄表內(nèi)的表項或頁表內(nèi)的表項中的P=0,即涉及到的頁不在內(nèi)存;違反也保護(hù)屬性的規(guī)定而對

36、頁進(jìn)行訪問。注意:從2.6.11版本開始,采用了四級分頁模型,但基本原理是一樣的。每個進(jìn)程的CR3的值是不同,進(jìn)程切換時保存或者恢復(fù)CR3的值。只要設(shè)置了CR3的值CPU將自動進(jìn)行尋址。要將某個物理頁加入進(jìn)程的地址空間,要做的事情就是將物理頁的物理地址填寫進(jìn)程頁目錄表內(nèi)的表項和頁表內(nèi)的表項。共享內(nèi)存實(shí)現(xiàn)原理就是:將相同的物理頁加入不同進(jìn)程的地址空間。顯然進(jìn)程中要加入一塊物理頁,就必須對應(yīng)一塊線性空間,于是就要先申請一塊線性空間,然后根據(jù)這塊線性空間填寫頁目錄表內(nèi)的表項和頁表內(nèi)的表項。(這里可以說明為什么不同進(jìn)程中的不同線性地址可以對應(yīng)相同的物理地址)。由于linux會先分配線性空間,頁表的修改

37、會推后進(jìn)行。Linux通過vm_area_struct對象實(shí)現(xiàn)線性區(qū),當(dāng)產(chǎn)生缺頁異常時,會根據(jù)vm_area_struct對象來修改頁表,然后重新執(zhí)行產(chǎn)生缺頁異常的代碼??偟膩碚f,內(nèi)核實(shí)際要做的事情是很多的,但是,內(nèi)核也提供了很多接口,所以我們要做的事情還是比較少的。以上就是共享內(nèi)存實(shí)現(xiàn)的基本原理,下面分析一下IPC共享內(nèi)存和內(nèi)存映射實(shí)現(xiàn)機(jī)制。實(shí)際上IPC共享內(nèi)存的實(shí)現(xiàn)是基于內(nèi)存映射,原因是:內(nèi)存映射提供了一些接口,基于內(nèi)存映射來實(shí)現(xiàn)IPC共享內(nèi)存可以復(fù)用這些代碼。但是,兩者最終的實(shí)現(xiàn)原理還是修改頁表。(六)IPC共享內(nèi)存實(shí)現(xiàn)機(jī)制先看一下內(nèi)核是如何組織共享內(nèi)存對象的,如圖2所示:圖2 共享內(nèi)存

38、對象組織其中struct shmid_kernel就是一個共享內(nèi)存對象,使用id radix tree來組織所有的共享內(nèi)存對象。使用id號查找一個共享內(nèi)存對象。我們現(xiàn)在最關(guān)心的問題是:如何根據(jù)struct shmid_kernel結(jié)構(gòu)獲得對象所擁有的物理內(nèi)存。是根據(jù)file-f_path.dentry-d_inodestruct address_space *mapping = inode-i_mappingmapping存儲著共享內(nèi)存擁有的物理頁,如圖3所示:圖3 共享內(nèi)存物理頁存儲方式其中page_tree用于存儲物理頁,每個節(jié)點(diǎn)的值類型是struct page *每個共享內(nèi)存對象對應(yīng)一個

39、inode對象,這個對象是被多個進(jìn)程共享,也就是說,進(jìn)程是通過inode對象獲得物理頁。這里借用了文件映射的框架,i_mmaping對象也就是文件的頁高速緩存。進(jìn)程映射共享內(nèi)存區(qū)域的過程:1.需要申請一塊線性地址空間,也就是生成一個vm_area_struct對象,并將對象加入到自己的地址空間,當(dāng)此時并不修改進(jìn)程頁表,而是把struct file對象加入到vm_area_struct對象中,執(zhí)行以下代碼:vma-vm_file = file;get_file(file);error = file-f_op-mmap(file, vma);注意:這里的file是根據(jù)shm_file生成的一個新的

40、對象,相當(dāng)于shm_file的復(fù)制。2. 當(dāng)?shù)谝淮卧L問共享內(nèi)存塊時,由于相應(yīng)的頁表項還未填寫,將產(chǎn)生缺頁異常,內(nèi)核根據(jù)產(chǎn)生異常的線性地址找到對應(yīng)的vm_area_struct對象,最后將執(zhí)行以下函數(shù):static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)struct inode *inode = vma-vm_file-f_path.dentry-d_inode;int error;int ret;if (loff_t)vmf-pgoff = i_size_read(inode)return VM_FAULT_SIGBUS;error = shmem_getpage(inode, vmf-pgoff, &vmf-page, SGP_CACHE, &ret);if (error)return (error = -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS);return ret | VM_FAULT_LOCKED;本函數(shù)的功能是:根據(jù)產(chǎn)生缺頁異常的線性地址找到對應(yīng)的物理頁,并將這個物理頁加入頁表。以上說明的也就是內(nèi)存映射實(shí)現(xiàn)機(jī)制,現(xiàn)在做個總結(jié):調(diào)用do_mmap()函數(shù)生成并注冊一個線性對象,同

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論