好文档 - 专业文书写作范文服务资料分享网站

(VR虚拟现实技术)L进程调度切换和虚拟空间管理深入分析最全版

天下 分享 时间: 加入收藏 我要投稿 点赞

更新进程的睡眠时间和动态优先级,SCHED_NORMAL调度。

4) schedule( ) 进程调度

5) load_balance() SMP系统的负载均衡。

4.schedule( )函数

进程调度有两种方式:直接调用和延迟调用。

直接调用schedule,当前进程资源不可用时会直接调用调度器,这种情况下,内核线程进行如下处理:

1) 将current插入到合适的等待队列中; 2) 将current状态变为TASK_INTERRUPTIBLE 或TASK_UNINTERRUPTIBLE 3) 调用schedule();

4) 检查资源是否可用,如果不可用,转到第2)步; 5) 一旦资源可用,从等待队列中移除current进程;

在设备驱动程序中也经常会检查TIF_NEED_RESCHED并调用schedule()。

延迟调用方式是通过设置current进程的TIF_NEED_RESCHED标志为1。当恢复用户态进程的执行前,会检查该标志并决定是否调用schedule()。延迟调度的情形有:

1) 在scheduler_tick()中如果current用完了时间片则设置该标志; 2) 在try_to_wake_up( )中唤醒一个进程并且该进程比当前运行进程优先级高。

3) 调用sched_setscheduler()时。

schedule()函数工作流程: 进程切换前的工作:

1) 禁止内核抢占,初始化局部变量prev,释放prev占有的大内核锁; need_resched: preempt_disable(); prev = current;

release_kernel_lock(prev);

2) 读取调度TSC时间,计算调整run_time时间, 更新调度状态rq->sched_cnt参数,获取rq的spin锁:spin_lock_irq(&rq->lock)。 3) 检查prev状态:如果状态不是TASK_RUNNING且没有在内核态被抢占,则从运行队列中移除;但是如果prev状态是TASK_INTERRUPTIBLE并且拥有非阻塞挂起的信号,则把进程状态设为TASK_RUNNING不移出运行队列。 if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) { switch_count = &prev->nvcsw;

if (unlikely((prev->state & TASK_INTERRUPTIBLE) && unlikely(signal_pending(prev))))

prev->state = TASK_RUNNING; else {

if (prev->state == TASK_UNINTERRUPTIBLE) rq->nr_uninterruptible++; deactivate_task(prev, rq); } }

4) 获取当前CPU逻辑号,如果当前运行队列为空,则调用idle_balance(cpu, rq)从其他CPU运行队列上拉进程到本地CPU的运行队列上。如果调整后,当前运行队列仍为空则next赋为idle进程,跳转到任务切换代码行去。 if (unlikely(!rq->nr_running)) { idle_balance(cpu, rq); if (!rq->nr_running) { next = rq->idle;

rq->expired_timestamp = 0; goto switch_tasks; } }

5) 如果runqueue中有进程,并且当前活得进程数为0,则交换active 和 expired队列指针。 array = rq->active;

if (unlikely(!array->nr_active)) {

schedstat_inc(rq, sched_switch); rq->active = rq->expired; rq->expired = array; array = rq->active;

rq->expired_timestamp = 0; rq->best_expired_prio = MAX_PRIO; }

6) 从运行队列的活动prio_array数据的位图中查找第一个位设置为1的索引,根据索引找到该优先级队列的第一个task。 idx = sched_find_first_bit(array->bitmap); queue = array->queue + idx;

next = list_entry(queue->next, struct task_struct, run_list);

7) 如果next是普通进程,并且next->sleep_type是

SLEEP_INTERACTIVE 或SLEEP_INTERRUPTED,则重新计算进程睡眠时间和进程优先级。

进程切换工作:

8) 更新sched_goidle,预期next结构数据,清除TIF_NEED_RESCHED标志,设置quiescent状态计数为1:rcu_data ->passed_quiesc = 1; switch_tasks: if (next == rq->idle)

schedstat_inc(rq, sched_goidle); prefetch(next); prefetch_stack(next);

clear_tsk_need_resched(prev); rcu_qsctr_inc(task_cpu(prev));

9) 更新prev进程运行时间戳prev->sleep_avg,prev->timestamp; 10) 调度信息切换到next,更新next;时间戳和运行队列信息: sched_info_switch(prev, next); if (likely(prev != next)) {

next->timestamp = next->last_ran = now; rq->nr_switches++; rq->curr = next; ++*switch_count; …… }

11) 进行进程切换,context_switch参见前面的分析,它进行进程空间和内核堆栈切换。prepare_lock_switch 功能是在定义了

__ARCH_WANT_INTERRUPTS_ON_CTXSW情况下,在切换前开中断spin_unlock_irq(&rq->lock); barrier()是保证代码执行顺序不变。 prepare_task_switch(rq, next); prev = context_switch(rq, prev, next);

(VR虚拟现实技术)L进程调度切换和虚拟空间管理深入分析最全版

更新进程的睡眠时间和动态优先级,SCHED_NORMAL调度。4)schedule()进程调度5)load_balance()SMP系统的负载均衡。4.schedule()函数进程调度有两种方式:直接调用和延迟调用。直接调用schedule,当前进程资源不可用时会直
推荐度:
点击下载文档文档为doc格式
5doo44si4f9epjx24qwd4i6jo0x1m7012b9
领取福利

微信扫码领取福利

微信扫码分享