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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

《Linux内核原理与分析》第三周作业

發(fā)布時間:2025/3/20 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《Linux内核原理与分析》第三周作业 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

實驗:基于kernel的簡單的時間片輪轉(zhuǎn)多道程序內(nèi)核

1、實驗要求

  • 完成一個簡單的時間片輪轉(zhuǎn)多道程序內(nèi)核代碼

    2、實驗過程

  • 進(jìn)入實驗樓的linux環(huán)境,打開shell,輸入以下代碼:
cd LinuxKernel/linux-3.9.4 rm -rf mykernel patch -p1 < ../mykernel_for_linux3.9.4sc.patch make allnoconfig make #編譯內(nèi)核請耐心等待 qemu -kernel arch/x86/boot/bzImage

執(zhí)行的效果如下:

  • 在mykernel的基礎(chǔ)上添加mypcb.h,修改mymain.c和myinterrupt.c文件,實現(xiàn)一個簡單的操作系統(tǒng)內(nèi)核,實現(xiàn)效果如下:

    3、mykernel時間片輪轉(zhuǎn)代碼分析

    mypcb.h
#define MAX_TASK_NUM 4 #define KERNEL_STACK_SIZE 1024*8/* CPU-specific state of this task */ struct Thread {unsigned long ip; //對應(yīng)eipunsigned long sp; //對應(yīng)esp };typedef struct PCB{int pid; //定義進(jìn)程idvolatile long state; //-1 unrunnable, 0 runnable, >0 stoppedchar stack[KERNEL_STACK_SIZE]; //內(nèi)核堆棧/* CPU-specific state of this task */struct Thread thread;unsigned long task_entry; //入口struct PCB *next; }tPCB;void my_schedule(void); //聲明調(diào)度函數(shù)

本mypcb.h頭文件主要定義了程序控制塊PCB,包括:
pid:定義進(jìn)程id
state:進(jìn)程狀態(tài)標(biāo)記,-1是未運行,0為運行,>0為終止
stack:定義使用的堆棧
thread:定義線程
task_entry:進(jìn)程入口
next:鏈表指向下一個PCB

myinterrupt.c

#include <linux/types.h> #include <linux/string.h> #include <linux/ctype.h> #include <linux/tty.h> #include <linux/vmalloc.h> #include "mypcb.h"extern tPCB task[MAX_TASK_NUM]; //extern引用全局變量 extern tPCB * my_current_task; extern volatile int my_need_sched; volatile int time_count = 0;void my_timer_handler(void) //時鐘中斷觸發(fā)本函數(shù) { #if 1if(time_count%100 == 0 && my_need_sched != 1) //當(dāng)時鐘中斷發(fā)生100次,并且my_need_sched不為1時,賦值為1{printk(KERN_NOTICE ">>>my_timer_handler here<<<\n");my_need_sched = 1;} time_count ++ ; #endifreturn; }void my_schedule(void) {tPCB * next; //下一進(jìn)程tPCB * prev; //當(dāng)前進(jìn)程if(my_current_task == NULL || my_current_task->next == NULL){return;}printk(KERN_NOTICE ">>>my_schedule<<<\n");/* schedule */next = my_current_task->next;prev = my_current_task;if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped */ //下一個進(jìn)程可運行,執(zhí)行進(jìn)程切換{my_current_task = next; printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid); /* 切換進(jìn)程 */asm volatile( "pushl %%ebp\n\t" /* save ebp */"movl %%esp,%0\n\t" /* save esp */"movl %2,%%esp\n\t" /* restore esp */"movl $1f,%1\n\t" /* save eip */ "pushl %3\n\t" "ret\n\t" /* restore eip */"1:\t" /* next process start here */"popl %%ebp\n\t": "=m" (prev->thread.sp),"=m" (prev->thread.ip): "m" (next->thread.sp),"m" (next->thread.ip)); }else{next->state = 0;my_current_task = next;printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid);/* switch to new process */asm volatile( "pushl %%ebp\n\t" /* save ebp */"movl %%esp,%0\n\t" /* save esp */"movl %2,%%esp\n\t" /* restore esp */"movl %2,%%ebp\n\t" /* restore ebp */"movl $1f,%1\n\t" /* save eip */ "pushl %3\n\t" "ret\n\t" /* restore eip */: "=m" (prev->thread.sp),"=m" (prev->thread.ip): "m" (next->thread.sp),"m" (next->thread.ip)); } return; }

本c文件中,定義了my_timer_handler和my_schedule兩個函數(shù)調(diào)用,前者是當(dāng)時鐘中斷發(fā)生100次,并且my_need_sched不為1時,賦值為1,是mymain.c中my_process函數(shù)判定主動調(diào)度的標(biāo)志;后者是執(zhí)行調(diào)度的具體過程,下面對切換進(jìn)程的匯編代碼進(jìn)行分析:
"pushl %%ebp\n\t" /* save ebp / ebp入棧
"movl %%esp,%0\n\t" / save esp / 保存當(dāng)前esp到進(jìn)程的sp中
"movl %2,%%esp\n\t" / restore esp / esp指向下一進(jìn)程
"movl $1f,%1\n\t" / save eip / 將1f存儲到進(jìn)程的ip中,$1f是標(biāo)號“1:\t”處,再次調(diào)度到該進(jìn)程時就會從1:開始執(zhí)行
"pushl %3\n\t" 下一進(jìn)程的ip入棧
"ret\n\t" / restore eip / eip指向下一進(jìn)程的起始地址
"1:\t" / next process start here */ 下一進(jìn)程從此處開始執(zhí)行
"popl %%ebp\n\t" 執(zhí)行完后出棧釋放空間
: "=m" (prev->thread.sp),"=m" (prev->thread.ip) 分別對于上面的%0,%1
: "m" (next->thread.sp),"m" (next->thread.ip) 分別對應(yīng)上面的%2,%3

mymain.c

#include <linux/types.h> #include <linux/string.h> #include <linux/ctype.h> #include <linux/tty.h> #include <linux/vmalloc.h> #include "mypcb.h"tPCB task[MAX_TASK_NUM]; //PCB的數(shù)組task tPCB * my_current_task = NULL; //當(dāng)前task指針 volatile int my_need_sched = 0; //是否需要調(diào)度void my_process(void); //my_process函數(shù)聲明void __init my_start_kernel(void) //mykernel內(nèi)核代碼的入口 {int pid = 0;int i;/* 初始化0號進(jìn)程*/task[pid].pid = pid;task[pid].state = 0;/* -1 unrunnable, 0 runnable, >0 stopped */task[pid].task_entry = task[pid].thread.ip = (unsigned long)my_process;task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1];task[pid].next = &task[pid];/*fork其他進(jìn)程 */for(i=1;i<MAX_TASK_NUM;i++){memcpy(&task[i],&task[0],sizeof(tPCB));task[i].pid = i;task[i].state = -1;task[i].thread.sp = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE-1];task[i].next = task[i-1].next;task[i-1].next = &task[i];}/* 用task[0]開始0號進(jìn)程 */pid = 0;my_current_task = &task[pid];asm volatile("movl %1,%%esp\n\t" /* set task[pid].thread.sp to esp */"pushl %1\n\t" /* push ebp */"pushl %0\n\t" /* push task[pid].thread.ip */"ret\n\t" /* pop task[pid].thread.ip to eip */"popl %%ebp\n\t": : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp) /* input c or d mean %ecx/%edx*/); } void my_process(void) {int i = 0;while(1){i++;if(i%10000000 == 0){printk(KERN_NOTICE "this is process %d -\n",my_current_task->pid);if(my_need_sched == 1) //判斷是否需要調(diào)度{my_need_sched = 0;my_schedule(); //這是一個主動調(diào)度}printk(KERN_NOTICE "this is process %d +\n",my_current_task->pid);} } }

本c文件中,有my_start_kernel和my_process兩個函數(shù),其中,前者為mykernel內(nèi)核代碼的入口函數(shù),后者為進(jìn)程的入口函數(shù),進(jìn)程在運行中輸出當(dāng)前進(jìn)程號,并通過my_need_sched變量判斷是否需要調(diào)度。
其中對0號進(jìn)程的啟動匯編代碼進(jìn)行分析:
"movl %1,%%esp\n\t" /* set task[pid].thread.sp to esp / 將當(dāng)前進(jìn)程0的sp賦給esp
"pushl %1\n\t" / push ebp / 進(jìn)程0的sp入棧
"pushl %0\n\t" / push task[pid].thread.ip / 進(jìn)程0的ip入棧
"ret\n\t" / pop task[pid].thread.ip to eip / 將進(jìn)程0的ip賦給eip
"popl %%ebp\n\t" 執(zhí)行完其他進(jìn)程,回到0號進(jìn)程,出棧
:
: "c" (task[pid].thread.ip),"d" (task[pid].thread.sp) / input c or d mean %ecx/%edx*/ 輸入,將0號進(jìn)程的ip、sp值分別存入ecx、edx寄存器中,分別對應(yīng)上面的%0,%1

4、問題與總結(jié)

本次實驗沒有遇到什么重大的問題,但是小毛病犯了一堆,比如在將代碼拷入實驗樓linux環(huán)境的vim中時,實驗樓的粘貼板不知為何復(fù)制粘貼會缺失一段代碼,后在編譯c文件的時候總是報錯,這個問題找了好久,后來發(fā)現(xiàn)是粘貼板粘貼的代碼缺失。還有一個是在make時找不到文件,后來發(fā)現(xiàn)修改代碼是在/mykernel目錄下進(jìn)行修改的,make編譯內(nèi)核需要在LinuxKernel/linux-3.9.4目錄下進(jìn)行,需要返回上一級菜單進(jìn)行make。
總共來講,本周各種事情比較多,學(xué)習(xí)的計劃一拖再拖,推遲了好久才完成,以后一定要合理分配時間,這一點尤為重要。
還有,學(xué)習(xí)要認(rèn)真仔細(xì),盡量避免因為犯低級錯誤而白白消耗大量學(xué)習(xí)時間。

轉(zhuǎn)載于:https://www.cnblogs.com/intoxication/p/9866849.html

總結(jié)

以上是生活随笔為你收集整理的《Linux内核原理与分析》第三周作业的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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