mm和active_mm
- 用户态进程
tsk->mm = tsk->active_mm ---->指向内存地址; - 内核态进程
tsk->mm = NULL
tsk->active_mm = pre_tsk->active_mm;
具体可以参考这个链接:
active_mm
https://zhuanlan.zhihu.com/p/66971714
这里又引申出来一个成员变量 mm_users
和 mm_count
/**
* @mm_users: The number of users including userspace.
*
* Use mmget()/mmget_not_zero()/mmput() to modify. When this
* drops to 0 (i.e. when the task exits and there are no other
* temporary reference holders), we also release a reference on
* @mm_count (which may then free the &struct mm_struct if
* @mm_count also drops to 0).
*/
atomic_t mm_users;
/**
* @mm_count: The number of references to &struct mm_struct
* (@mm_users count as 1).
*
* Use mmgrab()/mmdrop() to modify. When this drops to 0, the
* &struct mm_struct is freed.
*/
atomic_t mm_count;
上面总结出来就是可以发现无论多少userspace的process,只会增加users的计数,而mm_count的计数只为1,
可以推论得知,当mm_count的值大于1的时候应该有内核进程在引用该VMA空间;
context_switch代码
/*
* context_switch - switch to the new MM and the new thread's register state.
*/
static __always_inline struct rq *
context_switch(struct rq *rq, struct task_struct *prev,
struct task_struct *next, struct rq_flags *rf)
{
struct mm_struct *mm, *oldmm;
prepare_task_switch(rq, prev, next);
mm = next->mm; <===================== (1)
oldmm = prev->active_mm;
....
if (!mm) { <===================== (2)
next->active_mm = oldmm;
mmgrab(oldmm);
enter_lazy_tlb(oldmm, next);
} else
switch_mm_irqs_off(oldmm, mm, next); <====================(3)
if (!prev->mm) {
prev->active_mm = NULL;
rq->prev_mm = oldmm;
}
...
/* Here we just switch the register state and the stack. */
switch_to(prev, next, prev); <====================(4)
barrier();
return finish_task_switch(prev); <====================(5)
}
(1) 保存当前进程和即将切换进程指向虚拟内存区域的指针;
(2) 当切换进程是内核进程时
next->active_mm = oldmm;
; =======> 借用被切换进程的虚拟内存区域mmgrab(oldmm);
; =========>mm_count
加一enter_lazy_tlb(oldmm, next);
; ===========>this_cpu_write(cpu_tlbstate.is_lazy, true);
设置pre-cpu的tlb为lazy,最小化的flush tlb
(3) 进程空间的切换
void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
{
...
this_cpu_write(cpu_tlbstate.is_lazy, false);
...
barrier();
if (need_flush) {
...
load_new_mm_cr3(next->pgd, new_asid, true);
...
} else {
/* The new ASID is already up to date. */
load_new_mm_cr3(next->pgd, new_asid, false);
...
}
/* Make sure we write CR3 before loaded_mm. */
barrier();
...
}
/*
If set, RDPMC can be executed at any privilege level, else RDPMC can only be used in ring 0.
*/
load_mm_cr4(next);
switch_ldt(real_prev, next);
}
(4) 进程上下文的切换
(5) 完成进程切换
static struct rq *finish_task_switch(struct task_struct *prev)
__releases(rq->lock)
{
struct rq *rq = this_rq();
/*
在context_switch的代码里面
oldmm = prev->active_mm;
if (!prev->mm) {
prev->active_mm = NULL;
rq->prev_mm = oldmm;
}
*/
struct mm_struct *mm = rq->prev_mm;
long prev_state;
...
rq->prev_mm = NULL;
prev_state = prev->state;
...
if (mm) {
membarrier_mm_sync_core_before_usermode(mm);
mmdrop(mm); <================= (1)
}
if (unlikely(prev_state == TASK_DEAD)) {
...
/* Task is done with its stack. */
put_task_stack(prev);
put_task_struct(prev);
}
...
}
(1) 在 B(kernel)---->c 情况,释放“借用”内存