context_switch( )上下文切换:
context_switch( )函数建立next的地址空间。进程描述符的active_mm字段指向进程所使用的内存描述符,而mm字段
指向进程所拥有的内存描述符。对于一般的进程,这两个字段有相同的地址,但是,内核线程没有它自己的地址空间而且它的 mm字段总是被设置为 NULL。context_switch( )函数保证:如果next是一个内核线程,它使用prev所使用的地址空间:
static inline
task_t * context_switch(runqueue_t *rq, task_t *prev, task_t *next)
{
struct mm_struct *mm = next->mm;
struct mm_struct *oldmm = prev->active_mm;
如果next是内核线程,则线程使用prev所使用的地址空;schedule( )函数把该线程设置为懒惰TLB模式
事实上,每个内核线程并不拥有自己的页表集(task_struct->mm = NULL);更确切地说,它使用一个普通进程的页表集。不过,没有必要使一个用户态线性地址对应的TLB表项无效,因为内核线程不访问用户态地址空间。
|--------------------------------------|
| if (unlikely(!mm)) { |
| next->active_mm = oldmm; |
| atomic_inc(&oldmm->mm_count); |
| enter_lazy_tlb(oldmm, next); |
|--------------------------------------|
如果next是一个普通进程,schedule( )函数用next的地址空间替换prev的地址空间
|--------------------------------------|
| } else |
| switch_mm(oldmm, mm, next); |
|--------------------------------------|
如果prev是内核线程或正在退出的进程,context_switch()函数就把指向prev内存描述符的指针保存到运行队列的prev_mm字段中,然后重新设置prev->active_mm
|----------------------------------|
| if (unlikely(!prev->mm)) { |
| prev->active_mm = NULL; |
| WARN_ON(rq->prev_mm); |
| rq->prev_mm = oldmm; |
|----------------------------------|
}
context_switch()终于可以调用switch_to()执行prev和next之间的进程切换了
|----------------------------------|
| switch_to(prev, next, prev); |
|----------------------------------|
return prev;
}
- 调用switch_mm(),把虚拟内存从一个进程映射切换到新进程中
- 调用switch_to(),从上一个进程的处理器状态切换到新进程的处理器状态。这包括保存、恢复栈信息和寄存器信息
context_switch( )函数建立next的地址空间。进程描述符的active_mm字段指向进程所使用的内存描述符,而mm字段
指向进程所拥有的内存描述符。对于一般的进程,这两个字段有相同的地址,但是,内核线程没有它自己的地址空间而且它的 mm字段总是被设置为 NULL。context_switch( )函数保证:如果next是一个内核线程,它使用prev所使用的地址空间:
static inline
task_t * context_switch(runqueue_t *rq, task_t *prev, task_t *next)
{
struct mm_struct *mm = next->mm;
struct mm_struct *oldmm = prev->active_mm;
如果next是内核线程,则线程使用prev所使用的地址空;schedule( )函数把该线程设置为懒惰TLB模式
事实上,每个内核线程并不拥有自己的页表集(task_struct->mm = NULL);更确切地说,它使用一个普通进程的页表集。不过,没有必要使一个用户态线性地址对应的TLB表项无效,因为内核线程不访问用户态地址空间。
|--------------------------------------|
| if (unlikely(!mm)) { |
| next->active_mm = oldmm; |
| atomic_inc(&oldmm->mm_count); |
| enter_lazy_tlb(oldmm, next); |
|--------------------------------------|
如果next是一个普通进程,schedule( )函数用next的地址空间替换prev的地址空间
|--------------------------------------|
| } else |
| switch_mm(oldmm, mm, next); |
|--------------------------------------|
如果prev是内核线程或正在退出的进程,context_switch()函数就把指向prev内存描述符的指针保存到运行队列的prev_mm字段中,然后重新设置prev->active_mm
|----------------------------------|
| if (unlikely(!prev->mm)) { |
| prev->active_mm = NULL; |
| WARN_ON(rq->prev_mm); |
| rq->prev_mm = oldmm; |
|----------------------------------|
}
context_switch()终于可以调用switch_to()执行prev和next之间的进程切换了
|----------------------------------|
| switch_to(prev, next, prev); |
|----------------------------------|
return prev;
}