|
以下希望藉由一個實際可以在user mode運作的API, mmap()
7 ~. c# o4 B" @, e1 d* c2 M% D讓programmer能夠感受到MMU這個硬體在系統中所扮演的角色
' h2 k" k" s( i6 R" r2 m( q; f, p# E$ b5 w# }% j* e9 s
寫linux底下driver的人常常會看到這個東西 mmap()0 x& o3 e' C8 H$ I" I! f' m
在user mode program裡面假如你用open( "/dev/xxx", ... )- x5 [ m( i% T* j4 g' `
去打開一個檔案系統的節點
" {! W1 {0 N7 N% d) ~) I8 X0 D8 |就可以用這個file descriptor的handler對他做mmap()的動作, p4 N5 C* N4 h2 {/ ?9 X
那這個mmap究竟背後藏了哪些意義?# Z; `, f( t& ~! ~
又有哪些硬體在工作才能達成?
E0 d6 o* q* z: y% r g( E c" a% m n3 I5 } y4 j
mmap的字面意義是memory map; R* n7 d6 n0 ^$ A3 u# x
顧名思義就是『記憶體映對』( Z1 f% B& T" X& d+ f# \9 B& R- I
簡單來看,就是用mmap()幫你做對映* y- T! S: F' G2 q+ k
對映好了,對著傳回的address作存取: G* `1 [" X0 C6 V
就等於對檔案作存取
) H- ?# T8 d6 F( A$ `) N2 H
~- |6 H, h8 a" q* T4 x1. 首先來看mmap()一般是怎麼被使用的 (這邊可以先不用管要傳什麼參數); W Y1 o( ]3 L5 h( I
int fd, mapSize, offset, start;
" _+ L; B+ m7 x4 r9 ?char* ptr;, V4 ~& L) F7 B+ @$ ^% D
J, P2 n7 V; G; E. U
mapSize = 0x1000; /* 希望映對多大的區塊 */
9 {- \3 V1 p7 P3 q& A. doffset = 0;' e' u' Y7 J% m' w K, ~% {- D) G8 c
start = 0;$ L! b+ C, T+ N; n2 r: N
/* 打開檔案 */
5 Q& F! j1 K% g# r8 ~4 Dfd = open( "/home/tester/a.txt", O_RDWR | O_SYNC );
$ V4 |8 i' ]) x' K0 ^/* 作mmap動作,取得一個對應好的address */
0 K2 L# w; F% l' `ptr = mmap( 0, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset );
" k: X1 r( ]/ l5 s+ ^$ B$ e
1 y- y+ h! i4 j假如一切順利的話 ptr 就會接到一個address,這個address會對應到a.txt這個檔案所在的起始位置,
0 w3 E0 {' l; e& Z' k5 H- W+ E如果這時候我們用 strcpy( ptr, "hello!!" );
4 N' k0 ~7 J" k+ {1 |. N% L$ v; A1 h2 d- n( I4 _$ \" q( `
a.txt裡面就會被寫入"hello!!"的字串
2 p! ]' X$ u6 w6 a2 N7 q: T: p0 a& }; I6 |) t" g: R: q
2. 假如我寫了兩個程式,都是用mmap()到同一個a.txt,程式會不會出問題? 如果不會,那我既然對同一個檔案作mmap(),那我拿到的ptr不是應該是相同的address?8 x, S$ ]8 a7 Z4 {4 R
8 L9 a6 A" k1 A0 x: J( N答案是:兩個程式可以正常執行,但是這兩個回傳的address不一定相同。
5 @1 i! X. k0 Pwhy? 為什麼對同一個檔案寫入,也都做同樣的mmap()動作,甚至傳的參數值都相同。
4 N7 Q( M+ k4 w; a為什麼拿到的address可以是不同的? 更奇怪的是,位址不同,還是同樣寫到同一個檔案上頭。2 V0 T, L0 P4 i: z$ { }
D( L7 ~- w1 F! A0 n1 p; V
假如這一切都是合理的,那表示雖然這兩個位址不一定相同,其實都是對映同一個地方,表示有某種東西記錄著這個對應關係。而且,兩個program的ptr有時候會一樣,可是有時候又不一樣。唯一個可能是表示兩個process各自保有這些映對的方式。) @: ?6 a2 n1 N3 Y/ g
P& {9 b) e& @0 W3. 假設我只寫一個程式,但是mmap()兩次到同一個檔案上呢? 得到的兩個ptr會一樣嗎?& U) X9 Z; m' V. P5 j' [! L
3 y. ^" t/ j) l; C' ]1 D1 X答案是:這個兩ptr還是不一樣的,兩個不同program 跑出來的mmap()結果不同也就算了,同一個program呼叫兩次mmap()跑出來的ptr也不一樣,但又都對映著相同的檔案a.txt。因此我們又可以猜測這一個mmap()是動態的,動態去產生一種應對的方式,將傳回的ptr對應到真正的檔案a.txt去,所以同一個process可以對應好幾次,好幾次都用不同的address去對映到相同的檔案上去。
! k ]- A2 q: y3 g2 u# B$ q' X5 P9 `# p: v G
綜合上面三種現象,我們合理的懷疑系統裡面存在了一個東西,它讓每一個process可以動態地記錄address的對應關係。並且,每個process各自擁有這個table,而這些對映的關係會動態的反應在這個table當中。
: }( O/ V+ H0 ]% r( O/ B% p9 P I) |/ S8 i# A
回想一下一個系統有誰會做這種工作,不就是MMU所擔任的重要角色嗎?0 K) E, b S2 n; ?& q4 }' `! e
每個process各自擁有自己的 page table 當他呼叫mmap()的時候,系統就動態地幫她在這個table上寫上紀錄著( N* d t% L. ~# [, V4 \
9 O* x( }& X: K) ^5 i1 ][processA-pgtable]0 [3 g; q. W; }" E
0x00008000 ptr1 --> a.txt
$ h/ s9 C2 N& B0 u0xa0008000 ptr2 --> a.txt
1 ~; J6 W% {& P/ r/ ~
2 K) \; \* V5 ^" \" ^% D# X[processB-pgtable]6 g- A( R7 S( G
0x00008000 ptr1 --> a.txt
9 ?8 B) J) p( H0xb0008000 ptr2 --> a.txt
$ o% g& L+ [; ?6 G/ o l3 l4 l1 A2 u, f4 P
這樣ptr1, ptr2都可以對應到相同的地方,又因為各個process又有不同table,所以有時候ptr1有可能會相同。
6 n) J2 O' Q) i0 `3 ]如此一來,我們終於可以合理的解釋我們觀察mmap()為何對映出來的address會有如此的表現。原來就是MMU被加入,而且OS又被設計成每個process都會各自擁有一個page table來記錄他對記憶體如何解讀。 |
評分
-
查看全部評分
|