2010-11-11 46 views
1

爲什麼以下代碼可以正常工作?POSIX系統上的內存映射文件保持同步

void continuous_mmap (void) 
{ 
struct stat buf; 
int fd = open("file_one", O_RDONLY), i; 
char *contents; 

fstat(fd, &buf); 
contents = mmap(NULL, buf.st_size, PROT_WRITE, MAP_PRIVATE, fd, 0); 
close (fd); 
mprotect(contents, buf.st_size, PROT_READ); 
for (i = 0; i < 15; i++) { 
    printf ("%s\n", contents); 
    sleep (1); 
} 
munmap(contents, buf.st_size); 
} 

首先,文件保持同步(外部編輯和保存文件自動打印更新的內容),即使附加到文件。我的代碼如何能夠訪問超出我已映射的字節數(初始文件大小),而不進行分段?是否因爲mmap總是將系統頁面大小加起來?如果是這樣,這種行爲是否可以依賴於POSIX系統(我在mmap手冊頁中找不到任何此類要求)。

其次,文本如何自動附加'0'?是否因爲非映射字節自動歸零?這種行爲可以依賴嗎?

回答

1

POSIX甚至沒有要求一個不平凡的頁面大小;理論上一個實現可以具有1個字節的「頁面」大小。同樣,從頁面其餘部分讀取文件大小後的零似乎沒有被指定。我可以想象一些破壞的實現漏掉了在這裏被截斷的舊文件內容,但我會認爲一個主要的安全/隱私違規會使這樣的實現在現實世界中無關緊要。當然他們可以用0xDEADBEEF來填補空間,然後你就會失去運氣。

即使您可以假設零填充(這可能是大多數真實世界操作系統的情況),但我會告誡不要使用它。如果您的文件碰巧是系統頁面大小的精確倍數,會發生什麼情況?突然你的代碼崩潰了閱讀過去的最後,或者(可能更糟糕)從一個不相關的頁面讀取,這個頁面恰好映射到你的文件映射附近。這是一個非常非常令人討厭的錯誤,你可能無法捕捉到,因爲擁有一個文本文件的概率是系統頁面大小的精確倍數。

2

是標準說

系統應始終在對象的末尾零填充任何 部分頁面。 此外,系統絕不會將 末尾的對象的最後一個頁面的任何修改部分寫入 末尾。

  • 如果是這樣,可以此行爲將在上POSIX系統一般依賴 (我 找不到在MMAP手冊頁任何這樣的規定 )。

不,我不會這麼做,並非所有的實現都可能符合要求。我曾經見過至少一個相當破壞的實現。

您不應該使用mmap呼叫的此功能,但ftruncate可以根據您的需要延長您的文件。

0

即使映射爲MAP_PRIVATE,您看到文件的外部更新的原因是因爲您尚未寫入映射,因此係統尚未爲您提供文件頁面的私人副本。這種行爲是允許的,但不是必需的。

如果你有你的應用程序修改contents[0]之前的循環,它會而不是看到外部變化。

+0

添加一個'contents [0] ++;內容[0] - ;''在'關閉'之後和'mprotect'沒有幫助之前 - 這個過程仍然會看到這些變化。 – sanjoyd 2010-11-12 06:25:53

+0

@theDigtialEngel:這隻會觸及第一頁,所以我認爲後續頁面仍然是共享的。 – caf 2010-11-12 11:28:44

+0

雖然這在一般情況下會有意義,但我測試此代碼的文件不到一頁紙長。 – sanjoyd 2010-11-13 04:40:42