active_mm versus mm in the task_struct

Overview

In sched.h we see that each task has

  ...
        struct list_head tasks;
        struct list_head ptrace_children;
        struct list_head ptrace_list;
                                                                                                                              
----->  struct mm_struct *mm, *active_mm;  <-----
 
/* task state */
        struct linux_binfmt *binfmt;
        int exit_code, exit_signal;
        int pdeath_signal;  /*  The signal sent when the parent dies  */
        /* ??? */
  ...

Each process clearly has a mm_struct associated with it -- this gives the pages tables for the process. But what good is the active_mm?

Kernel Threads

Kernel threads have no user space context. They have no need for page tables of their own, so don't really need a struct_mm mm allocated. But on the other hand, you want kernel threads to act like normal threads in terms of scheduling, where you obviously need to switch struct_mm mm's when you swap processes. Swapping around this on context switches to kernel threads would be a waste, as it would just be a dummy structure. Thus kernel threads borrow the user space struct_mm mm for their own use.

In the scheduler sched.c

/*
 * context_switch - switch to the new MM and the new
 * thread's register state.
 */
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;

        if (unlikely(!mm)) {
                next->active_mm = oldmm;
                atomic_inc(&oldmm->mm_count);
                enter_lazy_tlb(oldmm, next, smp_processor_id());
        } else
                switch_mm(oldmm, mm, next, smp_processor_id());

        if (unlikely(!prev->mm)) {
                prev->active_mm = NULL;
                WARN_ON(rq->prev_mm);
                rq->prev_mm = oldmm;
        }

        /* Here we just switch the register state and the stack. */
        switch_to(prev, next, prev);

        return prev;
}

So you can see here that if the task doesn't have an mm  if (!mm)  we set the active_mm of the process we are about to switch to (the kernel thread) to the old thread's (the user space threads) mm.

If you switch from a kernel thread to a kernel thread you will be OK, because you 'chain' on the active_mm. For user tasks, I think the general rule that active_mm == mm should be true?

Personal Note

This is pretty interesting, but only appears to be intrinsically documented. sigh.

IA64wiki: activemm (last edited 2003-05-07 05:20:11 by mingus)

Gelato@UNSW is sponsored by
the University of New South Wales National ICT Australia The Gelato Federation Hewlett-Packard Company Australian Research Council
Please contact us with any questions or comments.