深入Linux内核架构笔记 - 进程管理与调度6: 实时调度类

Overview

按照POSIX标准的强制要求,除了"普通进程",Linux还支持两种实时调度类,调度器结构使得实时进程可以平滑地集成到内核中。
实时进程的特点是其优先级比普通进程高,rt_task通过检查其优先级来证实给定进程是否是实时进程,而task_has_rt_policy则检测进程是否关联到实时调度策略。

性质

  • 实时进程和普通进程有一个根本的不同之处:如果系统中有一个实时进程且可运行,那么调度器总是会选中它运行,除非有另一个优先级更高的实时进程
  • 循环进程(SCHED_RR):基于时间片,在进程运行时时间片会减少,进程时间用完后(100ms),则重置为初始值,并将进程放置到队列的末尾,这确保了在有几个优先级相同的SCHED_RR进程时,它们总是依次执行
  • 先进先出进程(SCHED_FIFO):没有时间片,在被调度器选择后,可以运行任意长时间。

数据结构

  • 实时进程调度类

    const struct sched_class rt_sched_class = {
    	.next			= &fair_sched_class,
    	.enqueue_task		= enqueue_task_rt,
    	.dequeue_task		= dequeue_task_rt,
    	.yield_task		= yield_task_rt,
    
    	.check_preempt_curr	= check_preempt_curr_rt,
    
    	.pick_next_task		= pick_next_task_rt,
    	.put_prev_task		= put_prev_task_rt,
    
    #ifdef CONFIG_SMP
    	.load_balance		= load_balance_rt,
    	.move_one_task		= move_one_task_rt,
    #endif
    
    	.set_curr_task          = set_curr_task_rt,
    	.task_tick		= task_tick_rt,
    };
    
  • 就绪队列

    struct rq {
    	struct rt_rq rt;
    }
    struct rt_rq {
    	struct rt_prio_array active;
    	int rt_load_balance_idx;
    	struct list_head *rt_load_balance_head, *rt_load_balance_curr;
    };
    struct rt_prio_array {
    	DECLARE_BITMAP(bitmap, MAX_RT_PRIO+1); /* include 1 bit for delimiter */
    	struct list_head queue[MAX_RT_PRIO];
    };
    
    • 具有相同优先级的所有实时进程都保存在一个链表中,表头为active.queue[prio],而active.bitmap位图中的每个比特位对应一个链表,凡包含了进程的链表,对应的比特位置位
  • 实时调度器类中对应于update_curr的是update_curr_rt,该函数将当前进程在CPU上执行花费的时间记录在sum_exec_runtime中,记录的是实际时间。

调度器操作

  • 进程的入队和离队都比较简单,只需以p->prio为索引访问queue数组,即可获得正确的链表,将进程加入或者从链表删除即可,当然要同步设置bitmap位图。

  • 选择下一个进程

    static struct task_struct *pick_next_task_rt(struct rq *rq)
    {
    	struct rt_prio_array *array = &rq->rt.active;
    	struct task_struct *next;
    	struct list_head *queue;
    	int idx;
    
    	idx = sched_find_first_bit(array->bitmap);
    	if (idx >= MAX_RT_PRIO)
    		return NULL;
    
    	queue = array->queue + idx;
    	next = list_entry(queue->next, struct task_struct, run_list);
    
    	next->se.exec_start = rq->clock;
    
    	return next;
    }
    
  • 周期调度

    static void task_tick_rt(struct rq *rq, struct task_struct *p)
    {
    	update_curr_rt(rq);
    
    	/*
    	 * RR tasks need a special form of timeslice management.
    	 * FIFO tasks have no timeslices.
    	 */
    	if (p->policy != SCHED_RR)
    		return;
    
    	if (--p->time_slice)
    		return;
    
    	p->time_slice = DEF_TIMESLICE;
    
    	/*
    	 * Requeue to the end of queue if we are not the only element
    	 * on the queue:
    	 */
    	if (p->run_list.prev != p->run_list.next) {
    		requeue_task_rt(rq, p);
    		set_tsk_need_resched(p);
    	}
    }
    
    • SCHED_FIFO进程可以运行任意长时间,因此直接返回即可
    • SCHED_RR进程减少其时间片,在尚未超出时间段时,直接返回,否则重置时间片为DEF_TIMESLICE(100ms),另外如果该进程不是链表中的唯一的进程,则重新排队到末尾
  • 实时进程转换

    • 使用sched_setscheduler系统调用,必须具有root权限或者CAP_SYS_NICE能力:使用deactive_task将进程从当前队列删除;在task_struct中设置实时优先级和调度类;重新激活进程
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值