linux rt调度器

    xiaoxiao2021-03-26  21

    RT(RealTime scheduler)实时调度器,对应用户设定的调度策略为 SCHED_FIFO/SCHED_RR。 SCHED_FIFO 先进先出队列调度,高优先级任务一直运行,直到任务阻塞,或者主动退出,或者被更高优先级 任务抢占。 SCHED_RR 时间片轮转调度,每个实时任务划分一个时间片,时间片用完会切换到其他任务执行。 进程几种状态表示: 1.      TASK_RUNNING: 这里表示进程没有被阻塞,即READY和RUNNING的结合体。至于具体是READY还是 RUNNING,在需要的时候可以做如下判断:调度程序取得该进程的进程状态为TASK_RUNNING且其所在CPU的current_task就是该进程,则认定他是RUNNING,否则就是READY。需要做如上判断的情况其实并不多,所以统以TASK_RUNNING描述便已足够。 2.      TASK_INTERRUPTIBLE: 进程处于BLOCK状态且可以被SIGNAL唤醒 3.      TASK_UNINTERRUPTIBLE: 进程处于BLOCK状态但不能被SIGNAL唤醒 4.      TASK_ZOMBIE: 进程已经结束,但描述符还没有被回收。 5.      TASK_STOPPED: 进程停止运行。通常在收到SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU等信号时发生;或者在调试时收到任何信号都会发生。可向其发送SIGCONT使其继续运行。 task的状态记录在task_struct结构的state成员中。 调度程序每次从处于running状态的task中选择一个最合适的来运行。 RT调度器的核心是优先级队列,调度程序从最高优先级队列头部选择一个task运行, 调度结束会将任务放到对应的优先级队列尾部。 bitmap标示优先级,某个bit置1标示该优先级队列不为空。 struct rt_prio_array { DECLARE_BITMAP(bitmap, MAX_RT_PRIO+1); /* include 1 bit for delimiter */ struct list_head queue[MAX_RT_PRIO];

    };

    task入队操作:

    /* * Adding/removing a task to/from a priority array: */ static void enqueue_task_rt(struct rq *rq, struct task_struct *p, int flags) { struct sched_rt_entity *rt_se = &p->rt; if (flags & ENQUEUE_WAKEUP) rt_se->timeout = 0; //flag为0的话,将实体的run_list 加入优先级队列queue尾部,否则插入头部,优先调度。 enqueue_rt_entity(rt_se, flags & ENQUEUE_HEAD); //p不是当前rq正在运行进程,并且p可以在其他cpu上运行,就将p进入rq pushable_tasks,可以做负载均衡时使用, if (!task_current(rq, p) && p->nr_cpus_allowed > 1) enqueue_pushable_task(rq, p); inc_nr_running(rq); inc_hmp_sched_stats_rt(rq, p); } //先将实体所做task group删除队列,然后再依次入队列 static void enqueue_rt_entity(struct sched_rt_entity *rt_se, bool head) { dequeue_rt_stack(rt_se); for_each_sched_rt_entity(rt_se) __enqueue_rt_entity(rt_se, head); } static void dequeue_rt_stack(struct sched_rt_entity *rt_se) { struct sched_rt_entity *back = NULL; //从下往上遍历,支持task group for_each_sched_rt_entity(rt_se) { rt_se->back = back; back = rt_se; } //从上往下遍历,依次出队 for (rt_se = back; rt_se; rt_se = rt_se->back) { if (on_rt_rq(rt_se)) __dequeue_rt_entity(rt_se); } } static void __dequeue_rt_entity(struct sched_rt_entity *rt_se) { struct rt_rq *rt_rq = rt_rq_of_se(rt_se);//实体所在rq struct rt_prio_array *array = &rt_rq->active; //优先级数组 list_del_init(&rt_se->run_list);//list中删除实体 if (list_empty(array->queue + rt_se_prio(rt_se)))//该实体所在优先级队列为空 __clear_bit(rt_se_prio(rt_se), array->bitmap);//bitmap标识对应优先级queue 是否为空 dec_rt_tasks(rt_se, rt_rq); if (!rt_rq->rt_nr_running) list_del_leaf_rt_rq(rt_rq); } //入队,调度实体加入对应优先级队列中 static void __enqueue_rt_entity(struct sched_rt_entity *rt_se, bool head) { struct rt_rq *rt_rq = rt_rq_of_se(rt_se);//实体所在rq struct rt_prio_array *array = &rt_rq->active;//优先级数组 struct rt_rq *group_rq = group_rt_rq(rt_se);//实体所属group struct list_head *queue = array->queue + rt_se_prio(rt_se);//优先级队列 /* * Don't enqueue the group if its throttled, or when empty. * The latter is a consequence of the former when a child group * get throttled and the current group doesn't have any other * active members. */ if (group_rq && (rt_rq_throttled(group_rq) || !group_rq->rt_nr_running)) return; if (!rt_rq->rt_nr_running) list_add_leaf_rt_rq(rt_rq); if (head) list_add(&rt_se->run_list, queue); else list_add_tail(&rt_se->run_list, queue); __set_bit(rt_se_prio(rt_se), array->bitmap); inc_rt_tasks(rt_se, rt_rq); } //出队操作,更新rq当前task 状态,实体出队,然后实体加入队列尾部 static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int flags) { struct sched_rt_entity *rt_se = &p->rt; update_curr_rt(rq); dequeue_rt_entity(rt_se); dequeue_pushable_task(rq, p); dec_nr_running(rq); dec_hmp_sched_stats_rt(rq, p); } static void dequeue_rt_entity(struct sched_rt_entity *rt_se) { dequeue_rt_stack(rt_se); //先从运行队列删除调度实体 for_each_sched_rt_entity(rt_se) { struct rt_rq *rt_rq = group_rt_rq(rt_se); if (rt_rq && rt_rq->rt_nr_running) __enqueue_rt_entity(rt_se, false);//将调度实体再重新加入队列尾部 } } //RT调度器选择下个task过程: static struct task_struct *pick_next_task_rt(struct rq *rq) { struct task_struct *p = _pick_next_task_rt(rq); /* The running task is never eligible for pushing */ //p接下来将开始运行,自然不需要再push到其他rq if (p) dequeue_pushable_task(rq, p); #ifdef CONFIG_SMP /* * We detect this state here so that we can avoid taking the RQ * lock again later if there is no need to push */ rq->post_schedule = has_pushable_tasks(rq); #endif return p; } static struct task_struct *_pick_next_task_rt(struct rq *rq) { struct sched_rt_entity *rt_se; struct task_struct *p; struct rt_rq *rt_rq; rt_rq = &rq->rt; //TASK_RUNNIG 数目 if (!rt_rq->rt_nr_running) return NULL; if (rt_rq_throttled(rt_rq)) return NULL; do {//处理组调度,task group 父进程在子进程的后面 rt_se = pick_next_rt_entity(rq, rt_rq); BUG_ON(!rt_se); rt_rq = group_rt_rq(rt_se);//实体在这个rq上 } while (rt_rq); /* * Force update of rq->clock_task in case we failed to do so in * put_prev_task. A stale value can cause us to over-charge execution * time to real-time task, that could trigger throttling unnecessarily */ if (rq->skip_clock_update > 0) { rq->skip_clock_update = 0; update_rq_clock(rq); } p = rt_task_of(rt_se); p->se.exec_start = rq_clock_task(rq);//rt优先级可能会调整为nice? return p; } //找个rq最高优先级队列第一个进程 static struct sched_rt_entity *pick_next_rt_entity(struct rq *rq, struct rt_rq *rt_rq) { struct rt_prio_array *array = &rt_rq->active; struct sched_rt_entity *next = NULL; struct list_head *queue; int idx; //第一个为1的bit代表了优先级queue的idx idx = sched_find_first_bit(array->bitmap); BUG_ON(idx >= MAX_RT_PRIO); queue = array->queue + idx; next = list_entry(queue->next, struct sched_rt_entity, run_list); return next; }

    转载请注明原文地址: https://ju.6miu.com/read-658585.html

    最新回复(0)