成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

操作系統(tǒng)就是用這兩個面試常考的結(jié)構(gòu)管理的緩沖區(qū)

系統(tǒng) Linux
本系列會以一個讀小說的心態(tài),從開機啟動后的代碼執(zhí)行順序,帶著大家閱讀和賞析 Linux 0.11 全部核心代碼,了解操作系統(tǒng)的技術(shù)細(xì)節(jié)和設(shè)計思想。

新讀者看這里,老讀者直接跳過。

本系列會以一個讀小說的心態(tài),從開機啟動后的代碼執(zhí)行順序,帶著大家閱讀和賞析 Linux 0.11 全部核心代碼,了解操作系統(tǒng)的技術(shù)細(xì)節(jié)和設(shè)計思想。

你會跟著我一起,看著一個操作系統(tǒng)從啥都沒有開始,一步一步最終實現(xiàn)它復(fù)雜又精巧的設(shè)計,讀完這個系列后希望你能發(fā)出感嘆,原來操作系統(tǒng)源碼就是這破玩意。

書接上回,上回書我們說到了進程調(diào)度的初始化,定義了一個長度為 64 的 task 數(shù)組用于管理全部進程的結(jié)構(gòu)。

之后在 GDT 中預(yù)定義了進程調(diào)度需要用到的 TSS 和 LDT 結(jié)構(gòu)。

之后開啟了定時器,準(zhǔn)備迎接時鐘中斷的到來,進而觸發(fā)進程調(diào)度。

那接下來我們就冷靜下,回到 main 函數(shù),繼續(xù)看下一個初始化的過程。 那就是緩沖區(qū)初始化 buffer_init,加油,沒剩多少了!

void main(void) {
...
mem_init(main_memory_start,memory_end);
trap_init();
blk_dev_init();
chr_dev_init();
tty_init();
time_init();
sched_init();
buffer_init(buffer_memory_end);
hd_init();
floppy_init();
sti();
move_to_user_mode();
if (!fork()) {
init();
}
for(;;) pause();
}

首先要注意到,這個函數(shù)傳了個參數(shù) buffer_memory_end,這個是在老早之前就設(shè)置好的,就在第12回 | 管理內(nèi)存前先劃分出三個邊界值,回顧下。

想起來了吧?而且我們在 第13回 | 主內(nèi)存初始化 mem_init 中,用 mem_init 設(shè)置好了主內(nèi)存的管理結(jié)構(gòu) mam_map。

再想不起來那就需要把前面的章節(jié)再讀一讀咯,不然后面越來越難。 前面是把主內(nèi)存區(qū)管理起來了,所以今天就是把剩下的緩沖區(qū)部分,也初始化管理起來。目的就是這么單純,我們看代碼。 我們還是采用之前的方式,就假設(shè)內(nèi)存只有 8M,把一些不相干的分支去掉,方便理解。

extern int end;
struct buffer_head * start_buffer = (struct buffer_head *) &end;

void buffer_init(long buffer_end) {
struct buffer_head * h = start_buffer;
void * b = (void *) buffer_end;
while ( (b -= 1024) >= ((void *) (h+1)) ) {
h->b_dev = 0;
h->b_dirt = 0;
h->b_count = 0;
h->b_lock = 0;
h->b_uptodate = 0;
h->b_wait = NULL;
h->b_next = NULL;
h->b_prev = NULL;
h->b_data = (char *) b;
h->b_prev_free = h-1;
h->b_next_free = h+1;
h++;
}
h--;
free_list = start_buffer;
free_list->b_prev_free = h;
h->b_next_free = free_list;
for (int i=0;i<307;i++)
hash_table[i]=NULL;
}

雖然很長,但其實就造了兩個數(shù)據(jù)結(jié)構(gòu)而已。

不過別急,我們先看這一行代碼。

extern int end;
void buffer_init(long buffer_end) {
struct buffer_head * start_buffer = (struct buffer_head *) &end;
...
}

這里有個外部變量 end,而我們的緩沖區(qū)開始位置start_buffer 就等于這個變量的內(nèi)存地址。

這個外部變量 end 并不是操作系統(tǒng)代碼寫就的,而是由鏈接器 ld 在鏈接整個程序時設(shè)置的一個外部變量,幫我們計算好了整個內(nèi)核代碼的末尾地址。 那在這之前的是內(nèi)核代碼區(qū)域肯定不能用,在這之后的,就給 buffer 用了。所以我們的內(nèi)存分布圖可以更精確一點了。

你看,之前的疑惑解決了吧?很好理解嘛,內(nèi)核程序和緩沖區(qū)的劃分,肯定有個分界線,這個分界線就是 end 變量的值。

這個值定多少合適呢?

像主內(nèi)存和緩沖區(qū)的分界線,就直接代碼里寫死了,就是上圖中的 2M。

可是內(nèi)核程序占多大內(nèi)存在寫的時候完全不知道,就算知道了如果改動一點代碼也會變化,所以就由程序編譯鏈接時由鏈接器程序幫我們把這個內(nèi)核代碼末端的地址計算出來,作為一個外部變量 end 我們拿來即用,就方便多了。

好,回過頭我們再看看,整段代碼創(chuàng)造了哪兩個管理結(jié)構(gòu)? 我們先看這段結(jié)構(gòu)。

void buffer_init(long buffer_end) {
struct buffer_head * h = start_buffer;
void * b = (void *) buffer_end;
while ( (b -= 1024) >= ((void *) (h+1)) ) {
...
h->b_data = (char *) b;
h->b_prev_free = h-1;
h->b_next_free = h+1;
h++;
}
...
}

就倆變量。

一個是 buffer_head 結(jié)構(gòu)的 h,代表緩沖頭,其指針值是 start_buffer,剛剛我們計算過了,就是圖中的內(nèi)核代碼末端地址 end,也就是緩沖區(qū)開頭。 一個是 b,代表緩沖塊,指針值是 buffer_end,也就是圖中的 2M,就是緩沖區(qū)結(jié)尾。 緩沖區(qū)結(jié)尾的 b 每次循環(huán) -1024,也就是一頁的值,緩沖區(qū)結(jié)尾的 h 每次循環(huán) +1(一個 buffer_head 大小的內(nèi)存),直到碰一塊為止。

可以看到,其實這個 b 就代表緩沖塊,h 代表緩沖頭,一個從上往下,一個從下往上。 而且這個過程中,h 被附上了屬性值,其中比較關(guān)鍵的是這個 buffer 所表示的數(shù)據(jù)部分 b_data,也就是指向了上面的緩沖塊 b。

還有這個 buffer 的前后空閑 buffer 的指針b_prev_free 和 b_next_free。

那畫成圖就是如下這樣。

當(dāng)緩沖頭 h 的所有 next 和 prev 指針都指向彼此時,就構(gòu)成了一個雙向鏈表。繼續(xù)看。

void buffer_init(long buffer_end) {
...
free_list = start_buffer;
free_list->b_prev_free = h;
h->b_next_free = free_list;
...
}

這三行代碼,結(jié)合剛剛的雙向鏈表 h,我畫出圖,你就懂了。

看,free_list 指向了緩沖頭雙向鏈表的第一個結(jié)構(gòu),然后就可以順著這個結(jié)構(gòu),從雙向鏈表中遍歷到任何一個緩沖頭結(jié)構(gòu)了,而通過緩沖頭又可以找到這個緩沖頭對應(yīng)的緩沖塊。 簡單說,緩沖頭就是具體緩沖塊的管理結(jié)構(gòu),而 free_list 開頭的雙向鏈表又是緩沖頭的管理結(jié)構(gòu),整個管理體系就這樣建立起來了。

現(xiàn)在,從 free_list 開始遍歷,就可以找到這里的所有內(nèi)容了。

不過,還有最后一個事,能幫助更好管理,往下看。

void buffer_init(long buffer_end) {
...
for (i=0;i<307;i++)
hash_table[i]=NULL;
}

一個 307 大小的 hash_table 數(shù)組,這是干嘛的呢?

其實今天的這個代碼在 buffer.c 中,而 buffer.c 是在 fs 包下的,也就是文件系統(tǒng)包下的。所以它今后是為文件系統(tǒng)而服務(wù),具體是內(nèi)核程序如果需要訪問塊設(shè)備中的數(shù)據(jù),就都需要經(jīng)過緩沖區(qū)來間接地操作。 也就是說,讀取塊設(shè)備的數(shù)據(jù)(硬盤中的數(shù)據(jù)),需要先讀到緩沖區(qū)中,如果緩沖區(qū)已有了,就不用從塊設(shè)備讀取了,直接取走。 那怎么知道緩沖區(qū)已經(jīng)有了要讀取的塊設(shè)備中的數(shù)據(jù)呢?從雙向鏈表從頭遍歷當(dāng)然可以,但是這效率可太低了。所以需要一個 hashmap 的結(jié)構(gòu)方便快速查找,這就是 hash_table 這個數(shù)組的作用。 現(xiàn)在只是初始化這個 hash_table,還并沒有哪個地方用到了它,所以我就先簡單劇透下。

之后當(dāng)要讀取某個塊設(shè)備上的數(shù)據(jù)時,首先要搜索相應(yīng)的緩沖塊,是下面這個函數(shù)。

#define _hashfn(dev,block) (((unsigned)(dev^block))%307)
#define hash(dev,block) hash_table[_hashfn(dev,block)]

// 搜索合適的緩沖塊
struct buffer_head * getblk(int dev,int block) {
...
struct buffer_head bh = get_hash_table(dev,block)
...
}

struct buffer_head * get_hash_table(int dev, int block) {
...
find_buffer(dev,block);
...
}

static struct buffer_head * find_buffer(int dev, int block) {
...
hash(dev,block);
...
}

一路跟下來發(fā)現(xiàn),就是通過

dev^block % 307

(設(shè)備號^邏輯塊號) Mod 307

找到在 hash_table 里的索引下標(biāo),接下來就和 Java 里的 HashMap 類似,如果哈希沖突就形成鏈表,畫成圖就是這樣。

哈希表 + 雙向鏈表,如果刷算法題多了,很容易想到這可以實現(xiàn) LRU 算法,沒錯,之后的緩沖區(qū)使用和棄用,正是這個算法發(fā)揮了作用。

也就是之后在講通過文件系統(tǒng)來讀取硬盤文件時,都需要使用和棄用這個緩沖區(qū)里的內(nèi)容,緩沖區(qū)即是用戶進程的內(nèi)存和硬盤之間的橋梁。

好了好了,再多說幾句就把文件系統(tǒng)里讀操作講出來了,壓力太大,本章還是主要就了解這個緩沖區(qū)的管理工作是如何初始化的,為后面做鋪墊。

回過頭來看看我們目前的進度吧!

void main(void) {
...
mem_init(main_memory_start,memory_end);
trap_init();
blk_dev_init();
chr_dev_init();
tty_init();
time_init();
sched_init();
buffer_init(buffer_memory_end);
hd_init();
floppy_init();

sti();
move_to_user_mode();
if (!fork()) {init();}
for(;;) pause();
}

整個初始化的部分,就差 hd_init 和 floppy_init這兩個塊設(shè)備的初始化還沒講了。

而且幸運的是,floppy_init 是軟盤初始化,現(xiàn)在軟盤幾乎都被淘汰了,計算機中也沒有軟盤驅(qū)動器了,所以這個我們完全可以不看,那就剩下一個hd_init 硬盤初始化了,非常簡單! 還記得小時候我特別喜歡收集軟盤,里面分門別類存上我做的 Flash 動畫,然后在軟盤上的那個紙標(biāo)簽上寫上文字,表示軟盤存了什么,想想看還是回憶呢。

扯遠(yuǎn)了。 之前的各種初始化工作所建立的數(shù)據(jù)結(jié)構(gòu),會在后面各個模塊發(fā)揮最最核心的作用,任何操作系統(tǒng)的管理都離不開這些初始化工作所建立的數(shù)據(jù)結(jié)構(gòu),所以一定要把這些根基搭建好,別急別慌。 等初始化工作全部完成,我會專門用一回給大家梳理一下,大家就盡可能把初始化這一大部分的數(shù)據(jù)結(jié)構(gòu)記在心里吧!


責(zé)任編輯:武曉燕 來源: 低并發(fā)編程
相關(guān)推薦

2009-05-13 09:21:48

2021-12-02 07:50:30

字節(jié)緩沖流使用

2009-09-24 18:16:40

2010-04-07 15:13:50

Unix操作系統(tǒng)

2011-12-14 16:30:42

javanio

2017-01-09 17:03:34

2019-02-27 13:58:29

漏洞緩沖區(qū)溢出系統(tǒng)安全

2009-12-03 09:01:07

兩個Linux操作系統(tǒng)

2011-07-20 10:54:14

C++

2010-12-27 10:21:21

2017-07-04 17:09:10

Map環(huán)形緩沖區(qū)數(shù)據(jù)

2014-07-30 11:21:46

2015-03-06 17:09:10

2010-10-09 14:45:48

2022-03-03 09:20:08

分布式數(shù)據(jù)庫場景

2018-01-26 14:52:43

2009-11-16 17:26:17

Oracle優(yōu)化緩沖區(qū)

2009-11-16 17:08:59

Oracle日志緩沖區(qū)

2021-12-09 09:30:38

字節(jié)流文件緩沖區(qū)

2010-09-08 15:43:18

點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 久一精品| 欧美日韩在线综合 | 古装三级在线播放 | 成人一区二区视频 | 欧美高清hd | 日本一区二区三区在线观看 | 成人三区| 精精国产xxxx视频在线播放7 | 亚洲一区二区三区免费观看 | 91污在线| 草b视频 | av在线免费观看网址 | a在线v| 黄色片免费在线观看 | 久久国产精品免费一区二区三区 | 久久一二 | 国产99久久精品一区二区300 | 免费在线黄色av | 亚洲成人精品一区 | 欧美高清一区 | 国产精品1区 | 久久久久久亚洲精品 | 久久999| 高清一区二区三区 | a级片www| 成人在线视频一区 | 性做久久久久久免费观看欧美 | 欧美日韩亚| 综合五月 | 五月天天色 | 激情一区二区三区 | 午夜精品导航 | 国产成人高清在线观看 | 国产精品免费观看 | 夜夜爽99久久国产综合精品女不卡 | 中文在线一区二区 | 日本高清中文字幕 | 国产伦精品一区二区三区在线 | 福利视频一区 | 欧美日韩在线免费 | 久久影音先锋 |