Linux内核设计第二周
——操作系统工作原理
作者:宋宸宁(20135315)
一、实验过程
图1 执行效果
从图中可以看出,每执行my_ start_ kernel函数两次或一次,my_ time_ hander函数执行一次。
图2 mymain.c文件关键代码部分
图3 myinterrupt.c文件关键代码部分
二、分析分析进程的启动和进程的切换机制(分析见注释)
1、myinterrupt.c
/* * linux/mykernel/myinterrupt.c * * Kernel internal my_timer_handler * * Copyright (C) 2013 Mengning * */ #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 tPCB * my_current_task; extern volatile int my_need_sched; volatile int time_count = 0; /* * Called by timer interrupt. * it runs in the name of current running process, * so it use kernel stack of current running process */ void my_timer_handler(void) { #if 1 if(time_count%1000 == 0 && my_need_sched != 1) { printk(KERN_NOTICE ">>>my_timer_handler here<<< "); my_need_sched = 1; } time_count ++ ; #endif return; } void my_schedule(void) { tPCB * next; tPCB * prev; if(my_current_task == NULL || my_current_task->next == NULL) { return; } printk(KERN_NOTICE ">>>my_schedule<<< "); /* schedule */ next = my_current_task->next; prev = my_current_task; if(next->state == 0)/* -1 unrunnable, 0 runnable, >0 stopped */ { /* 进程切换跳转到下一进程 */ asm volatile( "pushl %%ebp " /* 保存当前ebp */ "movl %%esp,%0 " /* 保存当前esp */ "movl %2,%%esp " /* 重新记录要跳转进程的 esp,%2为 next->thread.sp*/ "movl $1f,%1 " /* 保存当前 eip ,%1为prev->thread.ip*/ "pushl %3 " "ret " /* 记录要跳转进程的 eip,%3为 next->thread.ip*/ "1: " /* 下一个进程开始执行 */ "popl %%ebp " : "=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<<< ",prev->pid,next->pid); } else { next->state = 0; my_current_task = next; printk(KERN_NOTICE ">>>switch %d to %d<<< ",prev->pid,next->pid); /* switch to new process */ asm volatile( "pushl %%ebp " /* 保存当前 ebp */ "movl %%esp,%0 " /* 保存当前 esp */ "movl %2,%%esp " /* 重新记录要跳转进程的 esp ,%2为 next->thread.sp*/ "movl %2,%%ebp " /* 重新记录要跳转进程的 ebp,%2为 next->thread.sp */ "movl $1f,%1 " /* 保存当前 eip ,%1为prev->thread.ip,%1f就是指标号1:的代码在内存中存储的地址*/ "pushl %3 " "ret " /* 重新记录要跳转进程的 eip,%3为 next->thread.ip */ : "=m" (prev->thread.sp),"=m" (prev->thread.ip) : "m" (next->thread.sp),"m" (next->thread.ip) ); } return; }
2、mymain.c
/* * linux/mykernel/mymain.c * * Kernel internal my_start_kernel * * Copyright (C) 2013 Mengning * */ #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数组 tPCB * my_current_task = NULL; //声明当前task指针 volatile int my_need_sched = 0; //是否需要调度标志 void my_process(void); void __init my_start_kernel(void) { int pid = 0; int i; /* 初始化 0号进程*/ 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; /* 实际上是my_process*/ task[pid].thread.sp = (unsigned long)&task[pid].stack[KERNEL_STACK_SIZE-1]; task[pid].next = &task[pid]; // 定义堆栈的栈顶 /*创建更多的子进程*/ 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]; } /* 从0号进程开始启动 */ pid = 0; my_current_task = &task[pid]; asm volatile( "movl %1,%%esp " /* 设置 esp 的值*/ "pushl %1 " /* 将 ebp 压栈(此时esp=ebp),%1相当于task[pid].thread.sp*/ "pushl %0 " /* 将 eip 压栈,%0相当于task[pid].thread.ip*/ "ret " /* 相当于 eip 出栈 */ "popl %%ebp " /* 0号进程正是启动 */ : : "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 - ",my_current_task->pid); if(my_need_sched == 1) { my_need_sched = 0; my_schedule(); } printk(KERN_NOTICE "this is process %d + ",my_current_task->pid); } } }
3、mypcb.h
/* * linux/mykernel/mypcb.h * * Kernel internal PCB types * * Copyright (C) 2013 Mengning * */ #define MAX_TASK_NUM 4 #define KERNEL_STACK_SIZE 1024*8 /* CPU-specific state of this task */ struct Thread { unsigned long ip; //保存eip unsigned long sp; //保存esp }; typedef struct PCB{ int pid; volatile long state; /* 记录进程状态,-1 未运行, 0 运行中, >0 阻塞停止 */ char stack[KERNEL_STACK_SIZE]; /* 定义堆栈结构*/ struct Thread thread; unsigned long task_entry; /* 定义程序入口,通常是main函数*/ struct PCB *next; }tPCB; void my_schedule(void);//调度器函数
三、总结
阐明对“操作系统是如何工作的”的理解。
①操作系统是管理电脑硬件与软件资源的程序,同时也是计算机系统的内核与基石。
②操作系统是管理计算机系统的全部硬件资源包括软件资源及数据资源;控制程序运行;改善人机界面;为其它应用软件提供支持等,使计算机系统所有资源最大限度地发挥作用,为用户提供方便的、有效的、友善的服务界面。
③操作系统是一个庞大的管理控制程序,大致包括5个方面的管理功能:进程与处理机管理、作业管理、存储管理、设备管理、文件管理。
④操作系统通过通过函数调用堆栈和中断机制等,实现其管理功能。