linux内核分析-简单的操作系统内核源码解读
来源:互联网 发布:nginx 路径重定向 编辑:程序博客网 时间:2024/05/23 20:28
##《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”学习笔记 ##
源码组成:mypcb.h mymain.c myinterrupt.c
- mypcb.h
#define MAX_TASK_NUM 4 //进程数组链表的最大值#define KERNEL_STACK_SIZE 1024*8 //内核堆栈的大小/* CPU-specific state of this task */struct Thread { unsigned long ip;/*用于保存eip 指向CPU执行的下一条指令的地址*/ unsigned long sp;/*用于保存esp 堆栈指针*/};typedef struct PCB{ int pid; volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ char stack[KERNEL_STACK_SIZE]; /* CPU-specific state of this task */ struct Thread thread; unsigned long task_entry;/*进程入口 本程序中都设置为my_process*/ struct PCB *next; /*进程链表中的下一个进程*/}tPCB;void my_schedule(void);/*用于实现进程上下文的切换调度*/
2.mymain.c
void __init my_start_kernel(void){ int pid = 0; int i; /* Initialize process 0*/ task[pid].pid = pid; task[pid].state = 0;/* -1 unrunnable, 0 runnable, >0 stopped */ /*进程入口地址与进程的eip设为my_process*/ 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 more process */ 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]; } /* start process 0 by task[0] */ pid = 0; my_current_task = &task[pid]; /*构建0号进程的堆栈环境 ,启动0号进程 c语言中嵌入汇编代码,格式如下: asm ( 内容 : 输出 :输入 ); 加入volatitle表示不让编译器优化*/ 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) { /*调度标志位,在myinterrupt.c的my_timer_handler()函数中设置*/ my_need_sched = 0; /*主动调用进程列表的下一个进程*/ my_schedule(); } printk(KERN_NOTICE "this is process %d +\n",my_current_task->pid); } }}
3.myinterrupt.c
void my_schedule(void){ tPCB * next; tPCB * prev; 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 */ { /* switch to next process */ asm volatile( /*保存当前进程的ebp esp*/ "pushl %%ebp\n\t" /* save ebp */ "movl %%esp,%0\n\t" /* save esp */ /*构建下一个进程的esp*/ "movl %2,%%esp\n\t" /* restore esp */ /*$1f是指下面标号为1的位置,就是下一个进程启动的位置*/ "movl $1f,%1\n\t" /* save eip */ /*下一个进程eip压栈*/ "pushl %3\n\t" /*恢复现场:eip指向下下个进程的地址ebp恢复为第一条指令压栈保存的ebp*/ "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) ); my_current_task = next; printk(KERN_NOTICE ">>>switch %d to %d<<<\n",prev->pid,next->pid); } 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 */ /*新的进程从来没有执行过,所以栈为空esp与ebp指向同一位置*/ "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; }
4.小结
进程切换过程与函数调用堆栈基本类似
- 保存当前进程的堆栈环境(esp,eip,ebp),首先将当前进程的ebp压栈,并将esp和eip保存在当前进程的结构体中。
- 构建下一进程的堆栈环境。然后下一条进程的thread.sp读出,赋给esp;thread.ip读出赋给eip。若下一条进程是新的进程,处于未运行状态,则新进程堆栈为空,esp与ebp指向同一地址,这种情况与函数调用堆栈更加类似。若下一条进程处于运行态,那么ebp与当前进程的ebp指向同一地址。
- 恢复堆栈环境,为下下个进程做准备。恢复eip,即把执行完成的进程的thread.ip(下一进程的指令地址)赋给eip,上例中所有进程的thread.ip设为my_process。
阅读全文
0 0
- linux内核分析-简单的操作系统内核源码解读
- 一种解读Linux操作系统内核源码的好方法
- 解读linux内核源码的入门方法
- 解读linux内核源码的入门方法
- Linux内核源码分析
- Linux操作系统内核分析方法
- linux操作系统及内核分析
- 深入浅出分析Linux操作系统内核
- 解读linux内核源码的入门方法 [转]
- 通过一个简单的时间片轮转多道程序内核代码,分析linux操作系统系统
- Linux内核源码分析--内核启动
- 如何使解读Linux内核源码
- 解读Linux内核的Oops
- linux内核Makefile的简单分析
- 深入分析Linux内核源码
- 深入分析Linux内核源码
- 深入分析Linux内核源码
- linux 内核中断源码分析
- Java并发编程:CopyOnWriteArrayList
- JZOJ5454. 【NOIP2017提高A组冲刺11.5】仔细的检查
- 使用Scrapy爬取股票数据
- JS基础
- 单元测试的重要性【转自”至简李云“博客】
- linux内核分析-简单的操作系统内核源码解读
- 四周一次课(11月6日) 8.1 类的一般形式 8.2 python构造器 8.3 类的继承
- 关于Python列表的去重
- Hbase入门
- POJ
- 磁盘管理——LVM详解
- Maven(三)
- css雪碧图(css sprite)
- mysql5.7 登陆异常排查