|
以下希望藉由一個實際可以在user mode運作的API, mmap()% C: z5 A, X+ b
讓programmer能夠感受到MMU這個硬體在系統中所扮演的角色
" t& B& t8 D. Y( ]0 @4 t+ F' s9 w7 Z' t u. H- F: z1 S3 ^
寫linux底下driver的人常常會看到這個東西 mmap()" M" q* [2 X/ i0 W( m/ p
在user mode program裡面假如你用open( "/dev/xxx", ... )6 z' h+ `: i$ z, i, ~
去打開一個檔案系統的節點
5 j4 G% {$ D, `% u5 }. d7 p就可以用這個file descriptor的handler對他做mmap()的動作 L$ q( e4 R$ b9 O5 I+ Y
那這個mmap究竟背後藏了哪些意義?
: ?5 \0 x9 m! b; Q又有哪些硬體在工作才能達成?
0 P5 P0 u! }3 N2 Y+ u2 V7 D6 ?7 q% Y2 H8 E/ i6 t; l4 P [+ a
mmap的字面意義是memory map' N2 J) p4 A! y" T7 Y! s4 v) g
顧名思義就是『記憶體映對』
4 P# d3 N) L$ ~; s簡單來看,就是用mmap()幫你做對映
! y9 \- ?# _# Q: ]; M3 w; o對映好了,對著傳回的address作存取" {! Q, X% \$ {/ k5 Q
就等於對檔案作存取
2 N4 I7 N3 V6 u6 }; p4 x3 u$ [2 |: q7 k3 K; A9 w" B3 F/ d) n: G
1. 首先來看mmap()一般是怎麼被使用的 (這邊可以先不用管要傳什麼參數)0 V/ x4 w( [" W$ d3 r
int fd, mapSize, offset, start;) E- P5 x( a6 q( K; A
char* ptr;
$ h' u; t0 v. j( }8 V3 H" Z" L" U j( P: p1 ?
mapSize = 0x1000; /* 希望映對多大的區塊 */& k3 w9 Z# F# R" S5 F
offset = 0;9 ?' z( Y, e" }; n9 J* h$ B
start = 0;
; w# g. W; d+ y ^/* 打開檔案 */, @ j5 A" P; {: J+ L9 n; W# f2 g
fd = open( "/home/tester/a.txt", O_RDWR | O_SYNC ); : k; h: N7 @" \
/* 作mmap動作,取得一個對應好的address */
" x$ O& m( K$ N- kptr = mmap( 0, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset );
+ }/ G( R2 T6 B% ~# m7 r+ j, ~1 w; Z3 ]* G9 T. h6 @
假如一切順利的話 ptr 就會接到一個address,這個address會對應到a.txt這個檔案所在的起始位置,
/ {) O! Y; H! Y如果這時候我們用 strcpy( ptr, "hello!!" );
& F" m3 V3 C# E/ C( P. I K+ s
0 w4 b% G- L( Q; Ba.txt裡面就會被寫入"hello!!"的字串+ B( |8 ~( q: P" W& U8 u! T0 ~
5 u& s3 M/ g5 S, n- r* | N
2. 假如我寫了兩個程式,都是用mmap()到同一個a.txt,程式會不會出問題? 如果不會,那我既然對同一個檔案作mmap(),那我拿到的ptr不是應該是相同的address?
. ~0 B1 K3 u" Z- [2 e! H, O0 n+ R6 @
答案是:兩個程式可以正常執行,但是這兩個回傳的address不一定相同。7 G2 H& f) Z4 ?' i
why? 為什麼對同一個檔案寫入,也都做同樣的mmap()動作,甚至傳的參數值都相同。
' G. a; @8 r/ e6 B: z+ E為什麼拿到的address可以是不同的? 更奇怪的是,位址不同,還是同樣寫到同一個檔案上頭。
' G3 F n6 r% A! V) m" s
/ [ f2 h" `3 V+ b4 P; H假如這一切都是合理的,那表示雖然這兩個位址不一定相同,其實都是對映同一個地方,表示有某種東西記錄著這個對應關係。而且,兩個program的ptr有時候會一樣,可是有時候又不一樣。唯一個可能是表示兩個process各自保有這些映對的方式。
, z+ H! f' ?# c3 s, T, ^+ ^( B B2 z6 J8 @- f
3. 假設我只寫一個程式,但是mmap()兩次到同一個檔案上呢? 得到的兩個ptr會一樣嗎?/ I6 ~% z% k& s6 C
) x# N) O* X4 E! e0 ^. B7 f2 q答案是:這個兩ptr還是不一樣的,兩個不同program 跑出來的mmap()結果不同也就算了,同一個program呼叫兩次mmap()跑出來的ptr也不一樣,但又都對映著相同的檔案a.txt。因此我們又可以猜測這一個mmap()是動態的,動態去產生一種應對的方式,將傳回的ptr對應到真正的檔案a.txt去,所以同一個process可以對應好幾次,好幾次都用不同的address去對映到相同的檔案上去。6 M0 k) d+ J- l7 I
* V$ C' k6 Q# ]$ t: j綜合上面三種現象,我們合理的懷疑系統裡面存在了一個東西,它讓每一個process可以動態地記錄address的對應關係。並且,每個process各自擁有這個table,而這些對映的關係會動態的反應在這個table當中。/ m( _3 |1 Z1 b- l) p
W$ O8 p& [, I9 [- ^- M$ c
回想一下一個系統有誰會做這種工作,不就是MMU所擔任的重要角色嗎?. D" M2 r0 z2 c6 Q* r$ O! q
每個process各自擁有自己的 page table 當他呼叫mmap()的時候,系統就動態地幫她在這個table上寫上紀錄著 t( E" n, P. t: ]
4 ~6 Y. F$ }! U% w2 ]1 ~
[processA-pgtable]
/ ^+ w8 h- T, @3 v; ?! V0x00008000 ptr1 --> a.txt
5 ] w- s- R: D# {0 X, F& I0xa0008000 ptr2 --> a.txt
* [ z* `/ a3 b" g7 { m! T* h6 W+ `+ G3 _; m
[processB-pgtable]% J1 @4 j+ p/ W* N7 V: V
0x00008000 ptr1 --> a.txt
, H# g2 L9 n- K) t' c) z' l0xb0008000 ptr2 --> a.txt( @& t- a7 Q% r2 G$ F! i
; c$ k- X- i J# }" f
這樣ptr1, ptr2都可以對應到相同的地方,又因為各個process又有不同table,所以有時候ptr1有可能會相同。
9 R9 X, y' Z7 M0 }7 O如此一來,我們終於可以合理的解釋我們觀察mmap()為何對映出來的address會有如此的表現。原來就是MMU被加入,而且OS又被設計成每個process都會各自擁有一個page table來記錄他對記憶體如何解讀。 |
評分
-
查看全部評分
|