一.基于时间片轮转调度代码的解读

代码结构主要由三个文件组成:

1.mypcb.h

2.myinterrupt.c

3.mymain.c

1.进程控制块(mypcb.h)

/* CPU-specific state of this task */
struct Thread{
unsigned long ip; //eip,程序入口地址
unsigned long sp; //堆栈esp栈顶地址
}; typedef struct PCB{
int pid; //进程pid号
volatile long state; //进程运行状态,-1 unrunnable,0 runnable,>0 stopped
char stack[KERNEL_STACK_SIZE]; //进程的栈空间
/* CPU-specific state of this task */
struct Thread thread; //CPU的相关状态
unsigned long task_entry; //进程运行对应的函数
struct PCB *next; //下一个进程块地址
}tPCB; void my_schedule(void);

这里进程控制块(PCB)是采用链表的形式链接起来的。

2.进程的切换(myinterrupt.c)

extern tPCB task[MAX_TASK_NUM]; //进程控制块数组
extern tPCB *my_current_task; //当前对应的进程控制块
extern volatile int my_need_sched; //标志字段,来表示是否需要对进程进行调度 //时钟中断,周期性调用这个函数
void my_timer_handler(void){
#if 1
if(time_count%== && my_need_sched!=){
printk(KERN_NOTICE">>>my_timer_handler here<<<\n");
my_need_sched=;
} time_count++;
#endif
return;
}

接下来是进程上下文切换最关键的代码(my_schedule函数),采用的是内嵌汇编代码

当下一个进程的状态是正在运行时,则

if(next->state==){// -1 unrunnable,0 runnable,>0 stopped
/*switch to next process */
asm volatile(
"pushl %%ebp\n\t" //保存当前进程的栈基址指针 ebp
"movl %%esp,%0\n\t" //保存当前进程的栈顶指针 esp
"movl %2,%%esp\n\t" //回复下一个进程的栈顶指针 esp
"movl $1f,%1\n\t" //将当前进程的下一个指令地址保存到thread.ip中
"pushl %3\n\t" //将下一个进程的指令执行地址入栈
"ret\n\t" //ip出栈,
"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)
);
}

若下一个进程是新的进程,还没有执行过,基本方式与上面差不多,也是基于内嵌汇编方式实现上下文切换。

3.内核代码运行(mymain.c)

 内核从my_start_kernel开始执行,my_start_kernel主要是进行进程控制块的初始化,同时启动0号进程。

void __init my_start_kernel(void)
{
int pid = ;
int i;
/* Initialize process 0*/
task[pid].pid = pid;
task[pid].state = ;/* -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-];
task[pid].next = &task[pid];
/*fork more process */
for(i=;i<MAX_TASK_NUM;i++)
{
memcpy(&task[i],&task[],sizeof(tPCB));
task[i].pid = i;
task[i].state = -;
task[i].thread.sp = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE-];
task[i].next = task[i-].next;
task[i-].next = &task[i];
}
/* start process 0 by task[0] */
pid = ;
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*/
);
}

然后0号进程开始执行my_process函数。

4.程序运行的结果

二.实验总结

通过完成这个简单的时间片轮转多道程序的实验,让我更加深刻的理解了进程上下文切换的原理,以及内核启动的初始化过程。

《Linux内核分析》 week2作业-时间片轮转的更多相关文章

  1. 《linux内核分析》作业一:分析汇编代码

    通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的(王海宁) 姓名:王海宁                             学号:20135103 课程:<Linux内核分析& ...

  2. Linux内核分析

    通过分析汇编代码理解计算机是如何工作的   网易云课堂<Linux内核分析>作业 实验目的: 通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的 实验过程: 登陆实验楼虚拟机h ...

  3. 分析Linux内核中进程的调度(时间片轮转)-《Linux内核分析》Week2作业

    1.环境的搭建: 这个可以参考孟宁老师的github:mykernel,这里不再进行赘述.主要是就是下载Linux3.9的代码,然后安装孟宁老师编写的patch,最后进行编译. 2.代码的解读 课上的 ...

  4. linux内核分析作业:操作系统是如何工作的进行:完成一个简单的时间片轮转多道程序内核代码

    计算机如何工作 三个法宝:存储程序计算机.函数调用堆栈.中断机制. 堆栈 函数调用框架 传递参数 保存返回地址 提供局部变量空间 堆栈相关的寄存器 Esp 堆栈指针  (stack pointer) ...

  5. Linux内核分析—完成一个简单的时间片轮转多道程序内核代码

    ---恢复内容开始--- 20135125陈智威 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-10 ...

  6. Linux内核启动分析过程-《Linux内核分析》week3作业

    环境搭建 环境的搭建参考课件,主要就是编译内核源码和生成镜像 start_kernel 从start_kernel开始,才真正进入了Linux内核的启动过程.我们可以把start_kernel看做平时 ...

  7. Linux内核分析作业 NO.2

    操作系统是如何工作的 于佳心 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000  ...

  8. Linux内核分析:完成一个简单的时间片轮转多道程序内核代码

    PS.贺邦   原创作品转载请注明出处  <Linux内核分析>MOOC课程    http://mooc.study.163.com/course/USTC-1000029000 1.m ...

  9. Linux内核分析作业第二周

    操作系统是如何工作的 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.函数调用堆栈 1.计算机工作三 ...

  10. Linux内核分析作业二

    贾瑗 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000  一.操作系统是如 ...

随机推荐

  1. Asp.net中request.QueryString与request.Params的区别 【转】

    Request.Form:获取以POST方式提交的数据(接收Form提交来的数据): Request.QueryString:获取地址栏参数(以GET方式提交的数据) Request:包含以上两种方式 ...

  2. BZOJ 3065 带插入区间K小值

    http://www.lydsy.com/JudgeOnline/problem.php?id=3065 思路:替罪羊树套权值线段树. 当替罪羊树某个子树大于某个比利(比例)时就暴力重构,本题时间复杂 ...

  3. C51指针的使用

    指针就是指变量或数据所在的存储区地址.如一个字符型的变量 STR 存放在内存单元DATA 区的 51H 这个地址中,那么 DATA 区的 51H 地址就是变量 STR 的指针.在 C 语言中指针是一个 ...

  4. 《how to design programs》13章用list构造表

    使用cons构造一个包含多个元素的表十分麻烦,因此scheme提供了list操作,该操作接受任意量的值作为输入以创建一个表,下面是扩展的语法: <prm>=list 扩展的scheme值的 ...

  5. Codeforces Round #312 (Div. 2) A.Lala Land and Apple Trees

    Amr lives in Lala Land. Lala Land is a very beautiful country that is located on a coordinate line. ...

  6. 设计模式学习--复合模式(Compound Pattern)

    设计模式学习--复合模式(Compound Pattern) 概述 ——————————————————————————————————————————————————— 2013年8月4日<H ...

  7. 用js实现的刷新页面

    一.先来看一个简单的例子: 下面以三个页面分别命名为frame.html.top.html.bottom.html为例来具体说明如何做. frame.html 由上(top.html)下(bottom ...

  8. 新建maven工程时pom.xml报错

    新建maven工程时,pom.xml报错:第一行报如下错误:multiple annotations found at this line后添加org.eclipse.m2e相关的plugin配置后, ...

  9. python_Opencv_读取视频

    目标 • 学会读取视频文件,显示视频,保存视频文件 • 学会从摄像头获取并显示视频 • 你将会学习到这些函数:cv2.VideoCapture(),cv2.VideoWrite()用摄像头捕获视频 使 ...

  10. jquery trigger传值

    方法1: var e = $.Event('ok.menu.table', { relatedTarget: $el }) that.$el.trigger(e); 接受方法如下.此时,related ...