2020-2021-1 20212824《Linux内核原理与分析》第九周作业

操作系统概览

操作系统

  • 内核
    • 进程管理、进程调度、进程间通讯机制,内存管理,中断异常处理,文件系统,I/O系统
  • 其他程序
    • 函数库,shell程序

操作系统的目的

  • 与硬件交互,管理所有的硬件资源

  • 为用户程序提供一个执行环境

    在这里插入图片描述

linux一般执行过程

最一般的情况 :

正在运行的用户态进程x切换到运行用户态进行y

  1. x正在运行
  2. 发生中断-cpu将当前的进程上下文压入到进程x的内核堆栈
  3. SAVE_ALL 保存现场
  4. 中断处理过程或中断返回之前调用schdule(),其中的switch_to()做了关键的进程上下文切换
  5. 标号1之后开始运行进程y
  6. restore_all 恢复现场
  7. iret
  8. 继续运行进程y

特殊情况

  • 通过中断处理过程中的调度时机,用户态进程与内核线程之间互相切换,与最一般的情况类似,只是内核线程运行过程中发生中断没有用户态和内核态的转换
  • (用户态不能直接调用schdule) 内核线程主动调用schdule(),只有进程上下文的切换,没有发生中断上下文的切换
  • 创建子进程的系统调用在子进程的执行起点返回用户态,如fork
  • 加载一个新的可执行程序后返回到用户态的情况如execve

进程调度

  • I/O
    • 频繁的进行I/O
    • 通常会花费很多时间等待进程完成
  • cpu
    • 计算密集形
    • 需要大量的cpu时间进行计算
  • 批处理进程
    • 不必很快和用户交互,通常在后台运行
    • 不必很快响应
    • 典型的批处理进程:编译程序、科学计算
  • 实时进程
    • 有实时需求,优先级高的先行
    • 响应时间短,要稳定
    • 如音频,机械控制等
  • 交互式进程
    • 频繁与用户交互,需要等待用户输入
    • 响应时间要快
    • 如shell,文本编辑

基于以上进程的区别,所以需要进程调度

schdule函数负责实现调度
一般的用户态进程,只能被动调度
内核线程是只有内核态没有用户态的特殊进程

进程切换代码

当前进程怎么切换到next进程
为了控制进程的执行,内核必须有能力挂起cpu正在执行的进程,并且能够恢复之前被挂起的进程,这与中断上下文切换不同(中断在同一个进程中)
进程上下文切换:

  • 用户地址空间
  • 控制信息
  • 硬件上下文
next = pick_next_task(rq, prev); //包装使用某种进程调度策略

context_switch关键代码

context_switch(struct rq *rq, struct task_struct *prev,
	       struct task_struct *next)
{
	struct mm_struct *mm, *oldmm;

	prepare_task_switch(rq, prev, next);

	mm = next->mm;
	oldmm = prev->active_mm;
	/*
	 * For paravirt, this is coupled with an exit in switch_to to
	 * combine the page table reload and the switch backend into
	 * one hypercall.
	 */
	arch_start_context_switch(prev);

	if (!mm) {
		next->active_mm = oldmm;
		atomic_inc(&oldmm->mm_count);
		enter_lazy_tlb(oldmm, next);
	} else
		switch_mm(oldmm, mm, next);

	if (!prev->mm) {
		prev->active_mm = NULL;
		rq->prev_mm = oldmm;
	}
	/*
	 * Since the runqueue lock will be released by the next
	 * task (which is an invalid locking op but in the case
	 * of the scheduler it's an obvious special-case), so we
	 * do an early lockdep release here:
	 */
	spin_release(&rq->lock.dep_map, 1, _THIS_IP_);

	context_tracking_task_switch(prev, next);
	/* Here we just switch the register state and the stack. */
	switch_to(prev, next, prev);

	barrier();
	/*
	 * this_rq must be evaluated again because prev may have moved
	 * CPUs since it called schedule(), thus the 'rq' on its stack
	 * frame will be invalid.
	 */
	finish_task_switch(this_rq(), prev);
}

next_ip一般是$1f,对于新创建的子进程是ret_from_fork

schedule 调试

和之前的调试其实差不多,只不过这个词把断点设置在schedule 然后单步执行就行在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值