ILD

Process Management & Scheduling
作者:YUAN JIANPENG 邮箱:yuanjp@hust.edu.cn
发布时间:2018-8-19 站点:Inside Linux Development

Process Descriptor and the Task Structure

进程描述符是struct task_struct类型,定义在<linux/sched.h>,进程描述符包含了进程的所有信息。


Allocating the Process Descriptor

task_struct结构使用slab allocator分配。


2.6之前,task_struct存储在进程内核栈的底部。这样就不需要额外的寄存器来存储。


现在进程描述符使用slab allocator,一个新的结构体struct thread_info创建在栈的底部。


Storing the Process Descriptor

系统通过PID来标识进程。其类型是pid_t,最大为32768。可以通过/proc/sys/kernel/pid_max修改。


在x86中,current_thread_info() 可以获取 thread_info结构体的指针:

1
2
movl $-8192, %eax
andl %esp, %eax


进而得到task_struct.

1
current_thread_info()->task


在PPC架构中,current存储在r2寄存器中。


Process State

进程描述符中的state域存储了进程的当前状态。

TASK_RUNNING。进程是可运行的,它要么正在运行,要么在run queue中等待运行。这是执行在用户态的进程的唯一状态。

TASK_INTERRUPTIBLE。进程正在睡眠,正等待一个条件发生,来进入运行状态。

TASK_UNINTERRUPTIBLE。和TASK_INTERRUPTIBLE一样,除了收到信号不被唤醒外。


Multitasking

多任务操作系统分为:cooperative multitasking 和 preemptive multitasking。


Policy

I/O-Bound Process

进行频繁的IO处理


Processor-Bound Process

进行频繁的处理器运行


Process Priority

Linux有两种优先级。


第一种是nice值,从-20到+19。默认是0。nice值越大优先级越低。在Linux中,nice值控制时间片的比例。


第二种是 real-time priority。


timeslice


Wait queues

睡眠是通过wait queue处理的。一个wait queue是一个简单的进程列表,它们等待一个事件发生。在内核中wait queue使用wake_queue_head_t表示。


wait queue可以通过DECLARE_WAITQUEUE()静态创建,也可以通过init_waitqueue_head()动态创建。


进程可以主动把它们自己放入等待队列,然后标记自己为不可运行。当等待队列关联的事件发生时,等待队列中的线程被唤醒。


等待、唤醒的典型逻辑如下:

1
2
3
4
5
6
7
8
9
10
11
DEFINE_WAIT(wait);
 
add_wait_queue(q, &wait);
while (!condition) {
    /* condition is the event that we are waiting for */
    prepare_to_wait(&q, &wait, TASK_INTERRUPTIBLE);
    if (signal_pending(current))
        /* handle signal */
    schedule();
}
finish_wait(&q, &wait);


1. 创建一个wait queue entry,使用DEFINE_WAIT()

2. 使用add_wait_queue()将自己添加到等待队列q

3. prepare_to_wait()来将进程的状态变为TASK_INTERRUPTIBLE,并且会再次尝试将进程添加到等待队列。

使用finish_wait()将进程从等待队列中移除。


Waking Up

通过wake_up()


Preemption and Context Switching

上下文从切换由context_switch()处理,定义在kernel/sched.c。被schedule()调用。


user preemption 发生在

从系统调用返回到用户空间时

从中断处理返回到用户空间时


kernel preemption 发生在

中断处理退出,返回到kernel-space时

内核代码再次变成可抢断时

显示调用schedule()

If a task in the kernel blocks (which results in a call to schedule() )


Real-Time Scheduling Policies

内核提供两种real-time调度策略,SCHED_FIFO和SCHED_RR。非real-time调度策略即SCHED_NORMAL。

real-time调度不是CFS调度的。由特殊的real-time scheduler,定义在kernel/sched_rt.c调度。


SCHED_FIFO是一个陷入先出的调度算法,没有时间片。这种task总是调度在SCHED_NORMAL之前,当SCHED_FIFO task变成可运行后,它会次序运行,直到block或者显式放弃处理器。更高优先级的SCHED_FIFO和SCHED_RR可以抢占SCHED_FIFO。相同优先级的使用round-robin,但是只有task显式的放弃处理器时才会这样调度。如果SCHED_FIFO任务是可运行的,低优先级的不能被运行。


SCHED_RR和SCHED_FIFO基本一样,但是它们一直运行,直到预定义的时间片耗尽。


实时优先级从0到MAX_RT_PRIO-1。通常MAX_RT_PRIO为100


SCHED_NORMAL 任务的nice值,映射到 MAX_RT_PRIO到 MAX_RT_PRIO+40,-20, +19 映射到100, 139。


Scheduler-Related System Calls

如下

System callDescription
nice()set a process's nice value
sched_setscheduler()set a processos's scheduling policy
sched_getscheduler()Gets a process’s scheduling policy
sched_setparam()Sets a process’s real-time priority
sched_getparam()Gets a process’s real-time priority
sched_get_priority_max()Gets the maximum real-time priority
sched_get_priority_min()Gets the minimum real-time priority
sched_rr_get_interval()Gets a process’s timeslice value
sched_setaffinity()Sets a process’s processor affinity
sched_getaffinity()Gets a process’s processor affinity
sched_yield()Temporarily yields the processor


Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.