网易公开课《Linux内核分析》学习心得-mykernel实验的实践和分析
2016-03-03 00:56
537 查看
网易公开课《Linux内核分析》学习心得-mykernel实验的实践和分析
杨怡泽 原创作品转载请注明出处《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000实验
根据实验要求在实验楼中进行实验,输入命令cd LinuxKernel/linux-3.9.4 qemu -kernel arch/x86/boot/bzImage
得到如下结果:
现在程序中只有一个进程不断运行,但是依然可以分析出进程的启动机制。让我们观察一下mymain.c和myinterrupt.c两个文件中的核心代码。
在mymain.c中:
void __init my_start_kernel(void) { int i = 0; while(1) { i++; if(i%100000 == 0) printk(KERN_NOTICE "my_start_kernel here %d \n",i); } }
这段代码是操作系统的入口,从这里开始操作系统开始执行。
myinterrupt.c中,这段代码是用来处理时钟中断的,时钟中断是由linux内核完成,这段代码的主要功能就是将时钟中断进行处理:
void my_timer_handler(void) { printk(KERN_NOTICE "\n>>>>>>>>>>>>>>>>>my_timer_handler here<<<<<<<<<<<<<<<<<<\n\n"); }
现在我们需要在这个的基础上构建一个简单的操作系统。在mykernel文件夹中写入mypcb.h,其主要代码如下:
typedef struct PCB{ int pid; // 表示进程的状态 volatile long state; char stack[KERNEL_STACK_SIZE];// 表示内核的堆栈 /* CPU-specific state of this task */ struct Thread thread; unsigned long task_entry;// 操作系统的程序入口 struct PCB *next;//进程链表 unsigned long priority; }tPCB;
修改mymain.c:
tPCB task[MAX_TASK_NUM]; //task数组 tPCB * my_current_task = NULL; //声明当前task指针 volatile int my_need_sched = 0; //是否需要标志 void my_process(void); unsigned long get_rand(int); void sand_priority(void) { int i; for(i=0;i<MAX_TASK_NUM;i++) task[i].priority=get_rand(PRIORITY_MAX); } void __init my_start_kernel(void) { int pid = 0; //当前进程为0号进程 task[pid].pid = pid; task[pid].state = 0; //状态为正在运行 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 其他进程 */ for(pid=1;pid<MAX_TASK_NUM;pid++) { memcpy(&task[pid],&task[0],sizeof(tPCB)); task[pid].pid = pid; task[pid].state = -1; task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1]; task[pid].priority=get_rand(PRIORITY_MAX); } task[MAX_TASK_NUM-1].next=&task[0]; printk(KERN_NOTICE "\n\n\n\n\n\n system begin :>>>process 0 running!!!<<<\n\n"); pid = 0; //从零号开始执行 my_current_task = &task[pid]; //开始执行 /*嵌入式汇编*/ asm volatile( "movl %1,%%esp\n\t" "pushl %1\n\t" "pushl %0\n\t" "ret\n\t" "popl %%ebp\n\t" : : "c" (task[pid].thread.ip),"d" (task[pid].thread.sp) ); //汇编代码启动0号进程,内核初始化完成 }
这段代码主要是为了启动进程,在asm volatile中初始化完成内核启动0号进程。
修改myinterrupt.c用来启动其他进程和切换进程。如果下一个进程已经执行,则切换进程通过如下代码:
asm volatile( "pushl %%ebp\n\t" /* 保存 ebp */ "movl %%esp,%0\n\t" /* 移动esp到prev->thread.sp处 */ "movl %2,%%esp\n\t" /* 恢复esp */ "movl $1f,%1\n\t" /* 保存 eip */ "pushl %3\n\t" /*调用下一个进程 */ "ret\n\t" /* 恢复 eip */ "1:\t" /* 下一进程开始执行 */ "popl %%ebp\n\t" : "=m" (prev->thread.sp),"=m" (prev->thread.ip) : "m" (next->thread.sp),"m" (next->thread.ip) );
如果下一进程尚未执行,则需要先启动类似进程:
asm volatile( "pushl %%ebp\n\t" "movl %%esp,%0\n\t" "movl %2,%%esp\n\t" "movl %2,%%ebp\n\t" "movl $1f,%1\n\t" "pushl %3\n\t" //保存当前进程的入口 "ret\n\t" : "=m" (prev->thread.sp),"=m" (prev->thread.ip) : "m" (next->thread.sp),"m" (next->thread.ip) );
总结
操作系统的内核通过管理不同进程之间的运行,停止,切换和断点等来实现计算机的运转。当操作系统在运行进程的时候通过实现不同进程之间的切换,来保证每个进程都能顺利进行。当设备满足了读请求时,有一个中断就会通知内核,从而恢复以前的进程继续执行。相关文章推荐
- Linux下使用C语言返回年月日
- VisualSVN Server仓库迁移到Linux(包含所有版本, 权限,用户信息)
- Linux系统运维/vi的额外功能/4
- linux编译器琐碎杂记
- Linux入门学习教程:在Ubuntu 14.04中安装使用搜狗拼音输入法
- linux 进程备忘
- Linux 学习笔记 2016年3月2日, PM 10:01:30
- linux之sort用法
- 源码编译安装gcc-5.3.0
- linux 上 crontab 使用教程
- Windows Linux配置MD3200 的iSCSI的一些笔记
- linux环境变量与本地变量
- CentOS7安装Hadoop2.7完整流程
- Linux系统运维——vi的使用技巧——3
- ubuntu安装图像处理库PIL
- linux 线程备忘
- Linux学习决心书
- linux下安装jdk
- linux hosts文件的修改------利用root权限来vim /etc/hosts
- centOs安装搭建php环境