Minix 进程调度代码详解

合集下载

minix操作系统的启动过程与中断机制解析

minix操作系统的启动过程与中断机制解析

MINIX 操作系统的启动过程与中断机制解析公维冰朱文俊(兰州大学数学与统计学院,甘肃兰州730000)摘要:MINIX 操作系统是一个面向教学的操作系统,它是第一个将所有源代码免费对外公布的系统,它的这个优点就为我们学习操作系统提供了很大的方便,我们可以通过学习源代码来更深刻的学习操作系统的基本原理。

系统的分层式结构,实现方式虽然简单,但是却给出了操作系统最基本的实现结构。

我们这里通过解析代码来说明MINIX2.0操作系统的中断机制是如何实现的,包括硬件中断,软件中断和异常中断。

关键词:MINIX2.0操作系统中断机制硬中断软中断异常中图分类号:TP31介绍MINIX 操作系统是一种与UNIX 操作系统兼容的小型操作系统,它最早是由计算机科学教育家的Tanenbaum 开发的。

与UNIX 相比,MINIX 的小巧和高度的模块化使其非常适合于操作系统教程,而其源代码的公开性又为操作系统研究者提供了极大的方便。

现在流行的LINUX 操作系统就是在开放的MINIX 操作系统基础上发展起来的。

在MINIX 操作系统家族中,MINIX1.0的设计基于UNIX V7标准,而MINIX2.0的设计则基于POSIX 标准,现己升级到了MINIX3。

我们将在第二节介绍MINIX2.0操作系统的整体结构,第三节是MINIX2.0操作系统的启动过程,第四节介绍MINIX2.0操作系统的中断机制,包括硬件中断机制,软件中断机制和异常机制,第五节我们给出结论。

2MINIX2.0操作系统的整体结构MINIX2.0操作系统整体实行分层结构,如下所示:第四层:用户进程层init 进程编译器编辑器其它用户进程第三层:服务器进程层内存管理器(mm)文件系统服务器(fs)网络服务器(nets)第二层:I/O 驱动任务层内存管理驱动硬盘驱动终端驱动时钟任务其它驱动任务第一层:操作系统最底层操作系统的启动,中断处理,进程调度等以上各层中层数越低就越底层,其中低层是高层的基础,高层依赖低层实现更高级和更复杂的功能。

Minix 进程调度代码详解

Minix 进程调度代码详解

1.Minix3中为每个进程分配的时间片,当进程的时间片用完后,将进行进程调度。

进程的时间片以时钟滴答为单位进行分配。

每次时钟中断,中断处理程序将减少当前进程的时间片。

当时间片减小到0时,进行进程调度,选择一个合适的进程来拥有CPU。

Minix3以每秒钟60次的频率进行时钟中断,即时钟中断处理程序每秒执行60次。

每次执行,减少当前进程的时间片:/* Get number of ticks and update realtime. */ticks = lost_ticks + 1; /* lost_ticks为BIOS中断所花费的时间 */lost_ticks = 0; /* lost_ticks清0 */realtime += ticks; /* 更新时间 */proc_ptr->p_user_time += ticks; /* 更新当前进程的user_time */if (priv(proc_ptr)->s_flags & PREEMPTIBLE) {/* 如果进程可被抢占,则减少时间片 */proc_ptr->p_ticks_left -= ticks;}if (! (priv(proc_ptr)->s_flags & BILLABLE)) {/* 如果当前进程能付费,则修改sys_time及减少时间片 */bill_ptr->p_sys_time += ticks;bill_ptr->p_ticks_left -= ticks;}如果时间片用完,则向clock_task发送通知。

因为该进程的时间片用完,需要重新调度,所以该进程就成为了上一个执行的进程。

if((next_timeout <= realtime)||(proc_ptr->p_ticks_left<= 0)) { /* 如果定时器到期或者进程时间片用完,则进行调度 */prev_ptr = proc_ptr; /* 当前进程成为上一次执行的进程 */lock_notify(HARDWARE, CLOCK); /* send notification */ /* 时间到期时发送通知给clock_task,由该函数进行后续处理 */}2.clock_task为时钟任务的主程序,用一个无限循环等待并处理时钟中断处理程序发来的通知。

进程调度算法代码

进程调度算法代码

进程调度算法代码进程调度算法是操作系统中的一种重要机制,它决定了在多道程序环境下,如何安排各个进程的执行顺序和时间片。

不同的进程调度算法有不同的实现方式和优缺点,本文将就常见的几种进程调度算法进行详细介绍。

1. 先来先服务(FCFS)先来先服务是最简单、最直观的进程调度算法。

它按照进程到达时间的先后顺序进行调度,即先到达的进程先执行。

当一个进程开始执行后,直到该进程执行完毕或者发生某些阻塞事件才会切换到另一个进程。

FCFS算法代码如下:```void FCFS(){int i;for(i=0;i<n;i++){run(p[i].need_time);if(i!=n-1){wait(p[i+1].arrive_time-p[i].arrive_time-p[i].need_time); }}}```其中,p数组表示所有需要执行的进程,n表示总共有多少个需要执行的进程。

run函数表示运行该进程所需时间片,wait函数表示等待下一个进程到达所需时间。

FCFS算法优点是简单易懂、公平性好,但其缺点也很明显:无法处理短作业优先问题、平均等待时间长等。

2. 短作业优先(SJF)短作业优先是一种非抢占式的进程调度算法,它根据每个进程的执行时间来进行排序,执行时间短的进程先执行。

如果有多个进程的执行时间相同,则按照到达时间的先后顺序进行调度。

SJF算法代码如下:```void SJF(){int i,j;for(i=0;i<n;i++){for(j=i+1;j<n;j++){if(p[i].need_time>p[j].need_time){swap(p[i],p[j]);}}}for(i=0;i<n;i++){run(p[i].need_time);if(i!=n-1){wait(p[i+1].arrive_time-p[i].arrive_time-p[i].need_time); }}}```其中,swap函数表示交换两个进程的位置。

操作系统进程调度C语言代码

操作系统进程调度C语言代码

操作系统进程调度C语言代码#include <stdio.h>#define MAX 20//进程控制块typedef struct PCBchar name[10]; // 进程名int AT; // 到达时间int BT; // 服务时间int Pri; // 优先数int FT; // 完成时间int WT; //等待时间int RT; // 响应时间int position; // 第几号进程int flag; // 用来判断进程是否执行过}PCB;//进程调度void schedule(PCB a[], int n, int alg)int i, j, k, flag, temp;int count = 0;int pri_max = 0;float ATAT = 0.0;float AWT = 0.0;float ART = 0.0;PCBt;//各种算法的调度if (alg == 1)printf("采用先来先服务调度:\n"); //根据到达时间执行for (i = 0; i < n; i++)for (j = i + 1; j < n; j++)if (a[i].AT > a[j].AT)t=a[i];a[i]=a[j];a[j]=t;}//按到达时间依次执行for (i = 0; count != n; i++)for (j = 0; j < n; j++)//查找第一个到达时间小于等于当前时间的进程if (a[j].AT <= i && a[j].flag == 0)//记录运行时间a[j].BT--;//如果运行完成,记录完成时间、等待时间、响应时间if (a[j].BT == 0)a[j].FT=i+1;a[j].WT = a[j].FT - a[j].AT - a[j].Pri;a[j].RT=a[j].WT;a[j].flag = 1;count++;}elsebreak;}}}else if (alg == 2)printf("采用最短服务时间优先(非抢占)调度:\n");for (i = 0; count != n; i++)//找出服务时间最短的进程,并将其放置到最前面for (j = 0; j < n; j++)。

Minix进程实现

Minix进程实现

Minix进程实现2.5~2.6概述:本部分内容主要从两个部分介绍进程在Minix中的实现的:第一部分是介绍整个Minix的系统结构的,其中包括了Minix的内部结构以及各种头文件,其主要是对于各个头文件以及进程有关的数据结构的介绍的;第二部分讲的是Minix中进程的实现,其中包括Minix的系统初始化、中断处理、进程间的通信和进程调度。

Minix系统结构介绍:包括Minix内部结构以及各种头文件。

Minix内部四层结构最底层捕获所有的中断和陷入,完成进程调度,并向高层提供一个采用消息进行通信的独立顺序进程模型。

包含完成以下功能的函数:系统初始化、中断、消息传递以及进程调度。

第二层包括了I/O进程,每类设备都有一个I/O进程,我们称之为任务(task)。

只有一个任务,即系统任务与众不同,它不对应于任何I/O设备。

第三层包含向用户进程提供有用服务的进程。

这些服务器进程在低于内核和任务的特权级上运行,不能直接访问I/O端口,也不能访问属于自己段以外的内存。

第四层包含了所有的用户进程——shell、编译器、编辑器以及用户的a.out 程序。

Minix四层结构之间的联系:操作系统主要完成的两件事情:管理资源和通过系统调用方式提供扩展的计算机。

其中,资源管理主要是在内核(第一、二层)完成的,系统调用的解释在第三层。

第三层的各种服务进程被单独的设计成“服务器”,这样可以增加整个系统的可扩展性。

如果要是加入一个新的服务器进程,需要重新编译内核。

Minix源代码的组织源代码从逻辑上分成两个目录:/usr/include/和/usr/src/,记做:include/和/src/。

include/目录包含了许多符合POSIX标准的头文件,它又包含了三个子目录:1.sys/ 包含POSIX头文件2.minix/ 包含操作系统使用的头文件3.ibm/ 包含IBMPC特有定义的头文件。

src/目录包含了三个重要的子目录,其中包括了操作系统的源代码1.kernel/ 第一层和第二层的(进程、消息和驱动程序)2.mm/ 内存管理器代码3.fs/ 文件系统代码公共头文件其中,编译用户程序时可能用到的头文件放在include/目录下,而传统上include/sys/目录放那些编译系统程序和程序所用的头文件。

c语言实现进程调度算法

c语言实现进程调度算法

c语言实现进程调度算法进程调度算法是操作系统中的一个重要组成部分,用于决定在多道程序环境下,选择哪个进程来占用CPU并执行。

C语言是一种通用的编程语言,可以用于实现各种进程调度算法。

这里我将分别介绍三种常见的进程调度算法:先来先服务调度算法(FCFS)、最短作业优先调度算法(SJF)和轮转法调度算法(RR),并给出用C语言实现的示例代码。

首先,我们来看先来先服务调度算法(FCFS)。

此算法根据到达时间的先后顺序,按照先来后到的顺序进行处理。

下面是基于C语言的先来先服务调度算法实现示例代码:```c#include<stdio.h>struct Process};void FCFS(struct Process proc[], int n)for (int i = 1; i < n; i++)}printf("进程号到达时间服务时间完成时间等待时间周转时间\n");for (int i = 0; i < n; i++)}for (int i = 0; i < n; i++)}int maiint n;printf("请输入进程数:");scanf("%d", &n);struct Process proc[n];for (int i = 0; i < n; i++)printf("请输入进程%d的到达时间和服务时间(用空格分隔):", i + 1);}FCFS(proc, n);return 0;```其次,我们来看最短作业优先调度算法(SJF),该算法选择执行时间最短的进程先执行。

下面是基于C语言的最短作业优先调度算法实现示例代码:```c#include<stdio.h>struct Process};void SJF(struct Process proc[], int n)for (int i = 0; i < n; i++)for (int j = 0; j < i; j++)}shortest_job = i;for (int j = i + 1; j < n; j++)shortest_job = j;}}}for (int i = 1; i < n; i++)}printf("进程号到达时间服务时间完成时间等待时间周转时间\n");for (int i = 0; i < n; i++)}for (int i = 0; i < n; i++)}int maiint n;printf("请输入进程数:");scanf("%d", &n);struct Process proc[n];for (int i = 0; i < n; i++)printf("请输入进程%d的到达时间和服务时间(用空格分隔):", i + 1);}SJF(proc, n);return 0;```最后,我们来看轮转法调度算法(RR),该算法分配一个时间片给每个进程,当时间片用完后,将CPU分配给下一个进程。

操作系统五种进程调度算法的代码

操作系统五种进程调度算法的代码

操作系统五种进程调度算法的代码一、先来先服务(FCFS)调度算法先来先服务(FCFS)调度算法是操作系统处理进程调度时比较常用的算法,它的基本思想是按照进程的提交时间的先后顺序依次调度进程,新提交的进程会在当前运行进程之后排队,下面通过C语言代码来实现先来先服务(FCFS)调度算法:#include <stdio.h>#include <stdlib.h>//定义进程的数据结构struct Processint pid; // 进程标识符int at; // 到达时间int bt; // 执行时间};//进程调度函数void fcfs_schedule(struct Process *processes, int n)int i, j;//根据进程的到达时间排序for(i = 0; i < n; i++)for(j = i+1; j < n; j++)if(processes[i].at > processes[j].at) struct Process temp = processes[i]; processes[i] = processes[j];processes[j] = temp;//获取各个进程执行完毕的时间int ct[n];ct[0] = processes[0].at + processes[0].bt; for(i = 1; i < n; i++)if(ct[i-1] > processes[i].at)ct[i] = ct[i-1] + processes[i].bt;elsect[i] = processes[i].at + processes[i].bt; //计算各个进程的周转时间和带权周转时间int tat[n], wt[n], wt_r[n];for(i = 0; i < n; i++)tat[i] = ct[i] - processes[i].at;wt[i] = tat[i] - processes[i].bt;wt_r[i] = wt[i] / processes[i].bt;printf("P%d:\tAT=%d\tBT=%d\tCT=%d\tTAT=%d\tWT=%d\tWT_R=%f\n", processes[i].pid, processes[i].at, processes[i].bt, ct[i], tat[i], wt[i], wt_r[i]);//主函数int mainstruct Process processes[] ={1,0,3},{2,3,5},{3,4,6},{4,5,2},{5,6,4}};fcfs_schedule(processes, 5);return 0;输出:。

进程调度算法模拟程序设计

进程调度算法模拟程序设计

进程调度算法模拟程序设计引言进程调度算法是操作系统中的重要组成部分,它决定了进程在系统中的执行顺序和分配时间片的策略。

为了更好地理解和研究不同的进程调度算法,我们可以设计一个模拟程序来模拟进程的调度过程。

本文将介绍进程调度算法的基本概念和常见的调度算法,并详细讨论如何设计一个进程调度算法模拟程序。

什么是进程调度算法进程调度算法是操作系统中的一种策略,用于决定在多个进程同时请求执行时,系统按照什么样的顺序来选择并分配CPU资源。

进程调度算法的目标是尽可能地提高系统的吞吐量、响应时间和公平性。

常见的进程调度算法先来先服务(FCFS)先来先服务是最简单的进程调度算法,它按照进程到达的先后顺序进行调度。

当一个进程到达系统后,它会被放入就绪队列中,然后按照先后顺序执行。

这种算法的优点是简单易懂,但是存在”饥饿”问题,即长作业会占用CPU资源,导致其他短作业等待时间过长。

短作业优先(SJF)短作业优先算法是根据进程的执行时间来进行调度的。

当一个进程到达系统后,系统会根据其执行时间将其放入适当的位置,执行时间短的进程优先执行。

这种算法可以最大限度地减少平均等待时间,但是对于长作业来说可能会饥饿。

时间片轮转(RR)时间片轮转算法是一种分时调度算法,它将CPU的执行时间划分为多个时间片,每个进程在一个时间片内执行一定的时间,然后切换到下一个进程。

这种算法可以保证所有进程都有机会执行,并且对于响应时间要求较高的任务比较合适。

多级反馈队列(MFQ)多级反馈队列算法是一种综合了FCFS和RR的调度算法。

系统将进程根据优先级划分为多个队列,每个队列都有不同的时间片大小。

当一个进程到达系统后,它被放入第一个队列中,如果在时间片内没有执行完,则被移到下一个队列中。

这种算法可以根据进程的优先级和执行时间动态调整调度策略,提高系统的响应性能。

进程调度算法模拟程序设计程序结构为了设计一个进程调度算法模拟程序,我们需要考虑以下几个方面的内容:1.进程的数据结构:我们可以使用一个进程控制块(PCB)来表示一个进程,PCB包含了进程的状态、优先级、执行时间等信息。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

1.Minix3中为每个进程分配的时间片,当进程的时间片用完后,将进行进程调度。

进程的时间片以时钟滴答为单位进行分配。

每次时钟中断,中断处理程序将减少当前进程的时间片。

当时间片减小到0时,进行进程调度,选择一个合适的进程来拥有CPU。

Minix3以每秒钟60次的频率进行时钟中断,即时钟中断处理程序每秒执行60次。

每次执行,减少当前进程的时间片:/* Get number of ticks and update realtime. */ticks = lost_ticks + 1; /* lost_ticks为BIOS中断所花费的时间 */lost_ticks = 0; /* lost_ticks清0 */realtime += ticks; /* 更新时间 */proc_ptr->p_user_time += ticks; /* 更新当前进程的user_time */if (priv(proc_ptr)->s_flags & PREEMPTIBLE) {/* 如果进程可被抢占,则减少时间片 */proc_ptr->p_ticks_left -= ticks;}if (! (priv(proc_ptr)->s_flags & BILLABLE)) {/* 如果当前进程能付费,则修改sys_time及减少时间片 */bill_ptr->p_sys_time += ticks;bill_ptr->p_ticks_left -= ticks;}如果时间片用完,则向clock_task发送通知。

因为该进程的时间片用完,需要重新调度,所以该进程就成为了上一个执行的进程。

if((next_timeout <= realtime)||(proc_ptr->p_ticks_left<= 0)) { /* 如果定时器到期或者进程时间片用完,则进行调度 */prev_ptr = proc_ptr; /* 当前进程成为上一次执行的进程 */lock_notify(HARDWARE, CLOCK); /* send notification */ /* 时间到期时发送通知给clock_task,由该函数进行后续处理 */}2.clock_task为时钟任务的主程序,用一个无限循环等待并处理时钟中断处理程序发来的通知。

没有通知发来时,处于阻塞状态。

while (TRUE) {/* 获取消息 */receive(ANY, &m); /* 无消息时则阻塞 *//* 检查消息类型,只处理时钟中断处理程序发来的消息 */switch (m.m_type) {case HARD_INT:/* 这个消息由时钟中断处理程序(clock_handler)发出 */result = do_clocktick(&m); /* 处理该消息,检查时间片是否到期等 */break; /* result变量没有实际意义 */default: /* illegal request type */kprintf("CLOCK:illegal request %d from %d.\n", m.m_type,m.m_source);}}3.当通过消息检查后,调用do_clocktick函数处理该消息。

首先,检查是否是进程的时间片到期。

如果时间片到期,则重置该进程的时间片,并插入到就绪队列的适当位置。

将进程移出、移入就绪队列,就能完成为进程重新分配时间片和插入适当位置的任务。

if(prev_ptr->p_ticks_left<=0 && priv(prev_ptr)->s_flags & PREEMPTIBLE) { lock_dequeue(prev_ptr); /* 将进程移出队列 */lock_enqueue(prev_ptr); /* 在将进程移入队列 */}lock_dequeue函数将屏蔽中断,然后调用函数dequeue将进程移出就绪队列。

而函数lock_enqueue同样将屏蔽中断,然后调用函数enqueue。

下面详细讨论enqueue 函数。

4.enqueue首先调用函数sched,计算函数的优先级和应分配的时间片。

如果该进程为前一次运行过的进程,即进程连续运行过两次,则降低进程的优先级。

否则该进程可能无限期的占用CPU。

if ( ! time_left) { /* 时间片是否用完 */rp->p_ticks_left = rp->p_quantum_size; /* 分配完整的时间片? */if (prev_ptr == rp) penalty ++; /* 是否要降低进程优先级? */else penalty --; /* 进程都没执行过,则增加进程的优先级 */ prev_ptr = rp; /* 该进程刚运行过 */}接下来,确定进程的优先级。

Minix3中,共有16个优先级队列,最高为0,最低为15。

进程优先级最大为其规定的优先级,最小不能小于IDLE进程的优先级,即最小为14。

if (penalty != 0 && ! iskernelp(rp)) {/* 惩罚值不为0,且该进程不是内核进程 */ rp->p_priority += penalty; /* 根据惩罚值,确定新的优先级 */if (rp->p_priority < rp->p_max_priority) /* 最大为规定的最大优先级*/ rp->p_priority=rp->p_max_priority;else if (rp->p_priority > IDLE_Q-1) /* 不能小于IDLE的优先级 */ rp->p_priority = IDLE_Q-1;}最后,返回进程的优先级。

*queue = rp->p_priority;当进程的时间片未用完,则进程插入队列头部。

用完则插入队列尾部。

时间片未用完的原因有:1.其要求的定时器到期;2.进程请求了I/O操作而被阻塞。

5.进程优先级确定后,就将其插入对应的优先级队列。

这16个队列分别由rdy_head 数组指向每个队列的头和 rdy_tail数组指向每个队列的尾。

if (rdy_head[q] == NIL_PROC) { /* 如果队列为空 */rdy_head[q] = rdy_tail[q] = rp; /* create a new queue */rp->p_nextready = NIL_PROC; /* mark new end */}else if (front) { /* 队列非空,且插入头部。

即时间片未用完 */rp->p_nextready = rdy_head[q]; /* chain head of queue */rdy_head[q] = rp; /* set new queue head */}else { /* 插入队列尾部,即时间片用完 */rdy_tail[q]->p_nextready = rp; /* chain tail of queue */rdy_tail[q] = rp; /* set new queue tail */rp->p_nextready = NIL_PROC; /* mark new end */}6.最后,调用函数pick_proc选择一个优先级最高的进程来拥有CPU。

从16个队列中,从最高的优先级队列开始,选择队头的进程来占有CPU。

for (q=0; q < NR_SCHED_QUEUES; q++) {if ( (rp = rdy_head[q]) != NIL_PROC) {next_ptr = rp; /* run process 'rp' next */if (priv(rp)->s_flags & BILLABLE)bill_ptr = rp; /* bill for system time */return;}}最后,即将要运行的进程由next_ptr指针指示。

7.enqueue函数结束后,将返回到函数lock_enqueue。

接着lock_enqueue将开中断,在中断处理函数运行完之后,内核跳转到_restart处继续执行来完成进程的切换:save:cld ! set direction flag to a known valuepushad ! 保存通用寄存器o16 push ds ! save dso16 push es ! save eso16 push fs ! save fso16 push gs ! save gsmov dx, ss ! ss is kernel data segmentmov ds, dx ! load rest of kernel segmentsmov es, dx ! kernel does not use fs, gsmov eax, esp ! prepare to returnincb (_k_reenter) ! from -1 if not reenteringjnz set_restart1 ! 是否已经是内核堆栈,该情况发生在响应异常时mov esp, k_stktop ! 切换内核堆栈push _restart ! 中断处理完成后的返回地址入栈,即中断完成后转restart进行调度xor ebp, ebp ! for stacktracejmp RETADR-P_STACKBASE(eax) ! 返回到中断处理程序.align 4set_restart1: ! 检查到异常时,才会执行到此处push restart1jmp RETADR-P_STACKBASE(eax)上面的汇编代码是处理中断前保存现场信息的代码,其中在栈中压入了中断完成后的返回地址_restrart。

当中断处理完成后,将转入_restart代码启动一个进程。

_restart:! Restart the current process or the next process if it is set.cmp (_next_ptr), 0 ! 是否有其他进程被调度,pick_proc函数已经选择了一个进程! 所以next_ptr不为0jz 0f ! 如果没有调度其他进程,进继续执行前一个进程mov e ax, (_next_ptr)mov (_proc_ptr), eax ! 调度新进程,proc_ptr = next_ptrmov (_next_ptr), 0 ! next_ptr清00: mov esp, (_proc_ptr) ! will assume P_STACKBASE == 0lldt P_LDT_SEL(esp) ! 装入新进程的局部描述符表(LDT)lea eax, P_STACKTOP(esp) ! 下一次中断的临时堆栈将建立在这地址之后mov (_tss+TSS3_S_SP0), eax ! 将地址保存在TSS中restart1: ! 发生异常时从此处开始执行decb (_k_reenter)o16 pop gso16 pop fso16 pop eso16 pop dspopadadd esp, 4 ! skip return adriretd ! continue process下次中断的临时堆栈将建立在进程结构的stackframe_p结构的后面,硬件将保证临时堆栈不会溢出。

相关文档
最新文档