1 进程描述符 struct task_struct

进程存在任务队列(tasklist)双向链表中;

1.1 进程地址空间

struct mm_struct,即是进程地址空间,也称为内存描述符;线程没有独立的地址空间,共享进程的;

2 进程调度

调度思想,进程以所有进程的时间片总和为一个调度周期,每个进程在一个调度周期内可能会调度多次,每次调度会更新自己counter计数(记录自己时间片剩余时间),当所有非阻塞状态的进程时间片耗尽是(counter=0),系统为每个进程重新分配时间片(conter值恢复默认值);

2.1 进程调度过程

schedule
|—- preempt_disable 关内核抢占
current_thread_info()->preempt_count 内核抢占计数的值+1
current_thread_info()->preempt_count 32bit数
bit[ 7, 0]: preempt_mask,内核抢占计数
bit[15, 8]: softirq_mask ,软中断计数
bit[19,16]: hardirq_mask,硬中断计数
bit[20]: nmi_mask,
bit[21]: preempt_active, 是否可以抢占
当内核在 nmi ,软/硬中断,内核抢占这些上下文中,都不允许发生抢占的情况。
|—- 获取当前cpu id及运行队列
|—- 关本地中断,上锁,配置标志位
|—- deactivate_task 将此进程从rq中移除
|—- idle_balance 如果rq为空,从其他cpu的运行队列获取任务。
|—- pick_next_task 选择rq中优先级最高的进程
//这个比较复杂,下面一小节单独将进程调度选择哪个进程的条件
|—- 更新rq->curr为准备运行的进程,增加切换计数等
|—- context_switch 上下文切换,更新栈信息、内存及寄存器等
|—- switch_to 更新栈和寄存器
|—- finish_task_switch

2.2 进程调度如何选择

进程调度分成两种情况,实时优先级调度和普通优先级调度。优先级不同,调度的权重不同。
实时优先级调度:0~99,值越大,优先级越高;
普通优先级调度:-20~19;

  • nice,对于普通进程来说,nice的范围-20~19,进程创建时确定的,所以nice值也叫静态优先级;通常情况下,进程的ncie值为0
  • counter,每个进程还有自己counter计数,记录自己剩余时间片,随着进程时间片消耗,不断更新,所以也称为动态优先级;counter能反应在一个调度周期内,自己被调度的情况,公平调度(CFS)情况下,当counter值大,说明之前被调度的少,在下次调度的时候,会优先考虑;

进程调度的权重,也就是weight,决定了谁应该被调度。weight与 nice和counter关系:weigth 正比于 counter+(20-nice)。

通常情况下,普通进程创建时,nice为0,通过counter动态调整调度权重weight;在goodness函数中可以看到weight在非实时进程的情况下,两次计算weight值,
第一次weight = p->conter
第二次weight += 20- p->nice

2.3 时间片怎么计算的

当该进程刚被其父进程fork出来时,是平分其父进程的剩余时间片的。这个时间片执行完后,就会根据它的初始优先级来重新分配时间片,优先级为+19时最低,只分配最小时间片5ms,优先级为0时是100ms,优先级是-20时是最大时间片800ms。

2.3.1 prio

prio将实时优先级和普通优先级记性排序,prio = 实时优先级(0-99)+ 普通优先级(-20~19)排列:

  • 普通优先级从100~139,即prio100=普通优先级-20;
  • prio的0-99对应实时优先级的99-0(实时优先级取反对应);

    2.3.2 计算时间片

    根据prio值分成两种:
    1、如果prio小于120:time_slice=20(140-prio) //nice为-20(prio=100)时粉的最大时间片800ms
    2、如果prio大于等于120:time_slice=5
    (140-prio) //nice为+19(prio=139)时最低,只分配最小时间片5ms

linux源码如下:
#define SCALE_PRIO(x, prio) \
max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO/2), MIN_TIMESLICE)

static unsigned int task_timeslice(task_t p)
{
if (p->static_prio < NICE_TO_PRIO(0))
return SCALE_PRIO(DEF_TIMESLICE
4, p->static_prio);
else
return SCALE_PRIO(DEF_TIMESLICE, p->static_prio);