国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 操作系統 > 正文

xv6中存儲cpu和進程信息的技巧

2024-06-28 13:20:01
字體:
來源:轉載
供稿:網友
xv6中存儲cpu和進程信息的技巧

xv6是一個支持多處理器的Unix-like操作系統,

近日閱讀源碼時發現xv6在記錄當前CPU和進程狀態時非常tricky

首先,上代碼:

 1 extern struct cpu cpus[NCPU]; 2 extern int ncpu; 3  4 // Per-CPU variables, holding pointers to the 5 // current cpu and to the current PRocess. 6 // The asm suffix tells gcc to use "%gs:0" to refer to cpu 7 // and "%gs:4" to refer to proc.  seginit sets up the 8 // %gs segment register so that %gs refers to the memory 9 // holding those two variables in the local cpu's struct cpu.10 // This is similar to how thread-local variables are implemented11 // in thread libraries such as linux pthreads.12 extern struct cpu *cpu asm("%gs:0");       // &cpus[cpunum()]13 extern struct proc *proc asm("%gs:4");     // cpus[cpunum()].proc

其中struct cpu是一個用來保存每個cpu運行狀態的結構體,

代碼第一行定義了結構體數組cpus[NCPU],NCPU對應cpu的總數(最大為8),也就是說cpus用來存儲所有cpu的運行狀態

那么問題來了:上面的內核代碼是運行于每個cpu之中的,那每個cpu如何知道自身的當前運行狀態呢?

對于這個問題,我們可以通過lapic獲取cpu自身編號,再利用編號對cpus尋址即可,

也就是說,對于任意一個cpu,自身狀態的存儲位置可以這樣獲得:struct cpu *c = &cpus[cpunum()];

然而,第二個問題來了:我們不可能每次引用cpu自身狀態時都通過lapic獲取編號啊,能不能弄一個全局變量把狀態位置一次性存儲下來呢?

像是這樣,struct cpu *cpu; //全局變量,存儲cpu自身狀態,然后在初始化代碼中cpu = c;

對于記錄每個cpu正在運行的進程也有這樣的問題,能不能寫成:struct proc *proc; //全局變量,存儲當前cpu正在運行的進程狀態

那么,第三個問題來了:每個cpu是獨立并行的,在每個cpu上運行的內核代碼都是一樣的,頁表也一樣,

這意味著全局變量cpu和proc的地址也是一樣的,這樣便不可以用來區分不同cpu的狀態了。

因此,我們需要一種方法,可以讓我們在每個cpu中都用同一個符號記錄狀態,但這些符號卻是映射到不同的地址。

既然頁表一樣,我們自然不能用一個絕對的數值來尋址啦,仔細想想,頁表之上有什么?頁表之上,還有段表啊。

所以我們需要用segment register來尋址,只要我們在建立段表時把該段都映射到不同的內存區域不就可以了,所以我們有了以下聲明:

1 extern struct cpu *cpu asm("%gs:0");       // &cpus[cpunum()]2 extern struct proc *proc asm("%gs:4");     // cpus[cpunum()].proc

我們用gs作為段寄存器,cpu指向[%gs],proc指向[%gs+4],

其中為什么開頭要用extern呢?我問過某大神,他說是因為gs段是在外部建立的,相當于外部定義的。。。

OK,最后一個問題來了,gs段應該指向哪,才能確保每個cpu的gs段都位于不同的區域?

最直觀的想法當然是指向對應的cpus[num]內部啦,所以在struct cpu尾部增加兩個域:

1 struct cpu{2    ........  //cpu狀態3 4    // Cpu-local storage variables; see below5   struct cpu *cpu;6   struct proc *proc;           // The currently-running process.7 }

然后在建立段表時,增加gs段,并映射至尾部這兩個域:

 1   c = &cpus[cpunum()]; 2    3   ......... //建立其他段 4  5   // 建立gs段,共兩個域(存儲cpu和proc地址),起始地址為&c->cpu 6   c->gdt[SEG_KCPU] = SEG(STA_W, &c->cpu, 8, 0); 7  8   //加載gdt 9   lgdt(c->gdt, sizeof(c->gdt));10   //加載gs11   loadgs(SEG_KCPU << 3);12   13   // 把當前cpu和proc狀態的地址賦給cpu和proc全局變量14   //而cpu變量實質為%gs:0, proc變量實質為%gs:415   cpu = c;16   proc = 0;

其實在這里cpu和proc變量跟線程局部存儲的性質差不多,每個處理器都可以引用同一個變量,但這些變量都對應不同的存儲區域。

有可能這種實現技巧跟TLS(線程局部存儲)差不多,有空研究下TLS的實現看看是不是。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 桂平市| 铜山县| 永胜县| 永寿县| 玛多县| 台安县| 新源县| 尉犁县| 盘山县| 岳西县| 荣成市| 石城县| 延川县| 上蔡县| 娄底市| 谷城县| 土默特右旗| 永清县| 克拉玛依市| 讷河市| 白朗县| 盖州市| 平乐县| 广东省| 祁阳县| 安塞县| 四会市| 崇仁县| 江永县| 浦县| 永嘉县| 庄河市| 改则县| 灵宝市| 专栏| 仙游县| 犍为县| 新津县| 银川市| 伊吾县| 原平市|