2023-2024-1 20232816《Linux内核原理与分析》第九周作业

一、基础知识

(一)进程调度的时机

进程调度是操作系统中的一个重要功能,用于决定哪个进程将获得 CPU 的执行时间。进程调度的时机通常分为以下几种情况:
进程创建:当一个新的进程被创建时,操作系统需要确定该进程何时开始执行。通常,新创建的进程将被插入到就绪队列中,等待进行调度。
进程终止:当一个进程完成它的任务或由于其他原因终止时,操作系统需要将 CPU 重新分配给其他进程。进程的终止可能是主动的(如进程完成了它的任务)或被动的(如发生了致命错误)。
进程阻塞:当一个进程发起某个阻塞操作(例如等待 I/O 完成)时,它将暂时释放 CPU,并被移出运行队列。此时,操作系统将选择另一个就绪的进程来执行。
时间片用尽:在多任务环境下,操作系统通常使用时间片轮转算法等方式来划分 CPU 的执行时间。当一个进程的时间片用尽时,操作系统会将其移出运行队列,并选择下一个就绪的进程来执行。
中断处理:当发生硬件中断(如时钟中断、设备中断)或软件中断(如系统调用)时,操作系统需要暂停当前执行的进程,并切换到中断处理程序。中断处理完成后,操作系统可能会重新进行进程调度,选择下一个要执行的进程。

(二)schedule函数分析

def schedule():
    current_process = get_current_process()  # 获取当前正在执行的进程
    next_process = select_next_process()  # 选择下一个要执行的进程

    if next_process != current_process:
        save_context(current_process)  # 保存当前进程的上下文
        switch_context(next_process)  # 切换到下一个进程的上下文

get_current_process() 函数用于获取当前正在执行的进程。select_next_process() 函数根据调度算法选择下一个要执行的进程。这个函数的实现可以根据所采用的调度算法(如先来先服务、轮转调度、最短作业优先等)进行优先级比较、队列操作等。

如果下一个要执行的进程与当前进程不同,save_context(current_process) 函数将保存当前进程的上下文信息,包括寄存器状态、程序计数器等。然后,switch_context(next_process) 函数将切换到下一个进程的上下文,将 CPU 的控制权转移到该进程的执行代码。

需要注意的是,上述示例是一个简化的伪代码示例,实际的 schedule() 函数在具体的操作系统中可能会更加复杂,并涉及更多的调度策略和优化。此外,上下文切换的开销是非常高的,因此优化调度算法和减少上下文切换次数对系统性能至关重要。

(三)硬中断(Hardware Interrupt)和软中断(Software Interrupt)

硬中断(Hardware Interrupt)和软中断(Software Interrupt)是计算机系统中两种不同类型的中断。

硬中断(Hardware Interrupt):
硬中断是由计算机硬件发出的中断信号,用于通知处理器发生了一个事件或外部设备需要处理。硬中断是由硬件设备(如时钟、外部设备)通过中断控制器向处理器发送的信号,以引起处理器的注意并暂停当前正在执行的任务。硬中断是由硬件自动触发的,无需软件的干预。

软中断(Software Interrupt):
软中断是由软件或操作系统主动发起的中断。软中断通常用于在程序执行过程中主动请求操作系统的服务或触发特定的操作。软中断是通过软件指令或系统调用(如系统中断指令)来触发的,典型的例子是应用程序通过软中断请求操作系统执行特定功能,如文件操作、进程管理等。

二、实验过程

1.编译运行测试
采取给test函数增加exec函数的方法,进行调试编译
exec函数如下:

int Exec(int argc, char *argv[])
{
	int pid;
	/* fork another process */
	pid = fork();
	if (pid < 0) 
	{ 
		/* error occurred */
		fprintf(stderr,"Fork Failed!");
		exit(-1);
	} 
	else if (pid == 0) 
	{
		/*	 child process 	*/
    	printf("This is Child Process!\n");
		execlp("/hello","hello",NULL);
	} 
	else 
	{ 	
		/* 	parent process	 */
    	printf("This is Parent Process!\n");
		/* parent will wait for the child to complete*/
		wait(NULL);
		printf("Child Complete!\n");
	}
}

在这里插入图片描述增加完后修改test函数,实现exec功能如下图所示。
按照如下代码运行编译:

cd ~/LinuxKernel
vim test.c
cd menu 
make rootfs 

在这里插入图片描述
2.Linux的一般执行过程
(1)正在运行的用户态X。
(2)发生中断(包括异常、系统调用)。
(3) 保护现场,此时完成上下文切换。
(4)中断处理过程中或中断返回前调用schedule函数,其中switch_to做了关键进程上下文切换。
(5)运行用户态进程Y。
(6)恢复现场。
(7)完成中断上下文切换,从进程Y内核态返回到进程Y的用户态。
(8)继续运行用户态进程Y。
3、几种特殊情况
(1)通过中断处理过程中的调度时机,用户态进程与内核线程之间互相切换和内核线程之间互相切换,与最一般的情况非常类似,只是内核线程运行过程中发生中断没有进程用户态和内核态的转换;
(2)内核线程主动调用schedule(),只有进程上下文的切换,没有发生中断上下文的切换,与最一般的情况略简略;
(3)创建子进程的系统调用在子进程中的执行起点及返回用户态,如fork;
(4)加载一个新的可执行程序后返回到用户态的情况,如execve;

4.gdb调试
在gdb中设置以下断点:

schedule:进程调度的主体函数
context_switch:实现进程切换的函数
pick_next_task:负责根据调度策略和调度算法选择下一个进程
switch_to:其中switch_to为宏定义,不能设置断点,需到context_switch函数中单步执行查看调用
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

三、实验总结

在本次实验中,我们深入研究了进程上下文切换和调度的实现原理,并通过实际编程和实验验证加深了对其的理解。通过对Linux内核中与进程调度相关的函数和宏的分析,我们了解到以下重要概念和过程:
进程上下文切换是指在操作系统中从一个进程切换到另一个进程的过程。在本次实验中,我们了解到通过宏switch_to()来进行关键的上下文切换。在进程切换时,当前进程的寄存器状态和其他上下文信息会保存到进程控制块中,然后加载新进程的上下文信息,并通过切换堆栈来切换到新进程的执行流。
通过本次实验,我们通过动手实践加深了对进程上下文切换和调度的理解。我们学会了如何通过中断处理和内核线程来实现进程调度,以及进程调度的时机和过程。这对于我们理解操作系统中进程管理的核心原理和实现机制非常有帮助。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值