linux简单时间片轮转内核分析

时间片轮转调动算法 时间片轮转调度是一种最古老,最简单,最公平且使用最广的算法。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。 立即下载

操作系统是如何工作的

学号531
本博客围绕操作系统是如何工作的这一问题来进行相关的简单内核编写与分析的实验。
原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/

实验过程

使用实验楼的虚拟机打开shell
实验楼链接: https://www.shiyanlou.com/courses/195

  1. 打开Linux-3.9.4,编译,运行命令如下:
cd LinuxKernel/linux-3.9.4
rm -rf mykernel
patch -p1 < ../mykernel_for_linux3.9.4sc.patch
make allnoconfig
make #编译内核请耐心等待
qemu -kernel arch/x86/boot/bzImage
  1. 运行结果显示如下:
    在这里插入图片描述

  2. 打开linux-3.9.4\mykernel,可以看到mykernel.c和myinterrupt.c文件,打开文件如下,初始化是一个无限循环,每十万次显示一次;
    在这里插入图片描述

  3. 修改mykernel.c和myinterrupt.c文件,新建一个mypcb.h文件,
    文件代码参考自https://github.com/mengning/linuxkernel/;
    再次编译执行后如下:
    在这里插入图片描述
    上图截图显示了进程1切换到进程2。

实验中时间片轮转的内核代码分析

  1. mypcb.h代码分析:
#define MAX_TASK_NUM        4/*最大进程数*/
#define KERNEL_STACK_SIZE   1024*2 /*内核栈大小*/
struct Thread {
    unsigned long		ip;
    unsigned long		sp;
};
typedef struct PCB{
    int pid;
    volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
    unsigned long stack[KERNEL_STACK_SIZE];
    /* */
    struct Thread thread;
    unsigned long	task_entry;
    struct PCB *next;
}tPCB;
void my_schedule(void);

mypcb.h定义了进程控制块结构体;
其中tPCB用于保存进程信息:
thread:线程,其中ip指向下一个线程地址,sp指向栈底;
pid:进程代号;
state:为0时进程可运行,-1时进程不可运行,大于0进程挂起;
stack:进程堆栈;
task_entry:进程入口;
next:指向下一个PCB。

  1. 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];
tPCB * my_current_task = NULL;
volatile int my_need_sched = 0;

void my_process(void);

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 */
    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].stack[KERNEL_STACK_SIZE-1] - 1) = (unsigned long)&task[i].stack[KERNEL_STACK_SIZE-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];
	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 */
    	: 
    	: "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)	/* input c or d mean %ecx/%edx*/
	);
} 

int i = 0;

void my_process(void)
{    
    while(1)
    {
        i++;
        if(i%10000000 == 0)
        {
            printk(KERN_NOTICE "this is process %d -\n",my_current_task->pid);
            if(my_need_sched == 1)
            {
                my_need_sched = 0;
        	    my_schedule();
        	}
        	printk(KERN_NOTICE "this is process %d +\n",my_current_task->pid);
        }     
    }
}

系统启动时,首先调用 my_start_kernel ,即先初始化进程0,其中task_entry指向 my_process(进程运行函数),sp指针指向进程栈尾地址,next指针指向自己;
然后初始化更多进程,并且把新的进程加入到链表中;
接着的汇编代码表示将sp赋给esp,sp与ip压栈,ip给eip;
最后my_process开始循环。

  1. myinterrupt.c主要代码分析:
void my_timer_handler(void)
{
#if 1
	if (time_count % 1000 == 0 && my_need_sched != 1)
	{
		printk(KERN_NOTICE ">>>my_timer_handler here<<<\n\n\n\n\n\n");  /*此处多次换行*/
		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<<<\n");
	/* schedule */
	next = my_current_task->next;
	prev = my_current_task;
	if (next->state == 0) /* -1 unrunnable, 0 runnable, >0 stopped */
	{
		my_current_task = next;
		unsigned ct = 1000000;
		while (ct)
		{
			ct--;
		}
		printk(KERN_NOTICE ">>>switch %d to %d<<<\n", prev->pid, next->pid);
		/* switch to next process */
		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));
	}
	return;
}

my_timer_handler用于时钟相应,通过my_time_handler()函数定时地不断向cpu发出中断,从而实现了时间片轮转。每调用1000次,就去将全局变量my_need_sched的值修改为1,通知正在执行的进程执行调度程序my_schedule。
my_schedule用于完成进程的切换,ebp压栈保存,将esp的值保存到prev->thread.sp中,esp指向next->thread.sp,将1f赋值给prev->thread.ip,next->thread.ip压栈,(第一次执行会指向myprocess()函数而不是1f),next->thread.ip出栈并赋给eip,复位(第一次时执行my_process),即完成进程切换。

实验总结

总的来说,操作系统的工作需要进行进程的启动与切换,切换时需要保存上下文,切换的程序完成后需要恢复上下文,进程切换通过时钟中断进行控制。

设计一个按时间片轮转法实现处理器调度的程序 第二题[提示] (1) 假定系统有五个进程,每一个进程用一个进程控制块PCB来代表。进程控制块的格式为: 进程名 指针 要求运行时间 已运行时间 状态 其中,进程名----作为进程的标识,假设五个进程的进程名分别是Q1,Q2,Q3,Q4,Q5。 指针----进程按顺序排成循环队列,用指针指出下一个进程的进程控制块首地址,最后一个进程中的指针指出第一个进程的进程控制块首地址。 要求运行时间----假设进程需要运行的单位时间数。 已运行时间----假设进程已经运行的单位时间数,初始值为“0”。 状态----有两种状态,“就绪”状态和“结束”状态,初始状态都为“就绪”,用“R”表示,当一个进程运行结束后,它的状态变为“结束”,用“E”表示。 (2) 每次运行你所设计的处理器调度程序之前,为每个进程任意确定它的“要求运行时间”。 把五个进程按顺序排成循环队列,用指针指出队列连接情况。另用一标志单元记录轮到运行的进程。 (3) 处理器调度总是选择标志单元指示的进程运行。由于本实验是模拟处理器调度的功能,所以,对被选中的进程并不实际启动运行,而是执行: 已运行时间+1 来模拟进程的一次运行,表示进程已经运行过一个单位的时间。 请注意:在实际的系统中,当一个进程被选中运行时,必须置上该进程可以运行的时间片值,以及恢复进程的现场,让它占有处理器运行,直到出现等待事件或运行满一个时间片。在这里省去了这些工作,仅用“已运行时间+1”来表示进程已经运行满一个时间片。 (4) 进程运行一次后,应把该进程的进程控制块中的指针值送到标志单元,以指示下一个轮到运行的进程。同时,应判断该进程的要求运行时间与已运行时间,若该进程要求运行时间≠已运行时间,则表示它尚未执行结束,应待到下一轮时再运行。若该进程的要求运行时间=已运行时间,则表示它已经执行结束,应把它的状态修改为“结束”(E)且退出队列。此时,应把该进程的进程控制块中的指针值送到前面一个进程的指针位置。 (5) 若“就绪”状态的进程队列不为空,则重复上面(4)和(5)的步骤,直到所有进程都成为“结束”状态。 (6) 在所设计的称序中应有显示或打印语句,能显示或打印每次被选中进程的进程名以及运行一次后进称对列的变化。 (7) 为五个进程任意确定一组“要求运行时间”,启动所设计的处理器调度程序,显示或打印逐次被选中进程的进程名以及进程控制块的动态变化过程。 立即下载

相关推荐

Google账号找回通用方法(尤其是知道账号密码仍无法登录和找回的)

Google账号找回通用方法【尤其是知道账号密码仍无法登录和找回的】普通找回注意:适用于常用谷歌账户的设备和网络情况下无法使用手机或辅助邮箱验证码进行密码找回特殊找回方法注意;适用于1.新的设备以及网络环境(包括由于非正常原因导致设备系统以及应用信息变更)2.没有开启辅助验证(手机/邮箱)3.知道账号密码但无法登录或找回。通过申诉进行找回 普通找回 注意:适用于 常用谷歌账户的设备和网络情况下 无法使用手机或辅助邮箱验证码进行密码找回 通过恢复页面进行恢复 https://accounts.google

极客代码-极致生活 23万+

Linux 学习笔记(八):时间片轮转调度

Linux 学习笔记(八):时间片轮转调度

Amentos的博客 5800

算法面经手撕系列(2)--手撕BatchNormlization

手动实现/手撕BatchNormlization

罟霖同学的站点 868

CPU调度算法-Linux操作系统下的时间片轮转调度算法-C语言(附代码)

这个算法的核心思想是将所有的就绪进程排成一个队列,并给每个进程分配一个固定的时间段,称为“时间片”(time slice),通常在10到100毫秒之间。每个进程轮流使用CPU,如果在分配的时间片内没有完成,则会被放回队列末尾,等待下一次机会。但如果顾客太多,或者每个人的饭量不一样(进程的任务大小不同),就需要合理安排每个人的服务时间(时间片的长度),以确保大家都满意。:输入完数据后,程序会根据您输入的数据执行时间片轮转调度算法,并显示每个时间片执行的进程和时间。宏定义了每个时间片的长度,而。

m0_73160444的博客 2204

RustDesk网页端远程控制实战:如何用Web Client替代传统客户端(附安全配置建议)

本文详细介绍了RustDesk网页端远程控制的实战应用,包括其核心优势、配置流程及安全加固方案。通过Web Client替代传统客户端,用户可实现跨平台无缝体验和企业级管理效率,特别适合临时协作和移动设备使用。文章还提供了JWT身份验证、LDAP集成等安全配置建议,确保网页端访问的安全性。

weixin_30836759的博客 254

SAP 物料账前期没有运行的解决方法

If you use the actual costing (material ledger), you must have completely closed all period-end closing operations in the actual costing for the penultimate period prior to the period shift. Use the '...

含笑饮砒霜死后更嚣张 3317

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

1.环境的搭建: 这个可以参考孟宁老师的github:mykernel,这里不再进行赘述。主要是就是下载Linux3.9的代码,然后安装孟宁老师编写的patch,最后进行编译。 2.代码的解读 课上的代码全部保存在github上,我fork了一份,然后为它加上了详细的注释,参见mykernel 3.代码结构 这里主要有三个文件: mypcb.h 这个头文件定义了进程控制结构PCB mymain....

weixin_34297704的博客 178

【浅读论文-红外和可见光图像融合-CNN】Infrared and Visible Image Fusion using a Deep Learning Framework

1.这篇是2018年ICPR会议上发表的一篇文章1。博主个人觉得这算比较早期在VIF(红外光和可见光图像融合)中加入了深度学习这一模型的论文。2.这篇文章并不是完全使用深度学习的模型,模型主体在图像分解和融合仍然采用传统的方法,只有其中一个分支在特征提取和重建方面用到了VGG网络。3.论文地址4.代码地址本文提出了基于深度学习框架的一种新算法。本文提出使用下述论文中Image fusion with guided filtering2中的分解方法将源图像分解为基本部分和细节内容。

一枚博鼠的博客 1708

操作系统闲谈06——进程管理

操作系统闲谈06——进程管理

yttt的博客 595

Android16 3576 u盘固件升级功能添加

1.在u-boot/drivers/power/pmic/rk8xx.c。这里是读取power键的寄存器判断长短按。

tzj1058756809的博客 575

【图论】系列(一)之图论的构成

图论是研究图的数学分支,本章介绍了图论的基本构成和概念

qq_30066733的博客 751

linux线程时间片是多少_合理使用线程池

前言线程池是多线程和并发编程的重要手段,本文尝试从操作系统、线程池实现原理和资源分配三个方面来分析,解释如何高效地使用线程池以及背后的逻辑。操作系统知识在介绍线程池之前,我们先来了解一下操作系统相关的知识。1.时间片我们的服务器大多是分时操作系统,这种操作系统将系统资源(特别是CPU)进行时间上的分割,每个时间段称为一个时间片,以时间片轮转的方式为多个任务提供服务。一个CPU同一时间只能...

weixin_42463165的博客 2220

3、灵巧手的设计与构造

本文详细探讨了灵巧手的设计与构造,包括多指结构、关节和连杆设计、传感器集成以及分层控制架构等内容。同时,通过工业装配、医疗手术辅助和日常生活辅助等实际应用案例,展示了灵巧手的灵活性和适应性,并分析了当前设计面临的挑战及未来发展方向。

brandy的博客 493

Linux 内核分析 第二次作业 完成一个简单的时间片轮转多道程序内核代码

侯君 原创作品转载请注明出处 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-100002900 实验要求: 完成一个简单的时间片轮转多道程序内核代码,代码见视频中或从mykernel找。 详细分析该精简内核的源代码并给出实验截图,撰写一篇署名博客,并在博客文章中注明“真实姓名(与最后申请证书的姓名务必一致) + 原创

七等星 680

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

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

Linux内核分析 实验二:完成一个简单的时间片轮转多道程序内核代码 by 吕然 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000        这次作业,我们运行并分析一个精简的操作系统内核,理解操作系统是如何工作的。        一. 实验步骤与效果:

331

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

windows linux时间片,一个简单的时间片轮转Linux内核分析

一个简单的时间片轮转Linux内核分析Linux内核 操作系统by 干宇航原创作品转载请注明出处 《Linux内核分析》MOOC课程实验环境:windows10 pro + Virtual box 5.14 下 Ubuntu 15.10 64位采用孟宁老师提供的mykernel环境环境截图mypcb.h 代码/* mykernel--Simple simulation of the linux...

weixin_39963523的博客 241

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

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

第二周作业:完成一个简单的时间片轮转多道程序内核代码张家骥+ 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ” 一. mykernel实验指导 二. 开始第一部分实验 三.第二部分实验:修改内核代码,使之成为一个简单的时间片轮转多道程序内核,然后重新编译运行。 四.mykernel内核

标题获取失败 1767

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

路过的小游侠+ 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000  实验二     时间片轮转多道程序 本周学习了一个简单的操作系统内核的工作模式。从堆栈初始化开始:汇编代码通过enter,

路过的小游侠 830

第2节 一个简单的时间片轮转多道程序内核代码【Linux内核分析】

原创作品转载请注明出处 +《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一、实验要求 完成一个简单的时间片轮转多道程序内核代码。 二、实验内容 完成一个简单的时间片轮转多道程序内核代码,代码见视频中或从mykernel找 分析进程的启动和进程的切换机制 理解操作系统如何工作 三、实验环境

林沐风的技术学习专栏 482

Linux内核分析实验(一):基于mykernel的一个简单的时间片轮转多道程序内核代码分析

学号后三位:446 原创作品转载请注明出处 https://github.com/mengning/linuxkernel/。 1.环境配置 由于自己机器下载linux内核太慢,于是便决定在实验楼上进行操作。 环境:实验楼+linuxkernel3.94+qemu虚拟机 实验楼地址:https://www.shiyanlou.com/courses/195 github地址:https://git...

weixin_42107987的博客 383

[linux内核] 1.简单时间片轮转多道程序内核代码分析

学习内容来自庖丁解牛 文章目录实验中的mykernel初始环境理解时间片轮转多道程序内核代码分析源码及理解时间片轮转多道程序内核代码分析总结 实验中的mykernel 是一个仅支持时钟中断的硬件模拟环境,可以看作一个虚拟的cpu,在此基础上可以写基于时间片轮转的进程调度内核程序。 初始环境理解 初始环境就是实验楼在mykernel目录直接做好的代码,先来分析一下这个简单代码。 cd ~/LinuxKernel/linux-3.9.4/mykernel rm -rf mykernel patch -p1 &l

H4ppyD0g的博客 560

[网易云课堂]Linux内核分析(二)—— mykernel内核部署及简单时间片轮转程序分析

付何山+原创作品转载请注明出处+《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000; 导读:本文分为两个部分。第一部分将讲解孟宁老师的mykernel程序如何部署在自己的Linux系统中,第二部分将分析MyKernel中的简单时间片轮转程序的运行。 一、部署mykernel 系统:Ubuntu 16.0

u013568531的专栏 885

linux实验:基于mykernel的一个简单的时间片轮转多道程序内核代码分析

学号后三位:288 原创作品转载请注明出处 +https://github.com/mengning/linuxkernel/ 1.mykernel mykernel是由中科大孟宁老师建立的用于开发操作系统内核的一个平台,你可以在kernel版本库中找到mykernel的代码,链接:https://github.com/mengning/mykernel,根据里面的步骤将...

pjz000的博客 730

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

Lab2:一个简单的时间片轮转多道程序内核代码 席金玉   《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ” 1、话说Linux操作系统       Linux是一种开源电脑操作系统内核。它是一个用C语言写成,符合POSIX标准的类Unix操作系统。Linux是一个一体化内核(monolithic

絮雨清风 1145
下一篇: Linux内核系统调用分析
或曰
博客等级 码龄8年 0粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值