日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

写时复制就这么几行代码,还是不会?

發(fā)布時(shí)間:2024/8/23 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 写时复制就这么几行代码,还是不会? 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

作者 | 閃客

來(lái)源 | 低并發(fā)編程

這里講的是 Linux 內(nèi)核里的寫(xiě)時(shí)復(fù)制原理。

寫(xiě)時(shí)復(fù)制的原理網(wǎng)上講述的文章很多,今天來(lái)一篇很直接的文章,通過(guò)看看 Linux 0.11 這個(gè)最簡(jiǎn)單的操作系統(tǒng),從源碼層面把寫(xiě)時(shí)復(fù)制的原理搞清楚。

很簡(jiǎn)單哦,你可別中途就放棄了。

直接干!

哦不行,干之前先來(lái)點(diǎn)儲(chǔ)備知識(shí),如果你已經(jīng)有了這一 pa 可以略過(guò),不過(guò)我估計(jì)你沒(méi)有...

儲(chǔ)備知識(shí)

堅(jiān)持看完這部分,寫(xiě)時(shí)復(fù)制用到的這里的知識(shí)點(diǎn)只有其中一個(gè)位的值而已,但我把周邊也給你講講。

32 位模式下,Intel 設(shè)計(jì)了頁(yè)目錄表頁(yè)表兩種結(jié)構(gòu),用來(lái)給程序員們提供分頁(yè)機(jī)制。

在 Intel Volume-3 Chapter 4.3 Figure 4-4 中給出了頁(yè)表和頁(yè)目錄表的數(shù)據(jù)結(jié)構(gòu),PDE 就是頁(yè)目錄表,PTE 就是頁(yè)表。

大部分的操作系統(tǒng)使用的都是 4KB 的頁(yè)框大小,Linux 0.11 也是,所以我們只看 4KB 頁(yè)大小時(shí)的情況即可。

一個(gè)由程序員給出的邏輯地址,要先經(jīng)過(guò)分段機(jī)制的轉(zhuǎn)化變成線(xiàn)性地址,再經(jīng)過(guò)分頁(yè)機(jī)制的轉(zhuǎn)化變成物理地址

Figure 4-2 給出了線(xiàn)性地址到物理地址,也就是分頁(yè)機(jī)制的轉(zhuǎn)化過(guò)程。

這里的 PDE 就是頁(yè)目錄表,PTE 就是頁(yè)表,剛剛說(shuō)過(guò)了。

在手冊(cè)接下來(lái)的 Table 4-5 和 Table 4-6 中,詳細(xì)解釋了頁(yè)目錄表和頁(yè)表數(shù)據(jù)結(jié)構(gòu)各字段的含義。

Table 4-5 是頁(yè)目錄表。

Table 4-6 是頁(yè)表。

他們幾乎都是一樣的含義,我們就只看頁(yè)表就好了,看一些比較重要的位。

31:12 表示頁(yè)的起始物理地址,加上線(xiàn)性地址的后 12 位偏移地址,就構(gòu)成了最終要訪(fǎng)問(wèn)的內(nèi)存的物理地址,這個(gè)就不說(shuō)了。

第 0 位是 P,表示 Present,存在位。

第 1 位是 RW,表示讀寫(xiě)權(quán)限,0 表示只讀,那么此時(shí)往這個(gè)頁(yè)表示的內(nèi)存范圍內(nèi)寫(xiě)數(shù)據(jù),則不允許。

第 2 位是 US,表示用戶(hù)態(tài)還是內(nèi)核態(tài),0 表示內(nèi)核態(tài),那么此時(shí)用戶(hù)態(tài)的程序往這個(gè)內(nèi)存范圍內(nèi)寫(xiě)數(shù)據(jù),則不允許。

在 Linux 0.11 的 head.s 里,初次為頁(yè)表設(shè)置的值如下。

setup_paging:...movl?$pg0+7,_pg_dir?????/*?set?present?bit/user?r/w?*/movl?$pg1+7,_pg_dir+4???????/*??---------?"?"?---------?*/movl?$pg2+7,_pg_dir+8???????/*??---------?"?"?---------?*/movl?$pg3+7,_pg_dir+12??????/*??---------?"?"?---------?*/movl?$pg3+4092,%edimovl?$0xfff007,%eax?????/*??16Mb?-?4096?+?7?(r/w?user,p)?*/std 1:??stosl...

后三位是 7,用二進(jìn)制表示就是 111,即初始設(shè)置的 4 個(gè)頁(yè)目錄表和 1024 個(gè)頁(yè)表,都是:

存在(1),可讀寫(xiě)(1),用戶(hù)態(tài)(1)

好了,儲(chǔ)備知識(shí)就到這里。

如果你前面沒(méi)讀懂,你只需要知道,頁(yè)表當(dāng)中有一位是表示讀\寫(xiě)的,而 Linux 0.11 初始化時(shí),把它設(shè)置為了 1,表示可讀寫(xiě)。

寫(xiě)時(shí)復(fù)制的本質(zhì)

在調(diào)用 fork() 生成新進(jìn)程時(shí),新進(jìn)程與原進(jìn)程會(huì)共享同一內(nèi)存區(qū)。只有當(dāng)其中一個(gè)進(jìn)程進(jìn)行寫(xiě)操作時(shí),系統(tǒng)才會(huì)為其另外分配內(nèi)存頁(yè)面。

不過(guò)我們考慮寫(xiě)時(shí)復(fù)制并不用這么復(fù)雜,去掉些細(xì)節(jié)就是。

原來(lái)的進(jìn)程通過(guò)自己的頁(yè)表占用了一定范圍的物理內(nèi)存空間。

調(diào)用 fork 創(chuàng)建新進(jìn)程時(shí),原本頁(yè)表和物理地址空間里的內(nèi)容,都要進(jìn)行復(fù)制,因?yàn)檫M(jìn)程的內(nèi)存空間是要隔離的嘛。

但 fork 函數(shù)認(rèn)為,復(fù)制物理地址空間里的內(nèi)容,比較費(fèi)時(shí),所以姑且先只復(fù)制頁(yè)表,物理地址空間的內(nèi)容先不復(fù)制

如果只有讀操作,那就完全沒(méi)有影響,復(fù)不復(fù)制物理地址空間里的內(nèi)容就無(wú)所謂了,這就很賺。但如果有寫(xiě)操作,那就不得不把物理地址空間里的值復(fù)制一份,保證進(jìn)程間的內(nèi)存隔離。

有寫(xiě)操作時(shí),再?gòu)?fù)制物理內(nèi)存,就叫寫(xiě)時(shí)復(fù)制

看看代碼咋寫(xiě)的

有上述的現(xiàn)象,必然是在 fork 時(shí),對(duì)頁(yè)表做了手腳,這回知道為啥儲(chǔ)備知識(shí)里講頁(yè)表結(jié)構(gòu)了吧??

同時(shí),只要有寫(xiě)操作,就會(huì)觸發(fā)寫(xiě)時(shí)復(fù)制這個(gè)邏輯,這是咋做到的呢?答案是通過(guò)中斷,具體是缺頁(yè)中斷

好的,首先來(lái)看 fork。

這里只看其中關(guān)鍵的復(fù)制頁(yè)表的代碼。

int?copy_page_tables(...)?{...//?源頁(yè)表和新頁(yè)表一樣this_page?=?*from_page_table;...//?源頁(yè)表和新頁(yè)表均置為只讀this_page?&=?~2;*from_page_table?=?this_page;... }

還記得知識(shí)儲(chǔ)備當(dāng)中的頁(yè)表結(jié)構(gòu)吧,就是把 R/W 位置 0 了。

用剛剛的 fork 圖表示就是。

那么此時(shí),再次對(duì)這塊物理地址空間進(jìn)行寫(xiě)操作時(shí),就不允許了。

但不允許并不是真的不允許,Intel 會(huì)觸發(fā)一個(gè)缺頁(yè)中斷,具體是 0x14 號(hào)中斷,中斷處理程序里邊怎么處理,那就由 Linux 源碼自由發(fā)揮了。

Linux 0.11 的缺頁(yè)中斷處理函數(shù)的開(kāi)頭是用匯編寫(xiě)的,看著太鬧心了,這里我選 Linux 1.0 的代碼給大家看,邏輯是一樣的。

void?do_page_fault(...,?unsigned?long?error_code)?{...???if?(error_code?&?1)do_wp_page(error_code,?address,?current,?user_esp);elsedo_no_page(error_code,?address,?current,?user_esp);... }

可以看出,根據(jù)中斷異常碼 error_code 的不同,有不同的邏輯。

那觸發(fā)缺頁(yè)中斷的異常碼都有哪些呢?

在 Intel Volume-3 Chapter 4.7 Figure 4-12 中給出。

可以看出,當(dāng) error_code 的第 0 位,也就是存在位為 0 時(shí),會(huì)走 do_no_page 邏輯,其余情況,均走 do_wp_page 邏輯。

我們 fork 的時(shí)候只是將讀寫(xiě)位變成了只讀,存在位仍然是 1 沒(méi)有動(dòng),所以會(huì)走 do_wp_page 邏輯。

void?do_wp_page(unsigned?long?error_code,unsigned?long?address)?{//?后面這一大坨計(jì)算了?address?在頁(yè)表項(xiàng)的指針un_wp_page((unsigned?long?*)(((address>>10)?&?0xffc)?+?(0xfffff000?&*((unsigned?long?*)?((address>>20)?&0xffc))))); }void?un_wp_page(unsigned?long?*?table_entry)?{unsigned?long?old_page,new_page;old_page?=?0xfffff000?&?*table_entry;//?只被引用一次,說(shuō)明沒(méi)有被共享,那只改下讀寫(xiě)屬性就行了if?(mem_map[MAP_NR(old_page)]==1)?{*table_entry?|=?2;invalidate();return;}//?被引用多次,就需要復(fù)制頁(yè)表了new_page=get_free_page();mem_map[MAP_NR(old_page)]--;*table_entry?=?new_page?|?7;invalidate();copy_page(old_page,new_page); }//?刷新頁(yè)變換高速緩沖宏函數(shù) #define?invalidate()?\ __asm__("movl?%%eax,%%cr3"::"a"?(0))

我用圖直接說(shuō)明這段代碼的細(xì)節(jié)。

剛剛 fork 完一個(gè)進(jìn)程,是這個(gè)樣子的對(duì)吧?

這是我們對(duì)著這個(gè)物理空間范圍,寫(xiě)一個(gè)值,就會(huì)觸發(fā)上述函數(shù)。

假如是進(jìn)程 2 寫(xiě)的。

顯然此時(shí)這個(gè)物理空間被引用了大于 1 次,所以要復(fù)制頁(yè)面。

new_page=get_free_page();

并且更改頁(yè)面只讀屬性為可讀寫(xiě)。

*table_entry?=?new_page?|?7;

圖示就是這樣。

是不是很簡(jiǎn)單。

那此時(shí)如果進(jìn)程 1 再寫(xiě)呢?那么引用次數(shù)就等于 1 了,只需要更改下頁(yè)屬性即可,不用進(jìn)行頁(yè)面復(fù)制操作。

if?(mem_map[MAP_NR(old_page)]==1)?...

圖示就是這樣。

就這么簡(jiǎn)單。

是不是從細(xì)節(jié)上看,和你原來(lái)理解的寫(xiě)時(shí)復(fù)制,還有點(diǎn)不同。

缺頁(yè)中斷的處理過(guò)程中,除了寫(xiě)時(shí)復(fù)制原理的 do_wp_page,還有個(gè) do_no_page,是在頁(yè)表項(xiàng)的存在位 P 為 0 時(shí)觸發(fā)的。

這個(gè)和進(jìn)程按需加載內(nèi)存有關(guān),如果還沒(méi)加載到內(nèi)存,會(huì)通過(guò)這個(gè)函數(shù)將磁盤(pán)中的數(shù)據(jù)復(fù)制到內(nèi)存來(lái)~

往期推薦

如果讓你來(lái)設(shè)計(jì)網(wǎng)絡(luò)

這種本機(jī)網(wǎng)絡(luò) IO 方法,性能可以翻倍!

留不住客戶(hù)?該從你的系統(tǒng)上找找原因了!

明明還有大量?jī)?nèi)存,為啥報(bào)錯(cuò)“無(wú)法分配內(nèi)存”?

點(diǎn)分享

點(diǎn)收藏

點(diǎn)點(diǎn)贊

點(diǎn)在看

?

?

總結(jié)

以上是生活随笔為你收集整理的写时复制就这么几行代码,还是不会?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产好片无限资源 | 久久久xxx | 亚洲涩综合 | av香港经典三级级 在线 | 午夜精品一区二区在线观看 | 日日夜夜狠狠 | 久久久免费毛片 | 综合色吧 | www日本com | 日韩av线观看 | 日韩二级片 | 日日夜夜一区二区 | 大奶av| 精品国产乱码久久久久久免费 | 国产免费久久 | 在线网站av | 久久92| 特级av片| 成人在线免费观看网址 | 日韩视频精品在线 | 女性女同性aⅴ免费观女性恋 | 三级在线观看 | 亚色影库| 日韩欧美91| 国产日韩一区二区三区 | av不卡在线免费观看 | 日韩国产欧美一区二区 | 国内少妇毛片视频 | 欧日韩不卡在线视频 | 毛片视频软件 | 91精品在线免费 | 亚洲综合第一 | 在线免费视频一区二区 | 交视频在线播放 | 亚洲aⅴ在线观看 | 一卡二卡三卡四卡 | 自拍视频一区二区 | 亚洲精品aaaa| 亚洲天堂中文字幕在线观看 | 色久阁| 日本在线 | 中文字幕av一区二区三区人妻少妇 | www视频在线观看 | 69人妻精品久久无人专区 | 桃谷绘里香在线观看 | 久久久久久免费精品 | 五月天堂色| 成人精品免费 | 亚洲综合久久婷婷 | 精品小视频 | 青青草中文字幕 | 福利一二区 | 一级在线免费观看 | 最新的黄色网址 | 中文字幕11页中文字幕11页 | 国产成人精品自拍 | 丝袜美腿av在线 | 婷婷色婷婷开心五月四房播播 | 日韩手机看片 | 成人午夜剧场视频网站 | 欧美三区在线观看 | 国产午夜久久 | 久久大陆 | 成人午夜视频免费在线观看 | 国产做爰免费视频观看 | 亚洲の无码国产の无码步美 | 成人久久久久 | 美女啪啪动态图 | a国产免费| 性网爆门事件集合av | 毛片手机在线 | 亚洲啪啪av | 久免费一级suv好看的国产 | 国产一区在线观看视频 | 国产一区91精品张津瑜 | 亚洲天堂视频在线播放 | 日韩国产在线观看 | 中文 欧美 日韩 | 日韩免费高清视频网站 | 黑人操亚洲美女 | 少妇一级淫片免费放2 | 日本一二三区在线视频 | 精品国产a线一区二区三区东京热 | wwwxxxxx日本| 老头老太做爰xxx视频 | 国产高清成人久久 | 欧美偷拍综合 | 亚洲天堂一区在线观看 | 成人精品在线观看 | 16—17女人毛片 | 欧美人与动性xxxxx杂性 | www日日 | 91丨porny丨露出| 国产欧美日韩在线播放 | 青青草国产 | 精品91av | 一级片免费在线观看 | 伊在线久久丫 | 伦理av在线|