context_switch 代码走读(1)

mm和active_mm

这里又引申出来一个成员变量 mm_usersmm_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 情况,释放“借用”内存

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇