½ø³Ì

Ŀ ¼

  1. ½ø³Ì
    1. ÐźÅ
    2. sched.c
    3. ½ø³ÌÐźŶÓÁÐ
    4. SMP
    5. ÄÚºËÏß³ÌҳĿ¼µÄ½èÓÃ
    6. ´úÂë·ÖÎö
    7. Ïß³Ì
    8. ½ø³ÌÃèÊö·û
    9. init½ø³Ì´ÓÄÚºË̬Çл»µ½Óû§Ì¬
    10. SET_LINKS
    11. REMOVE_LINKS
    12. get_wchan()
    13. sigframeµÄ½á¹¹
    14. rt_sigframe½á¹¹
    15. ÐźŶÓÁеĽṹ
    16. ÄÚºËÏ̼߳ò½é
    17. ½ø³ÌÇл»¼ò½é
    18. ͬ²½»úÖÆ


½ø³Ì

Ò»  ½ø³Ìµ÷¶È

    ½ø³ÌµÄ״̬([include/linux.h]):

TASK_RUNNING, it means that it is in the "Ready List"
TASK_INTERRUPTIBLE, task waiting for a signal or a resource (sleeping)
TASK_UNINTERRUPTIBLE, task waiting for a resource (sleeping), it is in same "Wait Queue"
TASK_ZOMBIE, task child without father
TASK_STOPPED, task being debugged

       ______________     CPU Available     ______________
      |              |  ---------------->  |              |
      | TASK_RUNNING |                     | Real Running |
      |______________|  <----------------  |______________|
                           CPU Busy
            |   /|\
Waiting for |    | Resource
Resource   |    | Available
           \|/   |
    ______________________
   |                      |
   | TASK_INTERRUPTIBLE / |
   | TASK-UNINTERRUPTIBLE |
   |______________________|

                     Main Multitasking Flow

    ´ÓϵͳÄں˵ĽǶȿ´À´£¬Ò»¸ö½ø³Ì½ö½öÊǽø³Ì¿ØÖÆ±í£¨process table£©ÖеÄÒ»Ïî¡£½ø³Ì¿ØÖƱíÖеÄÿһÏî¶¼ÊÇÒ»¸ötask_struct ½á¹¹£¬¶øtask_struct ½á¹¹±¾ÉíÊÇÔÚinclude/linux/sched.hÖж¨ÒåµÄ¡£ÔÚtask_struct½á¹¹Öд洢¸÷Öֵͼ¶ºÍ¸ß¼¶µÄÐÅÏ¢£¬°üÀ¨´ÓһЩӲ¼þÉ豸µÄ¼Ä´æÆ÷¿½±´µ½½ø³ÌµÄ¹¤×÷Ŀ¼µÄÁ´½Óµã¡£

    ½ø³Ì¿ØÖƱí¼ÈÊÇÒ»¸öÊý×飬ÓÖÊÇÒ»¸öË«ÏòÁ´±í£¬Í¬Ê±ÓÖÊÇÒ»¸öÊ÷¡£ÆäÎïÀíʵÏÖÊÇÒ»¸ö°üÀ¨¶à¸öÖ¸ÕëµÄ¾²Ì¬Êý×é¡£´ËÊý×éµÄ³¤¶È±£´æÔÚinclude/linux/tasks.h ¶¨ÒåµÄ³£Á¿NR_TASKSÖУ¬ÆäȱʡֵΪ128£¬Êý×éÖеĽṹÔò±£´æÔÚϵͳԤÁôµÄÄÚ´æÒ³ÖС£Á´±íÊÇÓÉnext_task ºÍprev_taskÁ½¸öÖ¸ÕëʵÏֵ쬶øÊ÷µÄʵÏÖÔò±È½Ï¸´ÔÓ¡£

    ϵͳÆô¶¯ºó£¬ÄÚºËͨ³£×÷Ϊijһ¸ö½ø³ÌµÄ´ú±í¡£Ò»¸öÖ¸Ïòtask_structµÄÈ«¾ÖÖ¸Õë±äÁ¿currentÓÃÀ´¼Ç¼ÕýÔÚÔËÐеĽø³Ì¡£±äÁ¿currentÖ»ÄÜÓÉkernel/sched.cÖеĽø³Ìµ÷¶È¸Ä±ä¡£µ±ÏµÍ³ÐèÒª²é¿´ËùÓеĽø³Ìʱ£¬Ôòµ÷ÓÃfor_each_task£¬Õ⽫±ÈϵͳËÑË÷Êý×éµÄËÙ¶ÈÒª¿ìµÃ¶à¡£

¶þ¡¢Óû§½ø³ÌºÍÄÚºËÏß³Ì

    ijһ¸ö½ø³ÌÖ»ÄÜÔËÐÐÔÚÓû§·½Ê½£¨user mode£©»òÄں˷½Ê½£¨kernel mode£©Ï¡£Óû§³ÌÐòÔËÐÐÔÚÓû§·½Ê½Ï£¬¶øÏµÍ³µ÷ÓÃÔËÐÐÔÚÄں˷½Ê½Ï¡£ÔÚÕâÁ½ÖÖ·½Ê½ÏÂËùÓõĶÑÕ»²»Ò»Ñù£ºÓû§·½Ê½ÏÂÓõÄÊÇÒ»°ãµÄ¶ÑÕ»£¬¶øÄں˷½Ê½ÏÂÓõÄÊǹ̶¨´óСµÄ¶ÑÕ»£¨Ò»°ãΪһ¸öÄÚ´æÒ³µÄ´óС£©

    ¾¡¹ÜlinuxÊÇÒ»¸öºêÄÚºËϵͳ£¬ÄÚºËÏß³ÌÒÀÈ»´æÔÚ£¬ÒԱ㲢Ðеش¦ÀíһЩÄں˵ġ°¼ÒÎñÊÒ¡±¡£ÕâЩÈÎÎñ²»Õ¼ÓÃUSER memory£¨Óû§¿Õ¼ä£©£¬¶ø½ö½öʹÓÃKERNEL memory¡£ºÍÆäËûÄÚºËÄ£¿éÒ»Ñù£¬ËüÃÇÒ²Ôڸ߼¶È¨ÏÞ£¨i386ϵͳÖеÄRING 0£©Ï¹¤×÷×÷¡£ÄÚºËÏß³ÌÊDZ»kernel_thread [arch/i386/kernel/process]´´½¨µÄ,ËüÓÖͨ¹ýµ÷ÓÃÖøÃûµÄcloneϵͳµ÷ÓÃ[arch/i386/kernel/process.c] (ÀàËÆforkϵͳµ÷ÓõÄËùÓй¦Äܶ¼ÊÇÓÉËü×îÖÕʵÏÖ):

int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
        long retval, d0;

        __asm__ __volatile__(
                "movl %%esp,%%esi\n\t"
                "int $0x80\n\t"         /* Linux/i386 system call */
                "cmpl %%esp,%%esi\n\t"  /* child or parent? */
                "je 1f\n\t"             /* parent - jump */
                /* Load the argument into eax, and push it.  That way, it does
                 * not matter whether the called function is compiled with
                 * -mregparm or not.  */
                "movl %4,%%eax\n\t"
                "pushl %%eax\n\t"
                "call *%5\n\t"          /* call fn */
                "movl %3,%0\n\t"        /* exit */
                "int $0x80\n"
                "1:\t"
                :"=&a" (retval), "=&S" (d0)
                :"0" (__NR_clone), "i" (__NR_exit),
                 "r" (arg), "r" (fn),
                 "b" (flags | CLONE_VM)
                : "memory");
        return retval;
}

    Ò»µ©µ÷Óã¬ÎÒÃǾÍÓÐÁËÒ»¸öеÄÈÎÎñ£¨Task£© (Ò»°ãPID¶¼ºÜС, ÀýÈç2,3,µÈ) µÈ´ýÒ»¸öÏìÓ¦ºÜÂýµÄ×ÊÔ´£¬ÀýÈçswap»òÕßusbʼþ£¬ÒÔ±ãͬ²½¡£ÏÂÃæÊÇһЩ×î³£ÓõÄÄÚºËÏß³Ì(Äã¿ÉÒÔÓÃps xÃüÁî):

PID      COMMAND
1        init
2        keventd
3        kswapd
4        kreclaimd
5        bdflush
6        kupdated
7        kacpid
67        khubd

     initÄÚºËÏß³ÌÒ²ÊÇÆô¶¯ÒÔºó×î³õµÄ½ø³Ì¡£ Ëü»áµ÷ÓÃÆäËüÓû§Ä£Ê½µÄÈÎÎñ£¬(/etc/inittab)ÀýÈç¿ØÖÆÌ¨ÊØ»¤½ø³Ì£¨daemons£©£¬ ttyÊØ»¤½ø³ÌÒÔ¼°ÍøÂçÊØ»¤½ø³Ì(rc½Å±¾)¡£

ÏÂÃæÊÇÒ»¸öµäÐ͵ÄÄÚºËÏß³Ìkswapd [mm/vmscan.c].
kswapdÊDZ»clone()½¨Á¢µÄ [arch/i386/kernel/process.c]''

|do_initcalls
   |kswapd_init
      |kernel_thread
         |syscall fork (in assembler)

·do_initcalls [init/main.c]
·kswapd_init [mm/vmscan.c]
·kernel_thread [arch/i386/kernel/process.c]

Èý ½ø³Ì´´½¨£¬ÔËÐкÍÏûʧ

    LinuxϵͳʹÓÃϵͳµ÷ÓÃfork( )À´´´½¨Ò»¸ö½ø³Ì£¬Ê¹ÓÃexit( )À´½áÊø½ø³Ì¡£fork( )ºÍexit( )µÄÔ´³ÌÐò±£´æÔÚkernel/fork.c and kernel/exit.cÖС£fork( )µÄÖ÷ÒªÈÎÎñÊdzõʼ»¯Òª´´½¨½ø³ÌµÄÊý¾Ý½á¹¹£¬ÆäÖ÷ÒªµÄ²½ÖèÓУº

1£©ÉêÇëÒ»¸ö¿ÕÏеÄÒ³ÃæÀ´±£´ætask_struct¡£
2£©²éÕÒÒ»¸ö¿ÕµÄ½ø³Ì²Û£¨find_empty_process( )£©¡£
3£©Îªkernel_stack_pageÉêÇëÁíÒ»¸ö¿ÕÏеÄÄÚ´æÒ³×÷Ϊ¶ÑÕ»¡£
4£©½«¸¸½ø³ÌµÄLDT±í¿½±´¸ø×Ó½ø³Ì¡£
5£©¸´ÖƸ¸½ø³ÌµÄÄÚ´æÓ³ÉäÐÅÏ¢¡£
6£©¹ÜÀíÎļþÃèÊö·ûºÍÁ´½Óµã¡£

|sys_fork
   |do_fork
      |alloc_task_struct
         |__get_free_pages
       |p->state = TASK_UNINTERRUPTIBLE
       |copy_flags
       |p->pid = get_pid
       |copy_files
       |copy_fs
       |copy_sighand
       |copy_mm // should manage CopyOnWrite (I part)
          |allocate_mm
          |mm_init
             |pgd_alloc -> get_pgd_fast
                |get_pgd_slow
          |dup_mmap
             |copy_page_range
                |ptep_set_wrprotect
                   |clear_bit // set page to read-only
          |copy_segments // For LDT
       |copy_thread
          |childregs->eax = 0
          |p->thread.esp = childregs // child fork returns 0
          |p->thread.eip = ret_from_fork // child starts from fork exit
       |retval = p->pid // parent fork returns child pid
       |SET_LINKS // insertion of task into the list pointers
       |nr_threads++ // Global variable
       |wake_up_process(p) // Now we can wake up just created child
       |return retval

·sys_fork [arch/i386/kernel/process.c]
·do_fork [kernel/fork.c]
·alloc_task_struct [include/asm/processor.c]
·__get_free_pages [mm/page_alloc.c]
·get_pid [kernel/fork.c]
·copy_files
·copy_fs
·copy_sighand
·copy_mm
·allocate_mm
·mm_init
·pgd_alloc -> get_pgd_fast [include/asm/pgalloc.h]
·get_pgd_slow
·dup_mmap [kernel/fork.c]
·copy_page_range [mm/memory.c]
·ptep_set_wrprotect [include/asm/pgtable.h]
·clear_bit [include/asm/bitops.h]
·copy_segments [arch/i386/kernel/process.c]
·copy_thread
·SET_LINKS [include/linux/sched.h]
·wake_up_process [kernel/sched.c]

    ³·ÏûÒ»¸ö½ø³Ì¿ÉÄÜÉÔ΢¸´ÔÓЩ£¬ÒòΪ³·Ïû×Ó½ø³Ì±ØÐë֪ͨ¸¸½ø³Ì¡£ÁíÍ⣬ʹÓÃkill( )Ò²¿ÉÒÔ½áÊøÒ»¸ö½ø³Ì¡£sys_kill( )¡¢sys_wait( )ºÍsys_exit( )¶¼±£´æÔÚÎļþexit.cÖС£

    ʹÓÃfork ( )´´½¨Ò»¸ö½ø³Ìºó£¬³ÌÐòµÄÁ½¸ö¿½±´¶¼ÔÚÔËÐС£Í¨³£Ò»¸ö¿½±´Ê¹ÓÃexec ( )µ÷ÓÃÁíÒ»¸ö¿½±´¡£ÏµÍ³µ÷ÓÃexec ( )¸ºÔð¶¨Î»¿ÉÖ´ÐÐÎļþµÄ¶þ½øÖÆ´úÂ룬²¢¸ºÔð×°ÈëºÍÔËÐС£LinuxϵͳÖеÄexec ( )ͨ¹ýʹÓÃlinux_binfmt½á¹¹Ö§³Ö¶àÖÖ¶þ½øÖƸñʽ¡£Ã¿ÖÖ¶þ½øÖƸñʽ¶¼´ú±í¿ÉÖ´ÐдúÂëºÍÁ´½Ó¿â¡£linux _binfmt½á¹¹ÖÖ°üº¬Á½¸öÖ¸Õ룬һ¸öÖ¸Ïò×°Èë¿ÉÖ´ÐдúÂëµÄº¯Êý£¬ÁíÒ»¸öÖ¸Ïò×°ÈëÁ´½Ó¿âµÄº¯Êý¡£

    UnixϵͳÌṩ¸ø³ÌÐòÔ±6ÖÖµ÷ÓÃexec( ) µÄ·½·¨¡£ÆäÖеÄ5ÖÖÊÇ×÷Ϊ¿âº¯ÊýʵÏÖ£¬¶øsys_execve( )ÊÇÓÉϵͳÄÚºËʵÏֵġ£ËüÖ´ÐÐÒ»¸öÊ®·Ö¼òµ¥µÄÈÎÎñ£º×°Èë¿ÉÖ´ÐÐÎļþµÄÎļþÍ·£¬²¢ÊÔͼִÐÐËü¡£Èç¹ûÎļþµÄÍ·Á½¸ö×Ö½ÚÊÇ#! ,ÄÇôËü¾Íµ÷ÓÃÔÚÎļþµÚÒ»ÐÐÖÐËùÖ¸¶¨µÄ½âÊÍÆ÷£¬·ñÔò£¬Ëü½«Öð¸ö³¢ÊÔ×¢²áµÄ¶þ½øÖƸñʽ¡£

[Ŀ¼]


ÐźÅ

struct semaphore {
        atomic_t count; ½ø³Ìץȡsemaphoreʱ¼õ1
        int sleepers; ץȡsemaphoreʧ°ÜʱÔö1
        wait_queue_head_t wait; semaphoreµÄµÈ´ý¶ÓÁÐ
};
        down(&sem) ±àÒï³É:

        movl $sem,% ecx        ͨ¹ý¼Ä´æÆ÷ecxÏò__downº¯Êý´«µÝsemÖ¸Õë
        decl sem
        js 2f Èç¹ûΪ¸ºÖµ,±íʾsemaphoreÒѱ»Õ¼ÓÃ,Ö´ÐÐ__down_failed¹ý³Ì
1:
ÓÉÓÚ³öÏÖsemaphore¾ºÕùµÄ¿ÉÄÜÐԱȽÏС,½«·ÖÖ§´úÂë×ªÒÆµ½.text.lock¶Î,ÒÔËõ¶ÌÕý³£µÄÖ¸Áî·¾¶.
.section .text.lock,"ax"
2:        call __down_failed
        jmp 1b
.previous
        ...

        up(&sem) ±àÒï³É:

        movl $sem,% ecx
        incl sem
        jle 2f Èç¹ûСÓÚ»òµÈÓÚ0,±íʾ¸ÃsemaphoreÓнø³ÌÔڵȴý,¾ÍÈ¥µ÷ÓÃ__up_wakeup
1:
.section .text.lock,"ax"
2:        call __up_wakeup
        jmp 1b
.previous
        ...
__down_failed:
        pushl % eax
        pushl % edx
        pushl % ecx ; eax,edx,ecxÊÇ3¸ö¿ÉÓÃÓÚº¯Êý²ÎÊýµÄ¼Ä´æÆ÷
        call __down
        popl % ecx
        popl % edx
        popl % eax
        ret
__up_wakeup:
        pushl % eax
        pushl % edx
        pushl % ecx
        call __up
        popl % ecx
        popl % edx
        popl % eax
        ret
; semaphore.c
void __down(struct semaphore * sem)
{
        struct task_struct *tsk = current;
        DECLARE_WAITQUEUE(wait, tsk);
        tsk->state = TASK_UNINTERRUPTIBLE;
        add_wait_queue_exclusive(&sem->wait, &wait);
        // ½«µ±Ç°½ø³Ì¼ÓÈëµ½¸ÃsemaphoreµÄµÈ´ý¶ÓÁÐÖÐ

        spin_lock_irq(&semaphore_lock);
        sem->sleepers++;
        for (;;) {
                int sleepers = sem->sleepers;

                /*
                * Add "everybody else" into it. They aren't
                * playing, because we own the spinlock.
                */

                // atomic_add_negative(int i,atomic_t *v)½«i + v->counterÏà¼Ó,
                // ½á¹ûΪ¸º·µ»Ø1,·ñÔò·µ»Ø0
                if (!atomic_add_negative(sleepers - 1, &sem->count)) {
                // Èç¹û(sleepers - 1 + sem->count.counter)·Ç¸º,Ôò˵Ã÷
                // semaphoreÒѾ­±»ÊÍ·Å,¿ÉÒÔ·µ»Ø
                        sem->sleepers = 0;
                        break;
                }
                sem->sleepers = 1;        /* us - see -1 above */

                spin_unlock_irq(&semaphore_lock);
                // µ±semaphore±»up()»½ÐÑʱ,schedule()·µ»Ø
                schedule();
                // ËäÈ»ÒÑÏ̱߳»up»Ö¸´,µ«Îª·ÀÖ¹ÅöÇÉÓÖÓÐÒ»¸öÏ̻߳ñµÃÁËsemaphore,
                // Òò´Ë½«ËüÃÇ·ÅÔÚÑ­»·ÌåÖÐ
                tsk->state = TASK_UNINTERRUPTIBLE;
                spin_lock_irq(&semaphore_lock);
        }
        spin_unlock_irq(&semaphore_lock);
        // ¸Ã½ø³Ì»ñµÃÁËsemaphore,½«Ëü´ÓµÈ´ý¶ÓÁÐÖÐɾ³ý
        remove_wait_queue(&sem->wait, &wait);
        tsk->state = TASK_RUNNING;
        // ΪʲôÕâÀïÒªµ÷ÓÃwake_up,ÊÇÒòΪµ÷ÓÃËüûÓи±×÷ÓôӶø·ÀֹDZÔÚµÄËÀËøÂð?
        wake_up(&sem->wait);
}
void __up(struct semaphore *sem)
{
À©Õ¹Îª
__wake_up_common(&sem->wait,TASK_UNINTERRUPTIBLE|TASK_INTERRUPTIBLE,1,0);
»½ÐѶÓÁÐÖеÚ1¸ö½ø³Ì,¼´½«µÚ1¸ö½ø³Ì·ÅÈëÔËÐжÓÁÐ
        wake_up(&sem->wait);
}
; sched.c
static inline void __wake_up_common (wait_queue_head_t *q, unsigned int
mode,
                                     int nr_exclusive, const int sync)
{
        struct list_head *tmp, *head;
        struct task_struct *p;
        unsigned long flags;

        if (!q)
                goto out;

        wq_write_lock_irqsave(&q->lock, flags);

#if WAITQUEUE_DEBUG
        CHECK_MAGIC_WQHEAD(q);
#endif

        head = &q->task_list;
#if WAITQUEUE_DEBUG
        if (!head->next || !head->prev)
                WQ_BUG();
#endif
        tmp = head->next;
        while (tmp != head) {
                unsigned int state;
                wait_queue_t *curr = list_entry(tmp, wait_queue_t,
task_list);
                tmp = tmp->next;

#if WAITQUEUE_DEBUG
                CHECK_MAGIC(curr->__magic);
#endif
                p = curr->task;
                state = p->state;
                if (state & mode) {
#if WAITQUEUE_DEBUG
                        curr->__waker = (long)__builtin_return_address(0);
#endif
                        if (sync)
                                wake_up_process_synchronous(p);
                        else
                                wake_up_process(p);
                        if ((curr->flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
                                break;
                }
        }
        wq_write_unlock_irqrestore(&q->lock, flags);
out:
        return;
}
; sched.c
inline void wake_up_process(struct task_struct * p)
{
        unsigned long flags;

        /*
        * We want the common case fall through straight, thus the goto.
        */
        spin_lock_irqsave(&runqueue_lock, flags);
        p->state = TASK_RUNNING;
        if (task_on_runqueue(p))
                goto out;
        add_to_runqueue(p);
        reschedule_idle(p);
out:
        spin_unlock_irqrestore(&runqueue_lock, flags);
}
; sched.c
static inline void wake_up_process_synchronous(struct task_struct * p)
{
        unsigned long flags;

        /*
        * We want the common case fall through straight, thus the goto.
        */
        spin_lock_irqsave(&runqueue_lock, flags);
        p->state = TASK_RUNNING;
        if (task_on_runqueue(p))
                goto out;
        add_to_runqueue(p);
out:
        spin_unlock_irqrestore(&runqueue_lock, flags);
}
; sched.h
static inline int task_on_runqueue(struct task_struct *p)
{
        return (p->run_list.next != NULL);
}
; sched.c
static inline void add_to_runqueue(struct task_struct * p)
{
        list_add(&p->run_list, &runqueue_head);
        nr_running++;
}
static LIST_HEAD(runqueue_head);

; fork.c
void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *
wait)
{
        unsigned long flags;

        wq_write_lock_irqsave(&q->lock, flags);
        wait->flags = WQ_FLAG_EXCLUSIVE;
        __add_wait_queue_tail(q, wait);
        wq_write_unlock_irqrestore(&q->lock, flags);
}
; wait.h
static inline void __add_wait_queue_tail(wait_queue_head_t *head,
                                                wait_queue_t *new)
{
#if WAITQUEUE_DEBUG
        if (!head || !new)
                WQ_BUG();
        CHECK_MAGIC_WQHEAD(head);
        CHECK_MAGIC(new->__magic);
        if (!head->task_list.next || !head->task_list.prev)
                WQ_BUG();
#endif
        list_add_tail(&new->task_list, &head->task_list);
}
ÕýÖ´Ðе÷¶ÈµÄº¯ÊýÊÇschedule(void),ËüÑ¡ÔñÒ»¸ö×îºÏÊʵĽø³ÌÖ´ÐУ¬²¢ÇÒÕæÕý½øÐÐÉÏÏÂÎÄÇл»£¬
ʹµÃÑ¡ÖеĽø³ÌµÃÒÔÖ´ÐС£¶øreschedule_idle(struct task_struct *p)µÄ×÷ÓÃÊÇΪ½ø³ÌÑ¡Ôñ
Ò»¸öºÏÊʵÄCPUÀ´Ö´ÐУ¬Èç¹ûËüÑ¡ÖÐÁËij¸öCPU£¬Ôò½«¸ÃCPUÉϵ±Ç°ÔËÐнø³ÌµÄneed_resched±êÖ¾
ÖÃΪ1,È»ºóÏòËü·¢³öÒ»¸öÖØÐµ÷¶ÈµÄ´¦Àí»ú¼äÖжϣ¬Ê¹µÃÑ¡ÖеÄCPUÄܹ»ÔÚÖжϴ¦Àí·µ»ØÊ±Ö´ÐÐ
scheduleº¯Êý£¬ÕæÕýµ÷¶È½ø³ÌpÔÚCPUÉÏÖ´ÐС£ÔÚschedule()ºÍreschedule_idle()Öе÷ÓÃÁËgoodness()
º¯Êý¡£goodness()º¯ÊýÓÃÀ´ºâÁ¿Ò»¸ö´¦ÓÚ¿ÉÔËÐÐ״̬µÄ½ø³ÌÖµµÃÔËÐеij̶ȡ£´ËÍ⣬ÔÚschedule()
º¯ÊýÖл¹µ÷ÓÃÁËschedule_tail()º¯Êý;ÔÚreschedule_idle()º¯ÊýÖл¹µ÷ÓÃÁËreschedule_idle_slow()¡£


[Ŀ¼]


sched.c

|schedule
   |do_softirq // manages post-IRQ work
   |for each task
      |calculate counter
   |prepare_to__switch // does anything
   |switch_mm // change Memory context (change CR3 value)
   |switch_to (assembler)
      |SAVE ESP
      |RESTORE future_ESP
      |SAVE EIP
      |push future_EIP *** push parameter as we did a call
         |jmp __switch_to (it does some TSS work)
         |__switch_to()
          ..
         |ret *** ret from call using future_EIP in place of call address
      new_task


/*
* 'sched.c' is the main kernel file. It contains scheduling primitives
* (sleep_on, wakeup, schedule etc) as well as a number of simple system
* call functions (type getpid(), which just extracts a field from
* current-task
*/
#include
#include
#include
#include
#include
#include
#include
#define LATCH (1193180/HZ)
extern void mem_use(void);
extern int timer_interrupt(void);
extern int system_call(void);
union task_union {
struct task_struct task;
char stack[PAGE_SIZE];
};
static union task_union init_task = {INIT_TASK,};
long volatile jiffies=0;
long startup_time=0;
struct task_struct *current = &(init_task.task), *last_task_used_math =
NULL;
struct task_struct * task[NR_TASKS] = {&(init_task.task), };
long user_stack [ PAGE_SIZE>>2 ] ;
struct {
long * a;
short b;
} stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };
/*
* 'math_state_restore()' saves the current math information in the
* old math state array, and gets the new ones from the current task
*/
void math_state_restore() @@Э´¦ÀíÆ÷״̬±£´æ
{
if (last_task_used_math)
__asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
if (current->used_math)
__asm__("frstor %0"::"m" (current->tss.i387));
else {
__asm__("fninit"::);
current->used_math=1;
}
last_task_used_math=current;
}
/*
* 'schedule()' is the scheduler function. This is GOOD CODE! There
* probably won't be any reason to change this, as it should work well
* in all circumstances (ie gives IO-bound processes good response etc).
* The one thing you might take a look at is the signal-handler code
here.
*
* NOTE!! Task 0 is the 'idle' task, which gets called when no other
* tasks can run. It can not be killed, and it cannot sleep. The 'state'
* information in task[0] is never used.
*/
void schedule(void)
{
int i,next,c;
struct task_struct ** p;
/* check alarm, wake up any interruptible tasks that have got a signal
*/
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if (*p) {
if ((*p)->alarm && (*p)->alarm < jiffies) {
@@??
(*p)->signal |= (1<<(SIGALRM-1));@@14-1
(*p)->alarm = 0;
}
if ((*p)->signal && (*p)->state==TASK_INTERRUPTIBLE)
(*p)->state=TASK_RUNNING;
}
@@ task 1 ÈçºÎ±äΪTASK_RUNNING??signal ÈçºÎµÃµ½,alarmÈçºÎ±ä·Ç0ÇÒ /* this is the
scheduler proper: */
@@²Ù×÷ϵͳ×îÖØÒªµÄº¯Êý£¬µ÷¶ÈËã·¨
@@Õâ¸öÑ­»·ÒªÕÒµ½Ò»¸ö¿ÉÔËÐеÄÈÎÎñ²ÅÄÜÍ˳ö,»áËÀÔÚÕâÂð?¼´ÈçûÓÐÒ»¸ö¿ÉÔËÐÐ
while (1) {
c = -1;
next = 0;
i = NR_TASKS;
p = &task[NR_TASKS];
while (--i) {
if (!*--p)
continue;
if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
c = (*p)->counter, next = i;
}
if (c) break; @@¼ÇÊý´óÓÚÁã
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if (*p)
(*p)->counter = ((*p)->counter >> 1) +
(*p)->priority;
}
switch_to(next);
}
int sys_pause(void)
{
current->state = TASK_INTERRUPTIBLE; @@ÈÎÎñ¿ÉÖжÏ
schedule();
return 0;
}
void sleep_on(struct task_struct **p)
{
struct task_struct *tmp;
if (!p)
return;
if (current == &(init_task.task))
panic("task[0] trying to sleep");
tmp = *p;
*p = current;
current->state = TASK_UNINTERRUPTIBLE;
schedule();
if (tmp) @@¼¤»îp£¬Ê²Ã´Ê±ºò»ØÀ´£¿»½ÐÑÉÏ´Î˯ÃߵĽø³Ì
tmp->state=0;
}
void interruptible_sleep_on(struct task_struct **p)
{
struct task_struct *tmp;
if (!p)
return;
if (current == &(init_task.task))
panic("task[0] trying to sleep");
tmp=*p;
*p=current;
repeat: current->state = TASK_INTERRUPTIBLE;
schedule();
if (*p && *p != current) {
(**p).state=0;
goto repeat;
}
@@ºÃÏóϲ»À´
*p=NULL;
if (tmp)
tmp->state=0;
}
void wake_up(struct task_struct **p)
{
if (p && *p) {
(**p).state=0; @@»½ÐѸýø³Ìrunning
*p=NULL; @@˯ÃßջΪ0
}
}
void do_timer(long cpl) @@¶¨Ê±µ÷¶È
{
if (cpl)
current->utime++; @@Óû§Ì¬Ê±¼ä¼ÓÒ»
else
current->stime++; @@ϵͳ̬ʱ¼ä¼ÓÒ»
if ((--current->counter)>0) return; @@µ±Ç°¼ÇÊý¼õÒ»
current->counter=0;
if (!cpl) return;
schedule();
}
int sys_alarm(long seconds)
{
current->alarm = (seconds>0)?(jiffies+HZ*seconds):0;
return seconds;
}
int sys_getpid(void)
{
return current->pid;
}
int sys_getppid(void)
{
return current->father;
}
int sys_getuid(void)
{
return current->uid;
}
int sys_geteuid(void)
{
return current->euid;
}
int sys_getgid(void)
{
return current->gid;
}
int sys_getegid(void)
{
return current->egid;
}
int sys_nice(long increment)
{
if (current->priority-increment>0)
current->priority -= increment;
return 0;
}
int sys_signal(long signal,long addr,long restorer)
{
long i;
switch (signal) {
case SIGHUP: case SIGINT: case SIGQUIT: case SIGILL:
case SIGTRAP: case SIGABRT: case SIGFPE: case SIGUSR1:
case SIGSEGV: case SIGUSR2: case SIGPIPE: case SIGALRM:
case SIGCHLD:
i=(long) current->sig_fn[signal-1];
current->sig_fn[signal-1] = (fn_ptr) addr;
current->sig_restorer = (fn_ptr) restorer;
return i;
default: return -1;
}
}
void sched_init(void)
{
int i;
struct desc_struct * p;
set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));@@init task tss
set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));@@init ldt
p = gdt+2+FIRST_TSS_ENTRY;
for(i=1;i task[i] = NULL;
p->a=p->b=0;
p++;
p->a=p->b=0;
p++;
}
ltr(0); @@µ÷Èëtask 0µÄtss
lldt(0); @@µ÷Èëtask 0µÄldt
outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */
outb_p(LATCH & 0xff , 0x40); /* LSB */
outb(LATCH >> 8 , 0x40); /* MSB */
set_intr_gate(0x20,&timer_interrupt); @@irq 0 ʱÖÓÖжÏ
outb(inb_p(0x21)&~0x01,0x21);
set_system_gate(0x80,&system_call);
}


[Ŀ¼]


½ø³ÌÐźŶÓÁÐ

    ÿ¸ö½ø³Ì¾ßÓÐÒ»¸ösigpending½á¹¹ËùÃèÊöµÄÐźŶÓÁÐ,ËüÓÐ3¸ö³ÉÔ±,headÖ¸ÏòµÚÒ»¸ösigqueue³ÉÔ±,tailÖ¸Ïò×îÄ©µÄsigqueue³ÉÔ±µÄnextÖ¸Õë,signalÃèÊöÁ˴˶ÓÁÐÖеÄÐźż¯.

static int
send_signal(int sig, struct siginfo *info, struct sigpending *signals);
½«ÐźÅsigºÍ¶ÔÓ¦µÄÏûÏ¢½á¹¹infoÌí¼Óµ½ÐźŶÓÁÐsignalÖÐ.
static int
collect_signal(int sig, struct sigpending *list, siginfo_t *info);
·µ»ØÐźÅsigÔÚ¶ÓÁÐlistÖеÄÐÅÏ¢info.


struct task_struct {
        ...
        struct sigpending pending;
        ...
};
struct sigpending {
       struct sigqueue *head, **tail;
       sigset_t signal;
};
struct sigqueue {
       struct sigqueue *next;
       siginfo_t info;
       };
// kernel/signal.c
static int
send_signal(int sig, struct siginfo *info, struct sigpending *signals)
{
     struct sigqueue * q = NULL;
     /* Real-time signals must be queued if sent by sigqueue, or
       some other real-time mechanism.  It is implementation
      defined whether kill() does so.  We attempt to do so, on
      the principle of least surprise, but since kill is not
     allowed to fail with EAGAIN when low on memory we just
     make sure at least one signal gets delivered and don't
     pass on the info struct.  */

    if (atomic_read(&nr_queued_signals) < max_queued_signals) {
       q = kmem_cache_alloc(sigqueue_cachep, GFP_ATOMIC);
    }
    // nr_queued_signalsºÍmax_queued_signalsÓÃÀ´ÏÞÖÆÈ«¾Ösigqueue³ÉÔ±µÄÊýÄ¿
    if (q) {
        atomic_inc(&nr_queued_signals);
        q->next = NULL;
        *signals->tail = q;
        signals->tail = &q->next; tail×ÜÊÇÖ¸Ïò×îÄ©µÄÐźųÉÔ±µÄnextÖ¸Õë                switch ((unsign
ed long) info)
         {
        case 0:
          // info²ÎÊýÈç¹ûΪ0,±íʾÐźÅÀ´Ô´ÓÚµ±Ç°Óû§½ø³Ì                                  q->info.si_signo =
sig;
            q->info.si_errno = 0;
            q->info.si_code = SI_USER;
          q->info.si_pid = current->pid;
            q->info.si_uid = current->uid;
          break;
        case 1:
          // info²ÎÊýÈç¹ûΪ1,±íʾÐźÅÀ´Ô´ÓÚÄں˱¾Éí                                  q->info.si_signo = sig;
          q->info.si_errno = 0;
          q->info.si_code = SI_KERNEL;
           q->info.si_pid = 0;
          q->info.si_uid = 0;
           break;
        default:
           // ·ñÔò´ÓinfoÖ¸ÕëÖп½±´ÐźÅ
           copy_siginfo(&q->info, info);
          break;
        }
      }
      else if (sig >= SIGRTMIN && info && (unsigned long)info != 1                   && info->
si_code != SI_USER)
      {
        ; Èç¹û¸ÃÐźÅÊÇÄں˷¢³öµÄʵʱÐźÅ,¾Í·µ»Ø´íÎóÂë
        /*
         * Queue overflow, abort.  We may abort if the signal was rt
         * and sent by user using something other than kill().
       */
        return -EAGAIN;
      }
      sigaddset(&signals->signal, sig); ½«sigºÅ±ê¼ÇÔÚ¶ÓÁеÄÐźż¯ÉÏ
      return 0;
}
static int
collect_signal(int sig, struct sigpending *list, siginfo_t *info)
{
      if (sigismember(&list->signal, sig)) {
        /* Collect the siginfo appropriate to this signal.  */                struct sigqueue *q, **
pp;
         pp = &list->head; ppÖ¸ÏòµÚÒ»¸öÐźųÉÔ±µÄnextÖ¸Õë
        while ((q = *pp) != NULL) {
                if (q->info.si_signo == sig)                                            goto found_it;
                pp = &q->next;
         }
        /* Ok, it wasn't in the queue.  We must have
           been out of queue space.  So zero out the
          info.
         */
        sigdelset(&list->signal, sig);
        info->si_signo = sig;
        info->si_errno = 0;
        info->si_code = 0;
        info->si_pid = 0;
        info->si_uid = 0;
        return 1;
   found_it:
   // ½«ÕÒµ½ÐźųÉÔ±´ÓÐźŶÓÁÐÖÐɾ³ý
        if ((*pp = q->next) == NULL)
        list->tail = pp;
  /* Copy the sigqueue information and free the queue entry */
       copy_siginfo(info, &q->info);
       kmem_cache_free(sigqueue_cachep,q);
       atomic_dec(&nr_queued_signals);
  /* Non-RT signals can exist multiple times.. */
       if (sig >= SIGRTMIN) {
                while ((q = *pp) != NULL) {
                  if (q->info.si_signo == sig)                                             goto found_another;
                    pp = &q->next;
                }
       }
       sigdelset(&list->signal, sig);
    found_another:
        return 1;
    }
    return 0;
}

[Ŀ¼]


SMP

    ¶à´¦Àí»úϵͳÕýÔÚ±äµÃÔ½À´Ô½ÆÕͨ¡£¾¡¹Ü´ó¶àÊýÓû§¿Õ¼ä´úÂëÈÔ½«ÍêÃÀµØÔËÐУ¬¶øÇÒÓÐЩÇé¿öϲ»ÐèÒªÔö¼Ó¶îÍâµÄ´úÂë¾ÍÄÜÀûÓÃSMPÌØÐÔµÄÓÅÊÆ£¬µ«ÊÇÄں˿ռä´úÂë±ØÐë±àд³É¾ß±¸¡°SMPÒâʶ¡±ÇÒÊÇ¡°SMP°²È«µÄ¡±¡£ÒÔϼ¸¶ÎÎÄ×Ö½âÊÍÈçºÎÈ¥×ö¡£

ÎÊÌâ

    µ±Óжà¸öCPUʱ£¬Í¬ÑùµÄ´úÂë¿ÉÄÜͬʱÔÚÁ½¸ö»ò¶à¸öCPUÉÏÖ´ÐС£ÕâÔÚÈçÏÂËùʾÓÃÓÚ³õʼ»¯Ä³¸öͼÏñÉ豸µÄÀý³ÌÖпÉÄÜ»á³öÎÊÌâ¡£
        void init_hardware(void)
        {
            outb(0x1, hardware_base + 0x30);
            outb(0x2, hardware_base + 0x30);
            outb(0x3, hardware_base + 0x30);
            outb(0x4, hardware_base + 0x30);
        }
    ¼ÙÉè¸ÃÓ²¼þÒÀÀµÓڼĴæÆ÷0x30°´Ë³ÐòÒÀ´Î±»ÉèΪ0¡¢1¡¢2¡¢3À´³õʼ»¯£¬ÄÇôҪÊÇÓÐÁíÒ»¸öCPUÀ´²ÎºõµÄ»°£¬ÊÂÇé¾Í»á¸ãÔã¡£ÏëÏóÓÐÁ½¸öCPUµÄÇéÐΣ¬ËüÃǶ¼ÔÚÖ´ÐÐÕâ¸öÀý³Ì£¬²»¹ý2ºÅCPU½øÈëµÃÉÔÂýµã£º
        CPU 1                           CPU 2

        0x30 = 1
        0x30 = 2                        0x30 = 1
        0x30 = 3                        0x30 = 2
        0x30 = 4                        0x30 = 3
                                        0x30 = 4
    Õâ»á·¢ÉúʲôÇé¿öÄØ£¿´ÓÎÒÃÇÉèÏëµÄÓ²¼þÉ豸¿´À´£¬ËüÔڼĴæÆ÷0x30ÉÏÊÕµ½µÄ×Ö½Ú°´Ë³ÐòΪ£º1¡¢2¡¢1¡¢3¡¢2¡¢4¡¢3¡¢4¡£
    °¡£¡Ô­±¾ºÃºÃµÄʵڶþ¸öCPUÒ»À´¾Í¸ãµÃÒ»ÍÅÔãÁËÒ²¡£ËùÐÒµÄÊÇ£¬ÎÒÃÇÓзÀÖ¹ÕâÀàÊÂÇé·¢ÉúµÄ°ì·¨¡£

×ÔÐýËøÐ¡ÀúÊ·

    2.0.x°æ±¾µÄLinuxÄÚºËͨ¹ý¸øÕû¸öÄÚºËÒýÈëÒ»¸öÈ«¾Ö±äÁ¿À´·ÀÖ¹¶àÓÚÒ»¸öCPU»áÔì³ÉµÄÎÊÌâ¡£ÕâÒâζ×ÅÈκÎʱ¿ÌÖ»ÓÐÒ»¸öCPUÄܹ»Ö´ÐÐÀ´×ÔÄں˿ռäµÄ´úÂë¡£ÕâÑù¾¡¹ÜÄܹ¤×÷£¬µ«Êǵ±ÏµÍ³¿ªÊ¼ÒÔ¶àÓÚ2¸öµÄCPU³öÏÖʱ£¬À©Õ¹ÐÔÄܾͲ»ÔõôºÃ¡£
    2.1.x°æ±¾µÄÄÚºËϵÁмÓÈëÁËÁ£¶È¸üϸµÄSMPÖ§³Ö¡£ÕâÒâζ×Ų»ÔÙÒÀÀµÓÚÒÔǰ×÷Ϊȫ¾Ö±äÁ¿³öÏֵġ°´óËø¡±£¬¶øÊÇÿ¸öûÓÐSMPÒâʶµÄÀý³ÌÏÖÔÚ¶¼ÐèÒª¸÷×ÔµÄ×ÔÐýËø¡£Îļþasm/spinlock.hÖж¨ÒåÁËÈô¸ÉÀàÐ͵Ä×ÔÐýËø¡£
    ÓÐÁ˾ֲ¿»¯µÄ×ÔÐýËøºó£¬²»Ö¹Ò»¸öCPUͬʱִÐÐÄں˿ռä´úÂë¾Í±äµÃ¿ÉÄÜÁË¡£

¼òµ¥µÄ×ÔÐýËø

    Àí½â×ÔÐýËøµÄ×î¼òµ¥·½·¨ÊǰÑËü×÷Ϊһ¸ö±äÁ¿¿´´ý£¬¸Ã±äÁ¿°ÑÒ»¸öÀý³Ì»òÕß±ê¼ÇΪ¡°ÎÒµ±Ç°ÔÚÁíÒ»¸öCPUÉÏÔËÐУ¬ÇëÉÔµÈÒ»»á¡±£¬»òÕß±ê¼ÇΪ¡°ÎÒµ±Ç°²»ÔÚÔËÐС±¡£Èç¹û1ºÅCPUÊ×ÏȽøÈë¸ÃÀý³Ì£¬Ëü¾Í»ñÈ¡¸Ã×ÔÐýËø¡£µ±2ºÅCPUÊÔͼ½øÈëͬһ¸öÀý³Ìʱ£¬¸Ã×ÔÐýËø¸æËßËü×Ô¼ºÒÑΪ1ºÅCPUËù³ÖÓУ¬ÐèµÈµ½1ºÅCPUÊÍ·Å×Ô¼ººó²ÅÄܽøÈë¡£
        spinlock_t my_spinlock = SPIN_LOCK_UNLOCKED;
        unsigned long flags;

        spin_lock (&my_spinlock);
        ...
        critical section
        ...
        spin_unlock (&my_spinlock);

ÖжÏ

    ÉèÏëÎÒÃǵÄÓ²¼þµÄÇý¶¯³ÌÐò»¹ÓÐÒ»¸öÖжϴ¦Àí³ÌÐò¡£¸Ã´¦Àí³ÌÐòÐèÒªÐÞ¸ÄijЩÓÉÎÒÃǵÄÇý¶¯³ÌÐò¶¨ÒåµÄÈ«¾Ö±äÁ¿¡£Õâ»áÔì³É»ìÂÒ¡£ÎÒÃÇÈçºÎ½â¾öÄØ£¿
    ±£»¤Ä³¸öÊý¾Ý½á¹¹£¬Ê¹ËüÃâÔâÖжÏÖ®Ð޸ĵÄ×î³õ·½·¨ÊÇÈ«¾ÖµØ½ûÖ¹Öжϡ£ÔÚÒÑÖªÖ»ÓÐ×Ô¼ºµÄÖжϲŻáÐÞ¸Ä×Ô¼ºµÄÇý¶¯³ÌÐò±äÁ¿Ê±£¬Õâô×öЧÂʺܵ͡£ËùÐÒµÄÊÇ£¬ÎÒÃÇÏÖÔÚÓиüºÃµÄ°ì·¨ÁË¡£ÎÒÃÇÖ»ÊÇÔÚʹÓù²Ïí±äÁ¿ÆÚ¼ä½ûÖ¹Öжϣ¬´ËºóÖØÐÂʹÄÜ¡£
    ʵÏÖÕâÖÖ°ì·¨µÄº¯ÊýÓÐÈý¸ö£º
        disable_irq()
        enable_irq()
        disable_irq_nosync()
    ÕâÈý¸öº¯Êý¶¼È¡Ò»¸öÖжϺÅ×÷Ϊ²ÎÊý¡£×¢Ò⣬½ûÖ¹Ò»¸öÖжϵÄʱ¼äÌ«³¤»áµ¼ÖÂÄÑÒÔ×·×Ù³ÌÐòȱÏÝ£¬¶ªÊ§Êý¾Ý£¬ÉõÖÁ¸ü»µ¡£
    disable_irqº¯ÊýµÄ·Çͬ²½°æ±¾ÔÊÐíËùÖ¸¶¨µÄIRQ´¦Àí³ÌÐò¼ÌÐøÔËÐУ¬Ç°ÌáÊÇËüÒѾ­ÔÚÔËÐУ¬ÆÕͨµÄdisable_irqÔòËùÖ¸¶¨µÄIRQ´¦Àí³ÌÐò²»ÔÚÈçºÎCPUÉÏÔËÐС£
    Èç¹ûÐèÒªÔÚÖжϴ¦Àí³ÌÐòÖÐÐÞ¸Ä×ÔÐýËø£¬ÄǾͲ»ÄÜʹÓÃÆÕͨµÄspin_lock()ºÍspin_unlock()£¬¶øÓ¦¸Ã±£´æÖжÏ״̬¡£Õâ¿Éͨ¹ý¸øÕâÁ½¸öº¯ÊýÌí¼Ó_irqsaveºó׺ºÜÈÝÒ×µØ×öµ½£º
        spinlock_t my_spinlock = SPIN_LOCK_UNLOCKED;
        unsigned long flags;

        spin_lock_irqsave(&my_spinlock, flags);
        ...
        critical section
        ...
        spin_unlock_irqrestore (&my_spinlock, flags);


[Ŀ¼]


ÄÚºËÏß³ÌҳĿ¼µÄ½èÓÃ

    ´´½¨ÄÚºËÏ̵߳Äʱºò£¬ÓÉÓÚÄÚºËÏß³ÌûÓÐÓû§¿Õ¼ä£¬¶øËùÓнø³ÌµÄÄÚºËҳĿ¼¶¼ÊÇÒ»ÑùµÄ£¨£¨Ä³Ð©Çé¿öÏ¿ÉÄÜÓв»Í¬²½µÄÇé¿ö³öÏÖ£¬Ö÷ÒªÊÇΪÁ˼õÇáͬ²½ËùÓнø³ÌÄÚºËҳĿ¼µÄ¿ªÏú£¬¶øÖ»ÊÇÔÚ¸÷¸ö½ø³ÌÒª·ÃÎÊÄں˿ռ䣬Èç¹ûÓв»Í¬²½µÄÇé¿ö£¬È»ºó²Å½øÐÐͬ²½´¦Àí£©£¬ËùÒÔ´´½¨µÄÄÚºËÏ̵߳ÄÄÚºËҳĿ¼×ÜÊǽèÓýø³Ì0µÄÄÚºËҳĿ¼¡£

>>> kernel_threadÒÔ±êÖ¾CLONE_VMµ÷ÓÃcloneϵͳµ÷ÓÃ
/*
* Create a kernel thread
*/
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
long retval, d0;

__asm__ __volatile__(
  "movl %%esp,%%esi\n\t"
  "int $0x80\n\t"  /* Linux/i386 system call */
  "cmpl %%esp,%%esi\n\t" /* child or parent? */
  /* Load the argument into eax, and push it.  That way, it does
   * not matter whether the called function is compiled with
   * -mregparm or not.  */
  "movl %4,%%eax\n\t"
  "pushl %%eax\n\t"
  "call *%5\n\t"  /* call fn */
  "movl %3,%0\n\t" /* exit */
  "int $0x80\n"
  "1:\t"
  :"=&a" (retval), "=&S" (d0)
  :"0" (__NR_clone), "i" (__NR_exit),
   "r" (arg), "r" (fn),
   "b" (flags | CLONE_VM)
  : "memory");
return retval;
}

>>> sys_clone->do_fork->copy_mm£º
static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
{
struct mm_struct * mm, *oldmm;
int retval;

¡£¡£¡£¡£¡£¡£¡£¡£

tsk->mm = NULL;
tsk->active_mm = NULL;

/*
  * Are we cloning a kernel thread?
  *
  * We need to steal a active VM for that..
  */
>>> Èç¹ûÊÇÄÚºËÏ̵߳Ä×ÓỊ̈߳¨mm=NULL£©£¬ÔòÖ±½ÓÍ˳ö£¬´ËʱÄÚºËÏß³ÌmmºÍactive_mm¾ùΪΪNULL
oldmm = current->mm;
if (!oldmm)
  return 0;

>>> ÄÚºËỊ̈߳¬Ö»ÊÇÔö¼Óµ±Ç°½ø³ÌµÄÐéÄâ¿Õ¼äµÄÒýÓüÆÊý
if (clone_flags & CLONE_VM) {
  atomic_inc(&oldmm->mm_users);
  mm = oldmm;
  goto good_mm;
}

¡£¡£¡£¡£¡£¡£¡£¡£¡£¡£

good_mm:
>>> ÄÚºËÏ̵߳ÄmmºÍactive_mmÖ¸Ïòµ±Ç°½ø³ÌµÄmm_struct½á¹¹
tsk->mm = mm;
tsk->active_mm = mm;
return 0;

¡£¡£¡£¡£¡£¡£¡£
}

È»ºóÄÚºËÏß³ÌÒ»°ãµ÷ÓÃdaemonizeÀ´ÊͷŶÔÓû§¿Õ¼äµÄÒýÓãº
>>> daemonize->exit_mm->_exit_mm£º
/*
* Turn us into a lazy TLB process if we
* aren't already..
*/
static inline void __exit_mm(struct task_struct * tsk)
{
struct mm_struct * mm = tsk->mm;

mm_release();
if (mm) {
  atomic_inc(&mm->mm_count);
  if (mm != tsk->active_mm) BUG();
  /* more a memory barrier than a real lock */
  task_lock(tsk);
>>> ÊÍ·ÅÓû§ÐéÄâ¿Õ¼äµÄÊý¾Ý½á¹¹
  tsk->mm = NULL;
  task_unlock(tsk);
  enter_lazy_tlb(mm, current, smp_processor_id());

>>> µÝ¼õmmµÄÒýÓüÆÊý²¢ÊÇ·ñΪ0£¬ÊÇÔòÊÍ·ÅmmËù´ú±íµÄÓ³Éä
  mmput(mm);
}
}

asmlinkage void schedule(void)
{
¡£¡£¡£¡£¡£¡£¡£¡£¡£
if (!current->active_mm) BUG();

¡£¡£¡£¡£¡£¡£¡£¡£¡£

prepare_to_switch();
{
  struct mm_struct *mm = next->mm;
  struct mm_struct *oldmm = prev->active_mm;
>>> mm = NULL£¬Ñ¡ÖеÄΪÄÚºËÏß³Ì
  if (!mm) {
>>> ¶ÔÄÚºËÏß³Ì,active_mm = NULL£¬·ñÔòÒ»¶¨Êdzö´íÁË
   if (next->active_mm) BUG();
>>> Ñ¡ÖеÄÄÚºËÏß³Ìactive_mm½èÓÃÀϽø³ÌµÄactive_mm
   next->active_mm = oldmm;
   atomic_inc(&oldmm->mm_count);
   enter_lazy_tlb(oldmm, next, this_cpu);
  } else {
>>> mm != NULL Ñ¡ÖеÄΪÓû§½ø³Ì£¬active_mm±ØÐëÓëmmÏàµÈ£¬·ñÔòÒ»¶¨Êdzö´íÁË
   if (next->active_mm != mm) BUG();
   switch_mm(oldmm, mm, next, this_cpu);
  }

>>> prev = NULL £¬Çл»³öÈ¥µÄÊÇÄÚºËÏß³Ì
  if (!prev->mm) {
>>> ÉèÖÃÆä active_mm = NULL ¡£
   prev->active_mm = NULL;
   mmdrop(oldmm);
  }
}

}

¶ÔÄÚºËÏ̵߳ÄÐéÄâ¿Õ¼ä×ܽáһϣº
£±¡¢´´½¨µÄʱºò£º
¸¸½ø³ÌÊÇÓû§½ø³Ì£¬ÔòmmºÍactive_mm¾ù¹²Ïí¸¸½ø³ÌµÄ£¬È»ºóÄÚºËÏß³ÌÒ»°ãµ÷ÓÃdaemonizeÊÊÍ·Åmm
¸¸½ø³ÌÊÇÄÚºËỊ̈߳¬ÔòmmºÍactive_mm¾ùΪNULL
×ÜÖ®£¬ÄÚºËÏ̵߳Ämm = NULL£»½ø³Ìµ÷¶ÈµÄʱºòÒÔ´ËΪÒÀ¾ÝÅжÏÊÇÓû§½ø³Ì»¹ÊÇÄÚºËÏ̡߳£

£²¡¢½ø³Ìµ÷¶ÈµÄʱºò
Èç¹ûÇл»½øÀ´µÄÊÇÄÚºËỊ̈߳¬ÔòÖÃactive_mmΪÇл»³öÈ¥µÄ½ø³ÌµÄactive_mm£»
Èç¹ûÇл»³öÈ¥µÄÊÇÄÚºËỊ̈߳¬ÔòÖÃactive_mmΪNULL¡£

[Ŀ¼]


´úÂë·ÖÎö

    LINUXϵͳÊÇ·Öʱ¶àÓû§ÏµÍ³, ËüÓÐ¶à½ø³ÌϵͳµÄÌØµã£¬CPU°´Ê±¼äƬ·ÖÅ䏸¸÷¸öÓû§Ê¹ÓÃ, ¶øÔÚʵÖÊÉÏÓ¦¸Ã˵CPU°´Ê±¼äƬ·ÖÅ䏸¸÷¸ö½ø³ÌʹÓÃ, ÿ¸ö½ø³Ì¶¼ÓÐ×Ô¼ºµÄÔËÐл·¾³ÒÔʹµÃÔÚCPU×ö½ø³ÌÇл»Ê±±£´æ¸Ã½ø³ÌÒѼÆËãÁËÒ»°ëµÄ״̬¡£

½ø³ÌµÄÇл»°üÀ¨Èý¸ö²ã´Î:

    ·Óû§Êý¾ÝµÄ±£´æ: °üÀ¨ÕýÎĶÎ(TEXT), Êý¾Ý¶Î(DATA,BSS), Õ»¶Î(STACK), ¹²ÏíÄÚ´æ¶Î(SHARED MEMORY)µÄ±£´æ¡£
    ·¼Ä´æÆ÷Êý¾ÝµÄ±£´æ: °üÀ¨PC(program counter,Ö¸ÏòÏÂÒ»ÌõÒªÖ´ÐеÄÖ¸ÁîµÄµØÖ·),   PSW(processor status word,´¦Àí»ú״̬×Ö), SP(stack pointer,Õ»Ö¸Õë), PCBP(pointer of process control block,½ø³Ì¿ØÖÆ¿éÖ¸Õë), FP(frame pointer,Ö¸ÏòÕ»ÖÐÒ»¸öº¯ÊýµÄlocal ±äÁ¿µÄÊ×µØÖ·), AP(augument pointer,Ö¸ÏòÕ»Öк¯Êýµ÷ÓõÄʵ²ÎλÖÃ), ISP(interrupt stack pointer,ÖжÏÕ»Ö¸Õë), ÒÔ¼°ÆäËûµÄͨÓüĴæÆ÷µÈ¡£
    ·ÏµÍ³²ã´ÎµÄ±£´æ: °üÀ¨proc,u,ÐéÄâ´æ´¢¿Õ¼ä¹ÜÀí±í¸ñ,Öжϴ¦ÀíÕ»¡£ÒÔ±ãÓڸýø³ÌÔÙÒ»´ÎµÃµ½CPUʱ¼äƬʱÄÜÕý³£ÔËÐÐÏÂÈ¥¡£

    ¶à½ø³ÌϵͳµÄһЩͻ³öµÄÌØµã:
²¢Ðл¯
   Ò»¼þ¸´ÔÓµÄʼþÊÇ¿ÉÒÔ·Ö½â³ÉÈô¸É¸ö¼òµ¥Ê¼þÀ´½â¾öµÄ, ÕâÔÚ³ÌÐòÔ±µÄ´óÄÔÖÐÔç¾ÍÐγÉÁËÕâÖÖ¸ÅÄî, Ê×ÏȽ«ÎÊÌâ·Ö½â³ÉÒ»¸ö¸öСÎÊÌâ, ½«Ð¡ÎÊÌâÔÙϸ·Ö, ×îºóÔÚÒ»¸öºÏÊʵĹæÄ£ÉÏ×ö³ÉÒ»¸öº¯Êý¡£ ÔÚÈí¼þ¹¤³ÌÖÐÒ²ÊÇÕâô˵µÄ¡£Èç¹ûÎÒÃÇÒÔͼµÄ·½Ê½À´Ë¼¿¼, һЩСÎÊÌâµÄ¼ÆËãÊÇ¿ÉÒÔ»¥²»¸ÉÈŵÄ, ¿ÉÒÔͬʱ´¦Àí, ¶øÔڹؼüµãÔòÐèҪͳһÔÚÒ»¸öµØ·½À´´¦Àí, ÕâÑù³ÌÐòµÄÔËÐоÍÊDz¢ÐеÄ, ÖÁÉÙ´ÓÈ˵Äʱ¼ä¹ÛÄîÉÏÀ´ËµÊÇÕâÑùµÄ¡£ ¶øÃ¿¸öСÎÊÌâµÄ¼ÆËãÓÖÊǽϼòµ¥µÄ¡£
¼òµ¥ÓÐÐò
   ÕâÑùµÄ³ÌÐò¶Ô³ÌÐòÔ±À´Ëµ²»ÑÇÓÚ¹ÜÀíÒ»°àÈË, ³ÌÐòԱΪÿ¸ö½ø³ÌÉè¼ÆºÃÏàÓ¦µÄ¹¦ÄÜ, ²¢Í¨¹ýÒ»¶¨µÄͨѶ»úÖÆ½«ËüÃÇÓлúµØ½áºÏÔÚÒ»Æð, ¶Ôÿ¸ö½ø³ÌµÄÉè¼ÆÊǼòµ¥µÄ, Ö»ÔÚ×ܿز¿·ÖСÐÄÓ¦¸¶(ÆäʵҲÊÇÂù¼òµ¥µÄ), ¾Í¿ÉÍê³ÉÕû¸ö³ÌÐòµÄÊ©¹¤¡£
»¥²»¸ÉÈÅ
   Õâ¸öÌØµãÊDzÙ×÷ϵͳµÄÌØµã, ¸÷¸ö½ø³ÌÊǶÀÁ¢µÄ, ²»»á´®Î»¡£
ÊÂÎñ»¯
   ±ÈÈçÔÚÒ»¸öÊý¾Ýµç»°²éѯϵͳÖÐ, ½«³ÌÐòÉè¼Æ³ÉÒ»¸ö½ø³ÌÖ»´¦ÀíÒ»´Î²éѯ¼´¿É, ¼´Íê³ÉÒ»¸öÊÂÎñ¡£µ±µç»°²éѯ¿ªÊ¼Ê±, ²úÉúÕâÑùÒ»¸ö½ø³Ì¶Ô¸¶Õâ´Î²éѯ; ÁíÒ»¸öµç»°½øÀ´Ê±, Ö÷¿Ø³ÌÐòÓÖ²úÉúÒ»¸öÕâÑùµÄ½ø³Ì¶Ô¸¶, ÿ¸ö½ø³ÌÍê³É²éѯÈÎÎñºóÏûʧ. ÕâÑùµÄ±à³Ì¶à¼òµ¥, Ö»Òª×öÒ»´Î²éѯµÄ³ÌÐò¾Í¿ÉÒÔÁË¡£

   LinuxÊÇÒ»¸ö¶à½ø³ÌµÄ²Ù×÷ϵͳ£¬½ø³ÌÊÇ·ÖÀëµÄÈÎÎñ£¬ÓµÓи÷×ÔµÄȨÀûºÍÔðÈΡ£Èç¹ûÒ»¸ö½ø³Ì±ÀÀ££¬Ëü²»Ó¦¸ÃÈÃϵͳµÄÁíÒ»¸ö½ø³Ì±ÀÀ£¡£Ã¿Ò»¸ö¶ÀÁ¢µÄ½ø³ÌÔËÐÐÔÚ×Ô¼ºµÄÐéÄâµØÖ·¿Õ¼ä£¬³ýÁËͨ¹ý°²È«µÄºËÐĹÜÀíµÄ»úÖÆÖ®ÍâÎÞ·¨Ó°ÏìÆäËûµÄ½ø³Ì¡£
   ÔÚÒ»¸ö½ø³ÌµÄÉúÃüÖÜÆÚÖУ¬½ø³Ì»áʹÓÃÐí¶àϵͳ×ÊÔ´¡£±ÈÈçÀûÓÃϵͳµÄCPUÖ´ÐÐËüµÄÖ¸ÁÓÃϵͳµÄÎïÀíÄÚ´æÀ´´æ´¢ËüºÍËüµÄÊý¾Ý¡£Ëü»á´ò¿ªºÍʹÓÃÎļþϵͳÖеÄÎļþ£¬»áÖ±½Ó»òÕß¼ä½ÓʹÓÃϵͳµÄÎïÀíÉ豸¡£Èç¹ûÒ»¸ö½ø³Ì¶ÀÕ¼ÁËϵͳµÄ´ó²¿·ÖÎïÀíÄÚ´æºÍCPU£¬¶ÔÓÚÆäËû½ø³Ì¾ÍÊDz»¹«Æ½µÄ¡£ËùÒÔLinux±ØÐë¸ú×Ù½ø³Ì±¾ÉíºÍËüʹÓõÄϵͳ×ÊÔ´ÒԱ㹫ƽµØ¹ÜÀíϵͳÖеĽø³Ì¡£
   ϵͳ×¹óµÄ×ÊÔ´¾ÍÊÇCPU¡£Í¨³£ÏµÍ³Ö»ÓÐÒ»¸öCPU¡£Linux×÷Ϊһ¸ö¶à½ø³ÌµÄ²Ù×÷ϵͳ£¬ËüµÄÄ¿±ê¾ÍÊÇÈýø³ÌÔÚϵͳµÄCPUÉÏÔËÐУ¬³ä·ÖÀûÓÃCPU¡£Èç¹û½ø³ÌÊý¶àÓÚCPU£¨Ò»°ãÇé¿ö¶¼ÊÇÕâÑù£©£¬ÆäËûµÄ½ø³Ì¾Í±ØÐëµÈµ½CPU±»ÊͷŲÅÄÜÔËÐС£¶à½ø³ÌµÄ˼Ïë¾ÍÊÇ£ºÒ»¸ö½ø³ÌÒ»Ö±ÔËÐУ¬Ö±µ½Ëü±ØÐëµÈ´ý£¬Í¨³£ÊǵȴýһЩϵͳ×ÊÔ´£¬µÈÓµÓÐÁË×ÊÔ´£¬Ëü²Å¿ÉÒÔ¼ÌÐøÔËÐС£ÔÚÒ»¸öµ¥½ø³ÌµÄϵͳÖУ¬±ÈÈçDOS£¬CPU±»¼òµ¥µØÉèΪ¿ÕÏУ¬ÕâÑùµÈ´ý×ÊÔ´µÄʱ¼ä¾Í»á±»ÀË·Ñ¡£¶øÔÚÒ»¸ö¶à½ø³ÌµÄϵͳÖУ¬Í¬Ò»Ê±¿ÌÐí¶à½ø³ÌÔÚÄÚ´æÖУ¬µ±Ò»¸ö½ø³Ì±ØÐëµÈ´ýʱ£¬²Ù×÷ϵͳ½«CPU´ÓÕâ¸ö½ø³ÌÇл»µ½ÁíÒ»¸ö¸üÐèÒªµÄ½ø³Ì¡£
   ÎÒÃÇ×é·ÖÎöµÄÊÇLinux½ø³ÌµÄ״̬ת»»ÒÔ¼°±ê־λµÄ×÷Óã¬ËüûÓоßÌå¶ÔӦij¸öϵͳµ÷Ó㬶øÊÇ·Ö²¼ÔÚ¸÷¸öϵͳµ÷ÓÃÖС£ËùÒÔÎÒÃÇÏêϸ¶ø¹ã·ºµØ·ÖÎöÁË´óÁ¿µÄÔ­Â룬¶Ô½ø³Ì״̬ת»»µÄÔ­Òò¡¢·½Ê½ºÍ½á¹û½øÐÐÁË·ÖÎö£¬´óÖÂ×ܽáÁËÕû¸öLinuxϵͳ¶Ô½ø³Ì״̬¹ÜÀíµÄʵÏÖ»úÖÆ¡£

   LinuxÖУ¬Ã¿¸ö½ø³ÌÓÃÒ»¸ötask_structµÄÊý¾Ý½á¹¹À´±íʾ£¬ÓÃÀ´¹ÜÀíϵͳÖеĽø³Ì¡£TaskÏòÁ¿±íÊÇÖ¸ÏòϵͳÖÐÿһ¸ötask_structÊý¾Ý½á¹¹µÄÖ¸ÕëµÄÊý×é¡£ÕâÒâζ×ÅϵͳÖеÄ×î´ó½ø³ÌÊýÊܵ½TaskÏòÁ¿±íµÄÏÞÖÆ£¬È±Ê¡ÊÇ512¡£Õâ¸ö±íÈÃLinux¿ÉÒԲ鵽ϵͳÖеÄËùÓеĽø³Ì¡£²Ù×÷ϵͳ³õʼ»¯ºó£¬½¨Á¢Á˵ÚÒ»¸ötask_structÊý¾Ý½á¹¹INIT_TASK¡£µ±ÐµĽø³Ì´´½¨Ê±£¬´ÓϵͳÄÚ´æÖзÖÅäÒ»¸öеÄtask_struct£¬²¢Ôö¼Óµ½TaskÏòÁ¿±íÖС£ÎªÁ˸üÈÝÒײéÕÒ£¬ÓÃcurrentÖ¸ÕëÖ¸Ïòµ±Ç°ÔËÐеĽø³Ì¡£

   task_struct½á¹¹ÖÐÓйØÓÚ½ø³Ìµ÷¶ÈµÄÁ½¸öÖØÒªµÄÊý¾ÝÏ
   struct task_struct {
       ¡­¡­¡­¡­.
       volatile  long  state; /* -1 unrunnable , 0 runnable , >0 stopped */
       unsigned  long  flags; /* per process flags, defined below */
       ¡­¡­¡­¡­.
     }£»
   ÿ¸öÔÚTaskÏòÁ¿±íÖеǼǵĽø³Ì¶¼ÓÐÏàÓ¦µÄ½ø³Ì״̬ºÍ½ø³Ì±êÖ¾£¬ÊǽøÐнø³Ìµ÷¶ÈµÄÖØÒªÒÀ¾Ý¡£½ø³ÌÔÚÖ´ÐÐÁËÏàÓ¦µÄ½ø³Ìµ÷¶È²Ù×÷ºó£¬»áÓÉÓÚijЩԭÒò¸Ä±ä×ÔÉíµÄ״̬ºÍ±êÖ¾£¬Ò²¾ÍÊǸıästateºÍflagsÕâÁ½¸öÊý¾ÝÏî¡£½ø³ÌµÄ״̬²»Í¬¡¢±ê־λ²»Í¬¶ÔÓ¦Á˽ø³Ì¿ÉÒÔÖ´Ðв»Í¬²Ù×÷¡£ÔÚLinux2.2.8°æ±¾µÄsched.hÖж¨ÒåÁËÁùÖÖ״̬£¬Ê®ÈýÖÖ±êÖ¾¡£
//½ø³Ì״̬
#define TASK_RUNNING                0
#define TASK_INTERRUPTIBLE        1
#define TASK_UNINTERRUPTIBLE        2
#define TASK_ZOMBIE                4
#define TASK_STOPPED                8
#define TASK_SWAPPING                16

ËüÃǵĺ¬Òå·Ö±ðÊÇ£º

TASK_RUNNING£ºÕýÔÚÔËÐеĽø³Ì£¨ÊÇϵͳµÄµ±Ç°½ø³Ì£©»ò×¼±¸ÔËÐеĽø³Ì£¨ÔÚRunning¶ÓÁÐÖУ¬µÈ´ý±»°²Åŵ½ÏµÍ³µÄCPU£©¡£´¦ÓÚ¸Ã״̬µÄ½ø³Ìʵ¼Ê²ÎÓëÁ˽ø³Ìµ÷¶È¡£
TASK_INTERRUPTIBLE£º´¦Óڵȴý¶ÓÁÐÖеĽø³Ì£¬´ý×ÊÔ´ÓÐЧʱ»½ÐÑ£¬Ò²¿ÉÓÉÆäËü½ø³Ì±»ÐźÅÖжϡ¢»½ÐѺó½øÈë¾ÍÐ÷״̬¡£
TASK_UNINTERRUPTIBLE£º´¦Óڵȴý¶ÓÁÐÖеĽø³Ì£¬Ö±½ÓµÈ´ýÓ²¼þÌõ¼þ£¬´ý×ÊÔ´ÓÐЧʱ»½ÐÑ£¬²»¿ÉÓÉÆäËü½ø³Ìͨ¹ýÐźÅÖжϡ¢»½ÐÑ¡£
TASK_ZOMBIE£ºÖÕÖ¹µÄ½ø³Ì£¬Êǽø³Ì½áÊøÔËÐÐǰµÄÒ»¸ö¹ý¶È״̬£¨½©ËÀ״̬£©¡£ËäÈ»´ËʱÒѾ­ÊÍ·ÅÁËÄÚ´æ¡¢ÎļþµÈ×ÊÔ´£¬µ«ÊÇÔÚTaskÏòÁ¿±íÖÐÈÔÓÐÒ»¸ötask_structÊý¾Ý½á¹¹Ïî¡£Ëü²»½øÐÐÈκε÷¶È»ò״̬ת»»£¬µÈ´ý¸¸½ø³Ì½«Ëü³¹µ×ÊÍ·Å¡£
TASK_STOPPED£º½ø³Ì±»ÔÝÍ££¬Í¨¹ýÆäËü½ø³ÌµÄÐźŲÅÄÜ»½ÐÑ¡£ÕýÔÚµ÷ÊԵĽø³Ì¿ÉÒÔÔÚ¸Ãֹͣ״̬¡£
TASK_SWAPPING£º½ø³ÌÒ³Ãæ±»¶Ò»»³öÄÚ´æµÄ½ø³Ì¡£Õâ¸ö״̬»ù±¾ÉÏûÓÐÓõ½£¬Ö»ÓÐÔÚsched.cµÄcount_active_tasks£¨£©º¯ÊýÖÐÅжϴ¦ÓÚ¸ÃÖÖ״̬µÄ½ø³ÌÒ²ÊôÓÚactiveµÄ½ø³Ì£¬µ«Ã»ÓжԸÃ״̬µÄ¸³Öµ¡£

//½ø³Ì±ê־λ£º
#define PF_ALIGNWARN        0x00000001
#define PF_STARTING        0x00000002
#define PF_EXITING        0x00000004
#define PF_PTRACED        0x00000010
#define PF_TRACESYS        0x00000020
#define PF_FORKNOEXEC        0x00000040
#define PF_SUPERPRIV        0x00000100
#define PF_DUMPCORE        0x00000200
#define PF_SIGNALED        0x00000400
#define PF_MEMALLOC        0x00000800
#define PF_VFORK            0x00001000
#define PF_USEDFPU        0x00100000
#define PF_DTRACE        0x00200000

ÆäÖÐPF_STARTINGûÓÐÓõ½¡£
PF_MEMEALLOCºÍPF_VFORKÕâÁ½¸ö±ê־λÊÇа汾ÖвÅÓеġ£

¸÷¸ö±ê־λµÄ´ú±í×Ų»Í¬º¬Ò壬¶ÔÓ¦×Ų»Í¬µ÷Óãº

PF_ALIGNWARN    ±êÖ¾´òÓ¡¡°¶ÔÆë¡±¾¯¸æÐÅÏ¢£¬Ö»ÓÐÔÚ486»úÆ÷ÉÏʵÏÖ
PF_STARTING      ½ø³ÌÕý±»´´½¨
PF_EXITING        ±êÖ¾½ø³Ì¿ªÊ¼¹Ø±Õ¡£
ÔÚdo_exit()ʱÖÃλ¡£
    current->flags |= PF_EXITING
ÓÃÓÚÅжÏÊÇ·ñÓÐЧ½ø³Ì¡£
ÔÚnlmclnt_proc()(ÔÚfs\lockd\clntproc.c)£¬Èç¹ûcurrent_flagΪPF_EXITING£¬Ôò½ø³ÌÓÉÓÚÕýÔÚÍ˳öÇå³ýËùÓеÄËø£¬½«Ö´ÐÐÒì²½RPC µ÷Óá£
PF_PTRACED      ½ø³Ì±»¸ú×Ù±êÖ¾£¬
ÔÚdo_fork()ʱÇåλ¡£
    p->flags &= ~PF_PTRACED
µ±ptrace(0)±»µ÷ÓÃʱÖÃ룬ÔÚ½ø³ÌÊÍ·ÅǰҪÇåµô¡£
    current->flags |= PF_PTRACED
ÔÚsys_trace()ÖÐÅжÏ
Èç¹ûrequestΪPTRACE_TRACEME£¬ÈçÊÇÔò½«current_flagÖÃΪPF_PTRACED£»
Èç¹ûrequestΪPTRACE_ATTACH£¬Ôò½«child_flagÖÃΪPF_PTRACED£¬¸øchild·¢Ò»¸öSIGSTOPÐźÅ;
Èç¹ûrequestΪPTRACE_DETACH £¬Ôò½«childÇå³ýPF_PTRACED¡£
ÔÚsyscall_trace()ÖÐÅжÏcurrent_flagÈç¹ûΪPF_TRACEDºÍPF_TRACESYS,ÔòcurrentÇ¿ÐÐÍ˳öʱµÄ³ö´í´úÂëÖÃΪSIGTRAP²¢½«×´Ì¬ÖÃΪSTOPPED¡£
PF_TRACESYS       ÕýÔÚ¸ú×Ùϵͳµ÷Óá£
do_fork()ʱÇå룬ÔÚ½ø³ÌÊÍ·ÅǰҪÇåµô¡£
ÔÚsys_trace()ÖÐÅжÏrequestÈç¹ûΪPTRACE_SYSCALL£¬Ôò½«child->flags ÖÃΪ PF_TRACESYS£»ÈçΪPTRACE_SYSCALL£¬Ôò½«child->flags Çå³ý PF_TRACESYS£»È»ºó»½ÐÑchild¡£Èç¹ûrequestΪPTRACE_SINGLESTEP£¨¼´µ¥²½¸ú×Ù£©£¬Ôò½«child_flagÇå³ýPF_TRACESYS,»½ÐÑchild¡£
PF_FORKNOEXEC    ½ø³Ì¸Õ´´½¨£¬µ«»¹Ã»Ö´ÐС£
ÔÚdo_fork()ʱÖÃλ¡£
    p->flags |=  PF_FORKNOEXEC
ÔÚµ÷Èë¸ñʽÎļþʱÇåλ¡£
    p->flags &= ~ PF_FORKNOEXEC
PF_SUPERPRIV       ³¬¼¶Óû§ÌØÈ¨±êÖ¾¡£
    Èç¹ûÊdz¬¼¶Óû§½ø³ÌÔòÖÃ룬Óû§ÌØÈ¨ÉèΪ³¬¼¶Óû§£¬ÈçÊdz¬¼¶Óû§£¬ÔÚͳ¼ÆÊ±ÖÃͳ¼Æ±êÖ¾(accounting flag)ΪASU¡£
PF_DUMPCORE       ±êÖ¾½ø³ÌÊÇ·ñÇå¿ÕcoreÎļþ¡£
CoreÎļþÓÉgdb½øÐйÜÀí£¬¸øÓû§ÌṩÓÐÓÃÐÅÏ¢£¬ÀýÈç²é¿´¸¡µã¼Ä´æÆ÷µÄÄÚÈݱȽÏÀ§ÄÑ£¬ÊÂʵÉÏÎÒÃÇ¿ÉÒÔ´ÓÄÚºËÎļþÀïµÄÓû§½á¹¹Öеõ½
  CoreÎļþ¸ñʽÈçÏÂͼ£º
UPAGE
DATA
STACK
              Core Îļþ½á¹¹
       UPAGEÊǰüº¬Óû§½á¹¹µÄÒ»¸öÒ³Ãæ£¬¸æËßgdbÎļþÖÐÏÖÓÐÄÚÈÝËùÓмĴæÆ÷Ò²ÔÚ           UPAGEÖУ¬Í¨³£Ö»ÓÐÒ»Ò³¡£DATA´æ·ÅÊý¾ÝÇø¡£STACK¶ÑÕ»Çø
   ×îСCoreÎļþ³¤¶ÈΪÈýÒ³£¨12288×Ö½Ú£©
ÔÚtask_structÖж¨ÒåÒ»¸ödumpable±äÁ¿£¬µ±dumpable==1ʱ±íʾ½ø³Ì¿ÉÒÔÇå¿ÕcoreÎļþ£¨¼´½«coreÎļþ·ÅÈë»ØÊÕÕ¾£©£¬µÈÓÚ0ʱ±íʾ¸Ã½ø³Ì²»ÄÜÇå¿ÕcoreÎļþ£¨¼´coreÎļþÒÔ·ÅÔÚ»ØÊÕÕ¾ÖУ¬²»¿ÉÔٷŵ½»ØÊÕÕ¾ÖУ©£¬´Ë±äÁ¿³õֵΪ1¡£
ÀýÈçÔÚµ÷ÓÃdo_aout_core_dump()ʱÅжÏcurrent->dumpableÊÇ·ñµÈÓÚ1£¨¼´Åжϸýø³ÌÊÇ·ñÄܽ«coreÎļþ·ÅÈë»ØÊÕÕ¾£©£¬Èç¹ûµÈÓÚ1Ôò½«¸Ã±äÁ¿ÖÃΪ0£¬ÔÚµ±Ç°Ä¿Â¼Ï½¨Á¢Ò»¸öcore dump image ,ÔÚÇå¿ÕÓû§½á¹¹Ç°£¬ÓÉgdbËã³öÊý¾Ý¶ÎºÍ¶ÑÕ»¶ÎµÄλÖúÍʹÓõÄÐ鵨ַ£¬Óû§Êý¾ÝÇøºÍ¶ÑÕ»ÇøÔÚÇå¿Õǰ½«ÏàÓ¦ÄÚÈÝдÈëcore dump£¬½«PF_DUMPCOREÖÃ룬Çå¿ÕÊý¾ÝÇøºÍ¶ÑÕ»Çø¡£
Ö»ÓÐÔÚaout_core_dump()ÄÚµ÷ÓÃdo_aout_core_dump(),¶øÃ»Óеط½µ÷ÓÃaout_core_dump()¡£¶ÔÆäËüÎļþ¸ñʽҲÊÇÀàËÆ¡£
9¡¢ PF_SIGNALED       ±êÖ¾½ø³Ì±»ÐźÅɱ³ö¡£
ÔÚdo_signal()ÖÐÅжÏÐźţ¬Èç¹ûcurrentÊÕµ½ÐźÅΪSIGHUP, SIGINT, SIGIOT, SIGKILL, SIGPIPE, SIGTERM, SIGALRM, SIGSTKFLT, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGIO, SIGPOLL, SIGLOST, SIGPWR£¬ÔòÖ´ÐÐlock_kernel(),½«ÐźżÓÈëcurrentµÄÐźŶÓÁУ¬½«current->flagÖÃΪPF_SIGNALED,È»ºóÖ´ÐÐdo_exit()
PF_USEDFPU        ±êÖ¾¸Ã½ø³ÌʹÓÃFPU£¬´Ë±êÖ¾Ö»ÔÚSMPʱʹÓá£
ÔÚtask_structÖÐÓÐÒ»±äÁ¿used_math£¬½ø³ÌÊÇ·ñʹÓÃFPU¡£
ÔÚCPU´ÓprevÇл»µ½nextʱ£¬Èç¹ûprevʹÓÃFPUÔòprevµÄflagÇå³ýPF_USEDFPU¡£
    prev->flags&=~PF_USEDFPU
ÔÚflush_thread()(arch\i386\kernel\process.c)¡¢restore_i387_hard()¡¢save_i387_hard()(arch\i386\kernel\signal.c)ÖУ¬Èç¹ûÊÇSMP·½Ê½£¬ÇÒʹÓÃFPUÔòstts()£¬·ñÔòÇå³ýPF_USEDFPU¡£
    current->flags &= ~PF_USEDFPU
ÔÚsys_trace()ÖÐÈç¹ûrequestΪPTRACE_SETFPREGS£¬Ôò½«childµÄused_mathÖÃΪ1£¬½«child_flagÇå³ýPF_USEDFPU¡£
    child->flags &= ~PF_USEDFPU
ÔÚSMP·½Ê½Ï½øÐиú×Ùʱ£¬ÅжÏÊÇ·ñʹÓÃFPU¡£
ÔÚ¸ú×Ùʱ³öÏÖÊýѧ´íÎóʱÇåλ¡£
    current->flags &= ~PF_USEDFPU
PF_DTRACE          ½ø³ÌÑÓÆÚ¸ú×Ù±êÖ¾£¬Ö»ÔÚm68kÏÂʹÓá£
¸ú×ÙÒ»¸ötrappingÖ¸ÁîʱÖÃλ¡£
    current->flags |= PF_DTRACE
PF_ONSIGSTK        ±êÖ¾½ø³ÌÊÇ·ñ¹¤×÷ÔÚÐźÅÕ»£¬Ö»ÔÚm68k·½Ê½ÏÂʹÓá£
liunx 2.1.19°æ±¾ÖÐʹÓô˱ê־룬¶ø2.2.8°æ±¾Öв»Ê¹Óá£
ÔÚ´¦ÀíÐźŽ¨Á¢frameʱÈç¹ûsigaction±ê־ΪONSTACK£¬Ôò½«current->flagÖÃΪPF_ONSIGSTK¡£
PF_MEMALLOC      ½ø³Ì·ÖÅäÄÚ´æ±êÖ¾¡£
linux 2.2.8°æ±¾ÖÐʹÓô˱ê־λ¡£
ÔÚkpiod()ºÍkwpad()ÖÐÖÃλ¡£
    tsk->flags |= PF_MEMALLOC
PF_VFORK           linux 2.2.8°æ±¾ÖÐʹÓô˱ê־λ¡£
ÔÚcopy_flags(unsigned long clone_flags, struct task_struct *p)£¬Èç¹ûclone_flagsΪCLONE_VFORK£¬Ôò½«pµÄflagsÖÃΪPF_VFORK¡£
ÔÚmm_release£¨£©Öн«current ->flagsÇå³ýPF_VFORK¡£
    tsk->flags &= ~PF_VFORK
    ¾ßÌåµÄ·ÖÎöÓÉÎÒ×éµÄÁíÍâͬѧ½øÐС£

LinuxµÄ¸÷½ø³ÌÖ®¼äµÄ״̬ת»»µÄϵͳµ÷ÓÃ
ÎÒ½«²ÎÓëLinuxµÄ¸÷½ø³ÌÖ®¼äµÄ״̬ת»»µÄϵͳµ÷ÓÃ×ܽá³ÉÒ»ÕÅÁ÷³Ìͼ£º

½ø³ÌµÄ´´½¨£ºTASK_RUNNING

µÚÒ»¸ö½ø³ÌÔÚϵͳÆô¶¯Ê±´´½¨£¬µ±ÏµÍ³Æô¶¯µÄʱºòËüÔËÐÐÔÚºËÐÄ̬£¬Õâʱ£¬Ö»ÓÐÒ»¸ö½ø³Ì£º³õʼ»¯½ø³Ì¡£ÏóËùÓÐÆäËû½ø³ÌÒ»Ñù£¬³õʼ½ø³ÌÓÐÒ»×éÓöÑÕ»¡¢¼Ä´æÆ÷µÈµÈ±íʾµÄ»úÆ÷״̬¡£µ±ÏµÍ³ÖÐµÄÆäËû½ø³Ì´´½¨ºÍÔËÐеÄʱºòÕâЩÐÅÏ¢´æÔÚ³õʼ½ø³ÌµÄtask_structÊý¾Ý½á¹¹ÖС£ÔÚϵͳ³õʼ»¯½áÊøµÄʱºò£¬³õʼ½ø³ÌÆô¶¯Ò»¸öºËÐĽø³Ì£¨½Ð×öinit£©È»ºóÖ´ÐпÕÏÐÑ­»·£¬Ê²Ã´Ò²²»×ö¡£µ±Ã»ÓÐʲô¿ÉÒÔ×öµÄʱºò£¬µ÷¶È³ÌÐò»áÔËÐÐÕâ¸ö¿ÕÏеĽø³Ì¡£Õâ¸ö¿ÕÏнø³ÌµÄtask_structÊÇΨһһ¸ö²»ÊǶ¯Ì¬·ÖÅä¶øÊÇÔÚºËÐÄÁ¬½ÓµÄʱºò¾²Ì¬¶¨ÒåµÄ£¬ÎªÁ˲»ÖÁÓÚ»ìÏý£¬½Ð×öinit_task¡£
   ϵͳµ÷ÓÃsys_fork ºÍsys_clone¶¼µ÷Óú¯Êýdo_fork£¨£©£¨ÔÚkernel/fork.Öж¨Ò壩¡£
   ½ø³ÌÓÉdo_fork()º¯Êý´´½¨£¬ÏÈÉêÇë¿Õ¼ä£¬ÉêÇëºËÐĶÑÕ»£»È»ºóÔÚTaskÏòÁ¿±íÖÐÕÒµ½¿ÕÏÐλÖã»ÔÚ½øÐÐÕýʽ³õʼ»¯ÒÔǰ£¬½«Ð´´½¨µÄ½ø³ÌµÄ״̬¶¼ÖÃΪTASK_UNINTERRUPTIBLE£¬ÒÔÃâ³õʼ»¯¹ý³Ì±»´ò¶Ï£»¿ªÊ¼³õʼ»¯¹¤×÷£¬Èç³õʼ»¯½ø³ÌʱÖÓ¡¢Ðźš¢Ê±¼äµÈÊý¾Ý£»¼Ì³Ð¸¸½ø³ÌµÄ×ÊÔ´£¬ÈçÎļþ¡¢ÐźÅÁ¿¡¢ÄÚ´æµÈ£»Íê³É½ø³Ì³õʼ»¯ºó,Óɸ¸½ø³Ìµ÷ÓÃwake_up_process()º¯Êý½«Æä»½ÐÑ£¬×´Ì¬±äΪTASK_RUNNING£¬¹Òµ½¾ÍÐ÷¶ÓÁÐrun queue£¬·µ»Ø×Ó½ø³ÌµÄpid¡£

//   C:\SRCLNX\KERNEL\FORK.C
int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
{

        Ϊнø³ÌÉêÇëPCB¿Õ¼ä;
        if (ÉêÇë²»µ½)
                ·µ»Ø´íÎó,Í˳ö;
        Ϊнø³ÌÉêÇëºËÐĶÑÕ»;
        if (ºËÐĶÑÕ»ÉêÇë²»µ½)
                ·µ»Ø´íÎó,Í˳ö;
        Ϊнø³ÌÔÚTaskÏòÁ¿±íÖÐÕÒµ½¿ÕÏÐλÖÃ;
/*¸´ÖƸ¸½ø³Ìcurrent PCBÖеÄÐÅÏ¢£¬¼Ì³ÐcurrentµÄ×ÊÔ´*/£»
    p = current;
        ÔÚ½øÐÐÕýʽ³õʼ»¯ÒÔǰ£¬½«Ð´´½¨µÄ½ø³ÌµÄ״̬¶¼ÖÃΪTASK_UNINTERRUPTIBLE£¬ÒÔÃâ³õʼ»¯¹ý³Ì±»´ò¶Ï,²¢ÖÃһЩ±ê־λ.
/*Ϊ·ÀÖ¹Ðźš¢¶¨Ê±ÖжÏÎó»½ÐÑδ´´½¨Íê±ÏµÄ½ø                                       ³Ì£¬½«×Ó½ø³ÌµÄ״̬Éè³É²»¿ÉÖжϵÄ*/
        p->state = TASK_UNINTERRUPTIBLE;
/*¸ú×Ù״̬ºÍ³¬¼¶Óû§ÌØÈ¨ÊÇûÓм̳ÐÐԵģ¬ÒòΪÔÚrootÓû§ÎªÆÕͨÓû§´´½¨½ø³Ìʱ£¬³öÓÚ°²È«¿¼ÂÇÕâ¸öÆÕͨÓû§µÄ½ø³Ì²»ÔÊÐíÓµÓг¬¼¶Óû§ÌØÈ¨¡£*/
        p->flags &= ~(PF_PTRACED|PF_TRACESYS|PF_SUPERPRIV);
/*½«½ø³Ì±êÖ¾Éè³É³õ½¨£¬ÔÚ½ø³ÌµÚÒ»´Î»ñµÃCPUʱ£¬Äں˽«¸ù¾Ý´Ë±êÖ¾½øÐÐÒ»¶¨²Ù×÷*/
        p->flags |= PF_FORKNOEXEC;
   ¿ªÊ¼Task_structµÄ³õʼ»¯¹¤×÷£¬Èç³õʼ»¯½ø³ÌʱÖÓ¡¢Ðźš¢Ê±¼äµÈÊý¾Ý;
   ¼Ì³Ð¸¸½ø³ÌËùÓÐ×ÊÔ´:
                ¿½±´¸¸½ø³Ìµ±Ç°´ò¿ªµÄÎļþ;
                ¿½±´¸¸½ø³ÌÔÚVFSµÄλÖÃ;
                ¿½±´¸¸½ø³ÌµÄÐźÅÁ¿;
                ¿½±´¸¸½ø³ÌÔËÐеÄÄÚ´æ;
                ¿½±´¸¸½ø³ÌµÄÏß³Ì;
   ³õʼ»¯¹¤×÷½áÊø£¬¸¸½ø³Ì½«Æä½«Æä»½ÐÑ,¹ÒÈërunning¶ÓÁÐÖУ¬·µ»Ø×Ó½ø³ÌµÄpid;

}

½ø³ÌµÄµ÷¶È£¨schedule()£©£º

   ´¦ÓÚTASK_RUNNING״̬µÄ½ø³ÌÒÆµ½run queue£¬»áÓÉschedule()°´CPUµ÷¶ÈËã·¨ÔÚºÏÊʵÄʱºòÑ¡ÖУ¬·ÖÅ䏸CPU¡£
   д´½¨µÄ½ø³Ì¶¼ÊÇ´¦ÓÚTASK_RUNNING״̬£¬¶øÇÒ±»¹Òµ½run queueµÄ¶ÓÊס£½ø³Ìµ÷¶È²ÉÓñäÐεÄÂÖת·¨£¨round robin£©¡£µ±Ê±¼äƬµ½Ê±£¨10msµÄÕûÊý±¶£©£¬ÓÉʱÖÓÖжÏÒýÆðÐÂÒ»ÂÖµ÷¶È£¬°Ñµ±Ç°½ø³Ì¹Òµ½run queue¶Óβ¡£
   ËùÓеĽø³Ì²¿·ÖÔËÐÐÓëÓû§Ì¬£¬²¿·ÖÔËÐÐÓÚϵͳ̬¡£µ×²ãµÄÓ²¼þÈçºÎÖ§³ÖÕâЩ״̬¸÷²»Ïàͬµ«ÊÇͨ³£ÓÐÒ»¸ö°²È«»úÖÆ´ÓÓû§Ì¬×ªÈëϵͳ̬²¢×ª»ØÀ´¡£Óû§Ì¬±Èϵͳ̬µÄȨÏÞµÍÁ˺ܶࡣÿһ´Î½ø³ÌÖ´ÐÐÒ»¸öϵͳµ÷Óã¬Ëü¶¼´ÓÓû§Ì¬Çл»µ½ÏµÍ³Ì¬²¢¼ÌÐøÖ´ÐС£ÕâʱÈúËÐÄÖ´ÐÐÕâ¸ö½ø³Ì¡£LinuxÖУ¬½ø³Ì²»ÊÇ»¥ÏàÕù¶á³ÉΪµ±Ç°ÔËÐеĽø³Ì£¬ËüÃÇÎÞ·¨Í£Ö¹ÕýÔÚÔËÐÐµÄÆäËü½ø³ÌÈ»ºóÖ´ÐÐ×ÔÉí¡£Ã¿Ò»¸ö½ø³ÌÔÚËü±ØÐëµÈ´ýһЩϵͳʼþµÄʱºò»á·ÅÆúCPU¡£ÀýÈ磬һ¸ö½ø³Ì¿ÉÄܲ»µÃ²»µÈ´ý´ÓÒ»¸öÎļþÖжÁȡһ¸ö×Ö·û¡£Õâ¸öµÈ´ý·¢ÉúÔÚϵͳ̬µÄϵͳµ÷ÓÃÖС£½ø³ÌʹÓÃÁ˿⺯Êý´ò¿ª²¢¶ÁÎļþ£¬¿âº¯ÊýÓÖÖ´ÐÐϵͳµ÷ÓôӴò¿ªµÄÎļþÖжÁÈë×Ö½Ú¡£Õâʱ£¬µÈºòµÄ½ø³Ì»á±»¹ÒÆð£¬ÁíÒ»¸ö¸ü¼ÓÖµµÃµÄ½ø³Ì½«»á±»Ñ¡ÔñÖ´ÐС£½ø³Ì¾­³£µ÷ÓÃϵͳµ÷Óã¬ËùÒÔ¾­³£ÐèÒªµÈ´ý¡£¼´Ê¹½ø³ÌÖ´Ðе½ÐèÒªµÈ´ýÒ²ÓпÉÄÜ»áÓÃÈ¥²»¾ùºâµÄCPUʼþ£¬ËùÒÔLinuxʹÓÃÇÀÏÈʽµÄµ÷¶È¡£ÓÃÕâÖÖ·½°¸£¬Ã¿Ò»¸ö½ø³ÌÔÊÐíÔËÐÐÉÙÁ¿Ò»¶Îʱ¼ä£¬200ºÁÃ룬µ±Õâ¸öʱ¼ä¹ýÈ¥£¬Ñ¡ÔñÁíÒ»¸ö½ø³ÌÔËÐУ¬Ô­À´µÄ½ø³ÌµÈ´ýÒ»¶Îʱ¼äÖ±µ½ËüÓÖÖØÐÂÔËÐС£Õâ¸öʱ¼ä¶Î½Ð×öʱ¼äƬ¡£
   ÐèÒªµ÷¶È³ÌÐòÑ¡ÔñϵͳÖÐËùÓпÉÒÔÔËÐеĽø³ÌÖÐ×îÖµµÃµÄ½ø³Ì¡£Ò»¸ö¿ÉÒÔÔËÐеĽø³ÌÊÇÒ»¸öÖ»µÈ´ýCPUµÄ½ø³Ì¡£LinuxʹÓúÏÀí¶ø¼òµ¥µÄ»ùÓÚÓÅÏȼ¶µÄµ÷¶ÈËã·¨ÔÚϵͳµ±Ç°µÄ½ø³ÌÖнøÐÐÑ¡Ôñ¡£µ±ËüÑ¡ÔñÁË×¼±¸ÔËÐеÄнø³Ì£¬Ëü¾Í±£´æµ±Ç°½ø³ÌµÄ״̬¡¢ºÍ´¦ÀíÆ÷Ïà¹ØµÄ¼Ä´æÆ÷ºÍÆäËûÐèÒª±£´æµÄÉÏÏÂÎÄÐÅÏ¢µ½½ø³ÌµÄtask_structÊý¾Ý½á¹¹ÖС£È»ºó»Ö¸´ÒªÔËÐеÄеĽø³ÌµÄ״̬£¨Óֺʹ¦ÀíÆ÷Ïà¹Ø£©£¬°ÑϵͳµÄ¿ØÖƽ»¸øÕâ¸ö½ø³Ì¡£ÎªÁ˹«Æ½µØÔÚϵͳÖÐËùÓпÉÒÔÔËÐУ¨runnable£©µÄ½ø³ÌÖ®¼ä·ÖÅäCPUʱ¼ä£¬µ÷¶È³ÌÐòÔÚÿһ¸ö½ø³ÌµÄtask_struct½á¹¹Öб£´æÁËÐÅÏ¢¡£
   policy ½ø³ÌµÄµ÷¶È²ßÂÔ£ºLinuxÓÐÁ½ÖÖÀàÐ͵Ľø³Ì£ºÆÕͨºÍʵʱ¡£ÊµÊ±½ø³Ì±ÈËùÓÐÆäËü½ø³ÌµÄÓÅÏȼ¶¸ß¡£Èç¹ûÓÐÒ»¸öʵʱµÄ½ø³Ì×¼±¸ÔËÐУ¬ÄÇôËü×ÜÊÇÏȱ»ÔËÐС£ÊµÊ±½ø³ÌÓÐÁ½ÖÖ²ßÂÔ£º»·»òÏȽøÏȳö£¨round robin and first in first out£©¡£ÔÚ»·µÄµ÷¶È²ßÂÔÏ£¬Ã¿Ò»¸öʵʱ½ø³ÌÒÀ´ÎÔËÐУ¬¶øÔÚÏȽøÏȳöµÄ²ßÂÔÏ£¬Ã¿Ò»¸ö¿ÉÒÔÔËÐеĽø³Ì°´ÕÕËüÔÚµ÷¶È¶ÓÁÐÖеÄ˳ÐòÔËÐУ¬Õâ¸ö˳Ðò²»»á¸Ä±ä¡£
   Priority ½ø³ÌµÄµ÷¶ÈÓÅÏȼ¶¡£Ò²ÊÇËüÔÊÐíÔËÐеÄʱºò¿ÉÒÔʹÓõÄʱ¼äÁ¿£¨jiffies£©¡£Äã¿ÉÒÔͨ¹ýϵͳµ÷ÓûòÕßreniceÃüÁîÀ´¸Ä±äÒ»¸ö½ø³ÌµÄÓÅÏȼ¶¡£
   Rt_priority LinuxÖ§³Öʵʱ½ø³Ì¡£ÕâЩ½ø³Ì±ÈϵͳÖÐÆäËû·ÇʵʱµÄ½ø³ÌÓµÓиü¸ßµÄÓÅÏȼ¶¡£Õâ¸öÓòÔÊÐíµ÷¶È³ÌÐò¸³Óèÿһ¸öʵʱ½ø³ÌÒ»¸öÏà¶ÔµÄÓÅÏȼ¶¡£ÊµÊ±½ø³ÌµÄÓÅÏȼ¶¿ÉÒÔÓÃϵͳµ÷ÓÃÀ´ÐÞ¸ÄCoutner Õâʱ½ø³Ì¿ÉÒÔÔËÐеÄʱ¼äÁ¿£¨jiffies£©¡£½ø³ÌÆô¶¯µÄʱºòµÈÓÚÓÅÏȼ¶£¨priority£©£¬Ã¿Ò»´ÎʱÖÓÖÜÆÚµÝ¼õ¡£
  µ÷¶È³ÌÐòschedule()´ÓºËÐĵĶà¸öµØ·½ÔËÐС£Ëü¿ÉÒÔÔڰѵ±Ç°½ø³Ì·Åµ½µÈ´ý¶ÓÁÐÖ®ºóÔËÐУ¬Ò²¿ÉÒÔÔÚϵͳµ÷ÓÃÖ®ºó½ø³Ì´Óϵͳ̬·µ»Ø½ø³Ì̬֮ǰÔËÐС£ÐèÒªÔËÐе÷¶È³ÌÐòµÄÁíÒ»¸öÔ­ÒòÊÇϵͳʱÖӸպðѵ±Ç°½ø³ÌµÄ¼ÆÊýÆ÷(counter)ÖóÉÁË0¡£Ã¿Ò»´Îµ÷¶È³ÌÐòÔËÐÐËü×öÒÔϹ¤×÷£º
£¨1£©kernel work µ÷¶È³ÌÐòÔËÐÐbottom half handler²¢´¦ÀíϵͳµÄµ÷¶ÈÈÎÎñ¶ÓÁС£
£¨2£©Current pocess ÔÚÑ¡ÔñÁíÒ»¸ö½ø³Ì֮ǰ±ØÐë´¦Àíµ±Ç°½ø³Ì¡£
£¨3£©Èç¹ûµ±Ç°½ø³ÌµÄµ÷¶È²ßÂÔÊÇ»·ÔòËü·Åµ½ÔËÐжÓÁеÄ×îºó¡£
£¨4£©Èç¹ûÈÎÎñ״̬ÊÇTASK_INTERRUPTIBLEµÄ¶øÇÒËüÉϴε÷¶ÈµÄʱºòÊÕµ½¹ýÒ»¸öÐźţ¬ËüµÄ״̬±äΪTASK_RUNNING;
     Èç¹ûµ±Ç°½ø³Ì³¬Ê±£¬ËüµÄ״̬³ÉΪRUNNING;
     Èç¹ûµ±Ç°½ø³ÌµÄ״̬ΪRUNNINGÔò±£³Ö´Ë״̬;
     ²»ÊÇRUNNING»òÕßINTERRUPTIBLEµÄ½ø³Ì±»´ÓÔËÐжÓÁÐÖÐɾ³ý¡£ÕâÒâζ×ŵ±µ÷¶È³ÌÐò²éÕÒ×îÖµµÃÔËÐеĽø³Ìʱ²»»á¿¼ÂÇÕâÑùµÄ½ø³Ì¡£
(5)Process Selection µ÷¶È³ÌÐò²é¿´ÔËÐжÓÁÐÖеĽø³Ì£¬²éÕÒ×îÖµµÃÔËÐеĽø³Ì¡£Èç¹ûÓÐʵʱµÄ½ø³Ì£¨¾ßÓÐʵʱµ÷¶È²ßÂÔ£©£¬¾Í»á±ÈÆÕͨ½ø³Ì¸üÖØÒ»Ð©¡£ÆÕͨ½ø³ÌµÄÖØÁ¿ÊÇËüµÄcounter£¬µ«ÊǶÔÓÚʵʱ½ø³ÌÔòÊÇcounter ¼Ó1000¡£ÕâÒâζ×ÅÈç¹ûϵͳÖдæÔÚ¿ÉÔËÐеÄʵʱ½ø³Ì£¬¾Í×ÜÊÇÔÚÈÎºÎÆÕͨ¿ÉÔËÐеĽø³Ì֮ǰÔËÐС£µ±Ç°µÄ½ø³Ì£¬ÒòΪÓõôÁËһЩʱ¼äƬ£¨ËüµÄcounter¼õÉÙÁË£©£¬ËùÒÔÈç¹ûϵͳÖÐÓÉÆäËûͬµÈÓÅÏȼ¶µÄ½ø³Ì£¬¾Í»á´¦ÓÚ²»ÀûµÄλÖãºÕâÒ²ÊÇÓ¦¸ÃµÄ¡£Èç¹û¼¸¸ö½ø³ÌÓÖͬÑùµÄÓÅÏȼ¶£¬×î½Ó½üÔËÐжÓÁÐǰ¶ÎµÄÄǸö¾Í±»Ñ¡ÖС£µ±Ç°½ø³Ì±»·Åµ½ÔËÐжÓÁеĺóÃæ¡£Èç¹ûÒ»¸öƽºâµÄϵͳ£¬ÓµÓдóÁ¿ÏàͬÓÅÏȼ¶µÄ½ø³Ì£¬ÄÇô»Ø°´ÕÕ˳ÐòÖ´ÐÐÕâЩ½ø³Ì¡£Õâ½Ð×ö»·Ð͵÷¶È²ßÂÔ¡£²»¹ý£¬ÒòΪ½ø³ÌÐèÒªµÈ´ý×ÊÔ´£¬ËüÃǵÄÔËÐÐ˳Ðò¿ÉÄÜ»á±ä»¯¡£
(6)Swap Processes Èç¹û×îÖµµÃÔËÐеĽø³Ì²»Êǵ±Ç°½ø³Ì£¬µ±Ç°½ø³Ì±ØÐë±»¹ÒÆð£¬ÔËÐÐеĽø³Ì¡£µ±Ò»¸ö½ø³ÌÔËÐеÄʱºòËüʹÓÃÁËCPUºÍϵͳµÄ¼Ä´æÆ÷ºÍÎïÀíÄڴ档ÿһ´ÎËüµ÷ÓÃÀý³Ì¶¼Í¨¹ý¼Ä´æÆ÷»òÕß¶ÑÕ»´«µÝ²ÎÊý¡¢±£´æÊýÖµ±ÈÈçµ÷ÓÃÀý³ÌµÄ·µ»ØµØÖ·µÈ¡£Òò´Ë£¬µ±µ÷¶È³ÌÐòÔËÐеÄʱºòËüÔÚµ±Ç°½ø³ÌµÄÉÏÏÂÎÄÔËÐС£Ëü¿ÉÄÜÊÇÌØÈ¨Ä£Ê½£ººËÐÄ̬£¬µ«ÊÇËüÈÔ¾ÉÊǵ±Ç°ÔËÐеĽø³Ì¡£µ±Õâ¸ö½ø³ÌÒª¹ÒÆðʱ£¬ËüµÄËùÓлúÆ÷״̬£¬°üÀ¨³ÌÐò¼ÆÊýÆ÷(PC)ºÍËùÓеĴ¦ÀíÆ÷¼Ä´æÆ÷£¬±ØÐë´æµ½½ø³ÌµÄtask_structÊý¾Ý½á¹¹ÖС£È»ºó£¬±ØÐë¼ÓÔØÐ½ø³ÌµÄËùÓлúÆ÷״̬¡£ÕâÖÖ²Ù×÷ÒÀÀµÓÚϵͳ£¬²»Í¬µÄCPU²»»áÍêÈ«ÏàͬµØÊµÏÖ£¬²»¹ý¾­³£¶¼ÊÇͨ¹ýһЩӲ¼þµÄ°ïÖú¡£
(7)½»»»³öÈ¥½ø³ÌµÄÉÏÏÂÎÄ·¢ÉúÔÚµ÷¶ÈµÄ×îºó¡£Ç°Ò»¸ö½ø³Ì´æ´¢µÄÉÏÏÂÎÄ£¬¾ÍÊǵ±Õâ¸ö½ø³ÌÔÚµ÷¶È½áÊøµÄʱºòϵͳµÄÓ²¼þÉÏÏÂÎĵĿìÕÕ¡£ÏàͬµÄ£¬µ±¼ÓÔØÐµĽø³ÌµÄÉÏÏÂÎÄʱ£¬ÈÔ¾ÉÊǵ÷¶È½áÊøÊ±µÄ¿ìÕÕ£¬°üÀ¨½ø³ÌµÄ³ÌÐò¼ÆÊýÆ÷ºÍ¼Ä´æÆ÷µÄÄÚÈÝ¡£
(8)Èç¹ûǰһ¸ö½ø³Ì»òÕßеĵ±Ç°½ø³ÌʹÓÃÐéÄâÄڴ棬ÔòϵͳµÄÒ³±íÐèÒª¸üС£Í¬Ñù£¬Õâ¸ö¶¯×÷ÊʺÏÌåϵ½á¹¹Ïà¹Ø¡£Alpha AXP´¦ÀíÆ÷£¬Ê¹ÓÃTLT£¨Translation Look-aside Table£©»òÕß»º´æµÄÒ³±íÌõÄ¿£¬±ØÐëÇå³ýÊôÓÚǰһ¸ö½ø³ÌµÄ»º´æµÄÒ³±íÌõÄ¿¡£

   ÏÂÃæÎÒ¾ÍÀ´×ܽáһϽø³Ì´´½¨ÒÔºóµ½±»É±ËÀµÄÕû¸ö½ø³ÌÉúÃüÖÜÆÚÖУ¬×´Ì¬¿ÉÄÜÔÚTASK_RUNNING¡¢TASK_INTERRUPTIBLE¡¢TASK_UNINTERRUPTIBLE ¡¢TASK_STOPPEDÒÔ¼°TASK_ZOMBLEÖ®¼äת»»µÄÔ­Òò¡£

½ø³ÌÔÚTASK_RUNNINGÒÔ¼°TASK_UNINTERRUPTIBLE¡¢TASK_INTERRUPTIBLEÖ®¼äת»»£º
   »ñµÃCPU¶øÕýÔÚÔËÐеĽø³Ì»áÓÉÓÚijЩԭÒò£¬±ÈÈ磺ÉêÇë²»µ½Ä³¸ö×ÊÔ´£¬Æä״̬»á´ÓTASK_RUNNING±äΪTASK_INTERRUPTIBLE»òTASK_UNINTERRUPTIBLEµÄµÈ´ý״̬¡£Í¬ÑùÔÚ¾­ÀúÁËijЩÇé¿ö£¬´¦Óڵȴý״̬µÄ½ø³Ì»á±»ÖØÐ»½ÐÑ£¬µÈ´ý·ÖÅ䏸CPU¡£×´Ì¬ÎªTASK_INTERRUPTIBLEµÄ˯Ãß½ø³Ì»á±»»½ÐÑ£¬»Øµ½TASK_RUNNING״̬£¬ÖØÐµȴýschedule()·ÖÅ䏸ËüCPU£¬¼ÌÐøÔËÐУ¬±ÈÈ磺µ±ÉêÇë×ÊÔ´ÓÐЧʱ£¬Ò²¿ÉÒÔÓÉsignal»ò¶¨Ê±Öжϻ½ÐÑ¡£¶ø×´Ì¬ÎªTASK_INTERRUPTIBLEµÄ˯Ãß½ø³ÌÖ»Óе±ÉêÇë×ÊÔ´ÓÐЧʱ±»»½ÐÑ£¬²»Äܱ»signal¡¢¶¨Ê±Öжϻ½ÐÑ¡£

1.ͨ¹ýsleep_on()¡¢interruptible_sleep_on()¡¢sleep_on_timeout()¡¢interruptible_sleep_on_timeout£¨£©ÒÔ¼°wake_up()¡¢wake_up_process()¡¢wake_up_interruptible()º¯Êý¶Ô½øÐеÄת»»£º

   sleep_on():TASK_RUNNING->TASK_UNINTERRUPTIBLE
   µ±ÓµÓÐCPUµÄ½ø³ÌÉêÇë×ÊÔ´ÎÞЧʱ£¬»áͨ¹ýsleep_on()£¬½«½ø³Ì´ÓTASK_RUNNINGÇл»µ½TASK_UNINTERRUPTIBLE״̬¡£sleep_on()º¯ÊýµÄ×÷ÓþÍÊǽ«current½ø³ÌµÄ״̬ÖóÉTASK_UNINTERRUPTIBLE,²¢¼Óµ½µÈ´ý¶ÓÁÐÖС£
   Ò»°ãÀ´ËµÒýÆð״̬±ä³ÉTASK_UNINTERRUPTIBLEµÄ×ÊÔ´ÉêÇë¶¼ÊǶÔһЩӲ¼þ×ÊÔ´µÄÉêÇ룬Èç¹ûµÃ²»µ½ÕâЩ×ÊÔ´£¬½ø³Ì½«²»ÄÜÖ´ÐÐÏÂÈ¥£¬²»ÄÜÓÉsignalÐźŻòʱÖÓÖжϻ½ÐÑ£¬¶ø»Øµ½TASK_RUNNING״̬¡£
   ÎÒÃÇ×ܽáÁËÕâÖÖÀàÐ͵Äת»»Ô­ÒòÓУº
£¨1£©¶ÔijЩ×ÊÔ´µÄ²Ù×÷Ö»ÄÜÓÉÒ»¸ö½ø³Ì½øÐУ¬ËùÒÔϵͳ¶Ô¸ÃÏî×ÊÔ´²ÉÓÃÉÏËø»úÖÆ¡£ÔÚÉêÇë¸ÃÏî×ÊԴʱ£¬±ØÐëÏÈÉêÇë×ÊÔ´µÄËø£¬Èç¹ûÒѾ­±»±ðµÄ½ø³ÌÕ¼Óã¬Ôò±ØÐë˯ÃßÔÚ¶Ô¸ÃËøµÄµÈ´ý¶ÓÁÐÉÏ¡£¶øÇÒÕâÖÖ˯Ãß²»Äܱ»Öжϣ¬±ØÐëµÈµ½µÃµ½ÁË×ÊÔ´²ÅÄܼÌÐø½øÐÐÏÂÈ¥¡£
È磺
¶ÔÍøÂçÁ¬½Ó±íËø£¨Netlink table lock£©µÄÉêÇë, sleep_on(&nl_table_wait)£»
¶Ô½»»»Ò³½øÐÐI/O²Ù×÷µÄËøµÄÉêÇë, sleep_on(&lock_queue)£»
¶ÔHash±í²Ù×÷µÄËøµÄÉêÇë, sleep_on(&hash_wait)£»
ÔÚUMSDOSÎļþϵͳ´´½¨Îļþ»òĿ¼ʱ£¬±ØÐëµÈ´ýÆäËûͬÑùµÄ´´½¨¹¤×÷½áÊø,sleep_on (&dir->u.umsdos_i.u.dir_info.p);

£¨2£©Ä³Ð©½ø³ÌÔڴ󲿷Öʱ¼ä´¦ÓÚ˯Ãß״̬£¬½öÔÚÐèҪʱ±»»½ÐÑÈ¥Ö´ÐÐÏàÓ¦µÄ²Ù×÷£¬µ±Ö´ÐÐÍêºó£¬¸Ã½ø³ÌÓÖÇ¿ÖÆÈ¥Ë¯Ãß¡£
È磺
wakeup_bdflush£¨)ÊǶÔdirty buffer½øÐж¯Ì¬µÄÏìÓ¦£¬Ò»µ©¸Ã½ø³Ì±»¼¤»î£¬¾Í½«Ò»¶¨ÊýÁ¿µÄdirty bufferд»Ø´ÅÅÌ£¬È»ºóµ÷ÓÃsleep_on(&bdflush_done),ÓÖȥ˯Ãß¡£

interruptible_sleep_on():TASK_RUNNING->TASK_INTERRUPTIBLE
   Óësleep_on()º¯Êý·Ç³£µØÏàÏ󣬵±ÓµÓÐCPUµÄ½ø³ÌÉêÇë×ÊÔ´ÎÞЧʱ£¬»áͨ¹ýinterruptible_sleep_on()£¬½«½ø³Ì´ÓTASK_RUNNINGÇл»µ½TASK_INTERRUPTIBLE״̬¡£interruptible_sleep_on()º¯ÊýµÄ×÷ÓþÍÊǽ«current½ø³ÌµÄ״̬ÖóÉTASK_INTERRUPTIBLE,²¢¼Óµ½µÈ´ý¶ÓÁÐÖС£
   ´¦ÓÚTASK_INTERRUPTIBLE״̬µÄ½ø³Ì¿ÉÒÔÔÚ×ÊÔ´ÓÐЧʱ±»wake_up()¡¢wake_up_interruptible()»òwake_up_process()»½ÐÑ£¬»òÊÕµ½signalÐźÅÒÔ¼°Ê±¼äÖжϺ󱻻½ÐÑ¡£
   ½øÐÐÕâÖÖת»»µÄÔ­Òò»ù±¾ÉÏÓësleep_on()Ïàͬ£¬ÉêÇë×ÊÔ´ÎÞЧʱ½ø³ÌÇл»µ½µÈ´ý״̬¡£ÓëÖ®²»Í¬µÄÊÇ´¦ÓÚinterruptible_sleep_on()µÈ´ý״̬µÄ½ø³ÌÊÇ¿ÉÒÔ½ÓÊÜÐźŻòÖж϶øÖØÐ±äΪrunning״̬¡£ËùÒÔ¿ÉÒÔÈÏΪ¶ÔÕâЩ×ÊÔ´µÄÉêÇëûÓÐÏóÔÚsleep_on()ÖÐ×ÊÔ´µÄÒªÇóÄÇôÑϸñ£¬±ØÐëµÃµ½¸Ã×ÊÔ´½ø³Ì²ÅÄܼÌÐøÆäÔËÐÐÏÂÈ¥¡£

sleep_on_timeout():TASK_RUNNING->TASK_UNINTERRUPTIBLE
sleep_on_timeout(&block.b_wait, 30*HZ);

interruptible_sleep_on_timeout£¨£©£ºTASK_RUNNING->TASK_INTERRUPTIBLE
   ËäÈ»ÔÚÉêÇë×ÊÔ´»òÔËÐÐÖгöÏÖÁËijÖÖ´íÎ󣬵«ÊÇϵͳÈÔÈ»¸ø½ø³ÌÒ»´ÎÖØÐÂÔËÐеĻú»á¡£µ÷Óøú¯Êý½«½ø³Ì´ÓTASK_RUNNINGÇл»µ½TASK_INTERRUTIBLE״̬£¬²¢µÈ´ý¹æ¶¨µÄʱ¼äƬ³¤¶È,ÔÙÖØÐÂÊÔÒ»´Î¡£
È磺ÔÚsmb_request_ok ÖвúÉúÁËÁ¬½Óʧ°ÜµÄ´íÎ󣬻áÔÚsem_retry()ÖиøÒ»´ÎÖØÐÂÁ¬½ÓµÄ»ú»á¡£//interruptible_sleep_on_timeout(&server->wait,  5*HZ)£»

wake_up():TASK_UNINTERRUPTIBLE-> TASK_RUNNING;
          TASK_INTERRUPTIBLE-> TASK_RUNNING
   ´¦ÓÚTASK_UNINTERRUPTIBLE״̬µÄ½ø³Ì²»ÄÜÓÉsignalÐźŻòʱÖÓÖжϻ½ÐÑ£¬Ö»ÄÜÓÉwake_up()»òwake_up_process()»½ÐÑ¡£wake_up()º¯ÊýµÄ×÷ÓÃÊǽ«wait_queueÖеÄËùÓÐ״̬ΪTASK_INTERRUPTIBLE»òTASK_UNINTERRUPTIBLEµÄ½ø³Ì״̬¶¼ÖÃΪTASK_RUNNING,²¢½«ËüÃǶ¼·Åµ½running¶ÓÁÐÖÐÈ¥£¬¼´»½ÐÑÁËËùÓеȴýÔڸöÓÁÐÉϵĽø³Ì¡£
void wake_up(struct wait_queue **q)
{
        struct wait_queue *next;
        struct wait_queue *head;

        if (!q || !(next = *q))
                return;
        head = WAIT_QUEUE_HEAD(q);
        while (next != head) {
                struct task_struct *p = next->task;
                next = next->next;
                if (p != NULL) {
                        if ((p->state == TASK_UNINTERRUPTIBLE) ||
                            (p->state == TASK_INTERRUPTIBLE))
                                wake_up_process(p);
                }
                if (!next)
                        goto bad;
        }
        return;
bad:
        printk("wait_queue is bad (eip = %p)\n",
                __builtin_return_address(0));
        printk("        q = %p\n",q);
        printk("       *q = %p\n",*q);
}

  wake_up()ÔÚÏÂÁÐÇé¿öϱ»µ÷Óãº
Õâ¸öº¯Êýͨ³£ÔÚ×ÊÔ´ÓÐЧʱµ÷Óã¬×ÊÔ´ËøÒѾ­±»ÊÍ·Å£¬µÈ´ý¸Ã×ÊÔ´µÄËùÓнø³Ì¶¼±»ÖÃΪTASK_RUNNING״̬£¬ÒƵ½run queue£¬ÖØÐ²ÎÓëµ÷¶È£¬¶ÔÕâÒ»×ÊÔ´ÔٴξºÕù¡£ÕâʱÓÖ»áÓÐij¸ö½ø³Ì¾ºÕùµ½Á˸ÃÏî×ÊÔ´£¬¶øÆäËûµÄ½ø³ÌÔÚÉêÇëʧ°Üºó£¬Óֻص½TASK_UNINTERRUPTIBLE»òTASK_INTERRUPTIBLE״̬¡£
È磺
ÍøÂçÁ¬½Ó±íËø£¨Netlink table lock£©Êͷźó,»½Ðѵȴý¸ÃËøµÄËùÓÐ˯Ãß½ø³Ì wake_up(&nl_table_wait)£»
¶Ô½»»»Ò³½øÐÐI/O²Ù×÷µÄËøÊͷźó,»½Ðѵȴý¸ÃËøµÄËùÓÐ˯Ãß½ø³Ì, wake_up(&lock_queue)£»
¶ÔHash±í²Ù×÷µÄËøÊͷźó,»½Ðѵȴý¸ÃËøµÄËùÓÐ˯Ãß½ø³Ì£¬wake_up(&hash_wait)£»
ÔÚUMSDOSÎļþϵͳ´´½¨Îļþ»òĿ¼¹¤×÷½áÊøºó,»½ÐÑÆäËûÓÉÓڵȴýËü´´½¨½áÊø¶øË¯ÃߵĽø³Ì£¬ wake_up (&dir->u.umsdos_i.u.dir_info.p)£»

»½ÐÑ˯Ãß½ø³ÌÖ´ÐÐijЩ²Ù×÷£º
È磺
bd_flush()º¯ÊýÒª½«Ò»Ð©dirty bufferд»Ø´ÅÅÌ£¬¾Íµ÷ÓÃwake_up(&bdflush_done)£¬»½ÐÑÕýÔÚ˯ÃßµÄwakeup_bdflush£¨)½ø³ÌÈ¥´¦Àíд»Ø¡£


wake_up_process()£ºTASK_UNINTERRUPTIBLE-> TASK_RUNNING;
                   TASK_INTERRUPTIBLE-> TASK_RUNNING
   wake_up_process()º¯ÊýµÄ×÷ÓÃÊǽ«²ÎÊýËùÖ¸µÄÄǸö½ø³Ì״̬´ÓTASK_INTERRUPTIBLE,TASK_UNINTERRUPTIBLE±äΪTASK_RUNNING,²¢½«Ëü·Åµ½running¶ÓÁÐÖÐÈ¥¡£

void wake_up_process(struct task_struct * p)
{
        unsigned long flags;

        /*
        * We want the common case fall through straight, thus the goto.
        */
        spin_lock_irqsave(&runqueue_lock, flags);
        p->state = TASK_RUNNING;
        if (p->next_run)
                goto out;
        add_to_runqueue(p);
        spin_unlock_irqrestore(&runqueue_lock, flags);

        reschedule_idle(p);
        return;
out:
        spin_unlock_irqrestore(&runqueue_lock, flags);
}

   Õâ¸öº¯ÊýµÄʵÏÖ»úÖÆÓëwake_up()µÄ²»Í¬ÔÚÓÚ£¬ËüÖ»ÄÜ»½ÐÑijһ¸öÌØ¶¨µÄ˯Ãß½ø³Ì£¬¶øwake_up()ÊÇ»½ÐÑÕû¸öµÈ´ý¶ÓÁеÄ˯Ãß½ø³Ì¡£ËùÒÔ£¬ËüµÄ»½ÐѵÄÔ­ÒòÓëwake_up()Ò²ÓÐÒ»¶¨µÄÇø±ð£¬³ýÁËÓÉÓÚwake_up()¶ÔËüµÄµ÷ÓÃÖ®Í⣬Ëü»½Ðѽø³Ì²¢²»ÊÇÓÉÓÚ×ÊÔ´ÓÐЧÔì³ÉµÄ£¬»½ÐѵĽø³ÌÒ²²»ÊÇÒòµÈ´ý×ÊÔ´ÓÐЧ¶øË¯ÃߵĽø³Ì¡£ÓÐÒÔϼ¸ÖÖÇé¿ö£º
¸¸½ø³Ì¶Ô×Ó½ø³ÌµÄ»½ÐÑ£º
È磺
ÔÚsys_ptrace()Öе±ÊÕµ½µÄ¸ú×ÙÇëÇóΪ£ºPTRACE_CONT£¨ÔÚ´¦ÀíÍêÐźźó¼ÌÐø£©£»PTRACE_KILL£¨½«×Ó½ø³Ìɱ³ö£©£»PTRACE_SINGLESTEP£¨¶Ô×Ó½ø³Ì½øÐе¥²½¸ú×Ù£©£»PTRACE_DETACHµÄʱºò£¬¶¼»áÔÚ´¦Àí½áÊøÊ±£¬»½ÐÑ×Ó½ø³Ì£¬¸ø×Ó½ø³ÌÒ»¸öÔËÐеĻú»á¡£
ÔÚdo_fork()ÖУ¬Ð½¨½ø³Ì³õʼ»¯Íê±Ï£¬»áÓɸ¸½ø³Ì»½ÐÑËü£¬½«¸Ã½ø³ÌÒÆµ½run queueÖУ¬ÖÃ״̬ΪTASK_RUNNING¡£

µ±ÐèÒªµÄʱºò»½ÐÑij¸ö˯ÃßµÄϵͳµ÷Ó㬽øÐд¦Àí£º
È磺
kswapd_processÒ³Ãæ½»»»½ø³Ì£¬Í¨³£ÊÇ´¦ÓÚ˯Ãß״̬µÄ£¬µ±Ä³¸ö½ø³ÌÐèÒª¸ü¶àµÄÄڴ棬¶øµ÷ÓÃtry_to_free_pages£¨£©Ê±£¬¾Í»á»½ÐÑkswapd_processÒ³Ãæ½»»»½ø³Ì£¬µ÷Èë¸ü¶àµÄÄÚ´æÒ³Ãæ¡£

ÊÕµ½ÐźÅËù½øÐеÄÏàÓ¦´¦Àí£º
È磺
ijһ½ø³ÌµÄʱ¼äƬµ½ÁË£¬process_timeout()»áµ÷ÓÃwake_up_process()»½ÐѸýø³Ì£»
ÊÕµ½Ä³Ð©signalÐźÅ:´¦ÓÚSTOPPED״̬µÄ½ø³ÌÊÕµ½SIGKILL»òSIGCONT»á±»»½ÐÑ£¨×¢£º´¦ÓÚSTOPPED״̬µÄ½ø³Ì²»Äܱ»wake_up()»½ÐÑ£©£»ÒÔ¼°ÊÕµ½Ä³Ð©·ÇʵʱÐźţ¬²»Ðè¼Óµ½signal¶ÓÁÐÖÐÈ¥£¬´¦ÓÚTASK_INTERRUPTIBLEµÄ½ø³ÌÓлú»á±»»½ÐÑ¡£

×ÊÔ´ÓÐЧʱ£¬wake_up()¶ÔÕû¸öµÈ´ý¶ÓÁеϽÐÑÊÇͨ¹ý¶Ôÿ¸öµÈ´ý¶ÓÁÐÉϵĽø³Ìµ÷ÓÃwake_up_process()ʵÏֵġ£

wake_up_interruptible£¨£©£ºTASK_INTERRUPTIBLE-> TASK_RUNNING
   ½«wait_queueÖеÄËùÓÐ״̬Ϊ TASK_INTERRUPTIBLEµÄ½ø³Ì״̬¶¼ÖÃΪTASK_RUNNING,²¢½«ËüÃǶ¼·Åµ½running queueÖÐÈ¥¡£
   Õâ¸öº¯Êýͨ³£ÔÚsend_sig(·¢³öÐźÅ)ºóµ÷ÓÃ,ÒÔʹÐźŷ¢³öºóÄܼ°Ê±µÃµ½ÏìÓ¦£¬»òÕßµ±¿ÕÏÐÏÂÀ´Ê±£¬Ï£Íû¼ì²éÒ»ÏÂÊÇ·ñÓÐÊÕµ½ÓÐЧÐźŵÄÄÜÔËÐеĽø³Ìʱ£¬Ò²¿ÉÒÔµ÷ÓÃÕâ¸öº¯Êý£¬È磺
ÔÚ½ø³ÌÍ˳öǰµ÷ÓÃnotify_parent(),¸ø¸¸½ø³Ìsend_sig£¨£©ºó£¬½«µ÷ÓÃwake_up_interruptible £¨£©£¬Ê¹ÐźÅÄܹ»µÃµ½¼°Ê±µÄÏìÓ¦¡£
usr\src\linux\KERNEL\EXIT.C Öж¨ÒåÁË
void notify_parent(struct task_struct * tsk, int signal)
{
        send_sig(signal, tsk->p_pptr, 1);
        wake_up_interruptible(&tsk->p_pptr->wait_chldexit);
}
   µ±Ä³Ò»½ø³ÌÒª½áÊøÊ±£¬Ëü¿ÉÒÔͨ¹ýµ÷ÓÃnotify_parent(current, current->exit_signal)֪ͨ¸¸½ø³ÌÒÔ»½ÐÑ˯ÃßÔÚwait_chldexitÉϵĸ¸½ø³Ì


2. Semaphores£¨Ðźŵƣ©

  ÐźÅÁ¿ÓÃÓÚÉú³ÉËø»úÖÆ,±ÜÃâ·¢ÉúÊý¾Ý²»Ò»Ö¡£
  ÐźÅÁ¿×î¼òµ¥µÄÐÎʽ¾ÍÊÇÄÚ´æÖÐÒ»¸öλÖã¬ËüµÄȡֵ¿ÉÒÔÓɶà¸ö½ø³Ì¼ìÑéºÍÉèÖ᣼ìÑéºÍÉèÖõIJÙ×÷£¬ÖÁÉÙ¶ÔÓÚ¹ØÁªµÄÿһ¸ö½ø³ÌÀ´½²£¬ÊDz»¿ÉÖжϻòÕß˵ÓÐÔ­×ÓÐÔ£ºÖ»ÒªÆô¶¯¾Í²»ÄÜÖÐÖ¹¡£¼ìÑéºÍÉèÖòÙ×÷µÄ½á¹ûÊÇÐźŵƵ±Ç°ÖµºÍÉèÖÃÖµµÄºÍ£¬¿ÉÒÔÊÇÕý»òÕ߸º¡£¸ù¾Ý²âÊÔºÍÉèÖòÙ×÷µÄ½á¹û£¬Ò»¸ö½ø³Ì¿ÉÄܱØÐë˯ÃßÖ±µ½ÐźŵƵÄÖµ±»ÁíÒ»¸ö½ø³Ì¸Ä±ä¡£ÐźŵƿÉÒÔÓÃÓÚʵÏÖÁÙ½çÇøÓò£¨critical regions£©£¬¾ÍÊÇÖØÒªµÄ´úÂëÇø£¬Í¬Ò»Ê±¿ÌÖ»ÄÜÓÐÒ»¸ö½ø³ÌÔËÐС£
   ¶ÔÐźŵƵIJÙ×÷ÊÇͨ¹ýÒÔÏÂÁ½×é»ù±¾º¯ÊýʵÏֵģº
1£®void __up(struct semaphore *sem) £ºTASK_UNINTERRUPTIBLE-> TASK_RUNNING;
                                  TASK_INTERRUPTIBLE-> TASK_RUNNING
    int __do_down(struct semaphore * sem, int task_state)ÓÉÒÔÏÂÁ½¸öº¯Êýµ÷Ó㬷ֱðת»»µ½²»Í¬µÄµÈ´ý״̬£º
(1)int __down_interruptible (struct semaphore * sem)£º
   TASK_RUNNING ->TASK_INTERRUPTIBLE;
(2)void __down(struct semaphore * sem):
   TASK_RUNNING ->TASK_UNINTERRUPTIBLE£»
2. extern inline void up(struct semaphore * sem)
   extern inline void down(struct semaphore * sem)£»
   extern inline int down_interruptible(struct semaphore * sem)£»

   LinuxÐźÅÁ¿ÊÇͨ¹ýÁ½Â·counter±äÁ¿ÊµÏֵģºµ±½ø³ÌÓÉÓÚÉêÇë²»µ½ÁÙ½çÇø×ÊÔ´¶øË¯Ãßʱ£¬»á½«semaphore½á¹¹Öеġ±count¡±±äÁ¿ÖµÔ­×ӵصݼõ1£¬½ø³Ì˯ÃߵȴýÁÙ½çÇø×ÊÔ´µÄÊÍ·Å£»¶øµ±up()º¯Êý»½ÐÑ˯Ãߵȴý½ø³Ìʱ£¬Èç¹û¡±count¡±±äÁ¿ÖµÐ¡ÓÚ0£¬»á½«semaphore½á¹¹Öеġ± waking¡±±äÁ¿ÖµÔ­×ӵصÝÔö1£¬»½ÐÑ˯Ãß½ø³Ì¡£ËäÈ»ËùÓеȴý½ø³Ì¶¼±»»½ÐÑ¡£µ«Ö»ÓÐÊ×Ïȵõ½¡± waking¡±µÄ½ø³Ì²ÅÄܵõ½ÐźÅÁ¿£¬¼ÌÐøÔËÐÐÏÂÈ¥£¬ÆäËû½ø³ÌÈÔÈ»»Øµ½×î³õµÄµÈ´ý״̬¡£

Linux¶¨ÒåÐźŵƽṹÊÇ£º
struct semaphore {
        atomic_t count;
        int waking;
        struct wait_queue * wait;
};
   ÐźŵƵÄÖµ³õʼ»¯ÎªÒ»¸öºê¶¨ÒåµÄ½á¹¹MUTEXµÄÖµ{count=1£¬waking=0£¬wait=NULL}¡£

void __up(struct semaphore *sem)£º
Õ¼ÓÐÁÙ½çÇø×ÊÔ´µÄ½ø³Ì£¬µ÷ÓÃ__up()ÊÍ·Å×ÊÔ´¡£ÔÚ__up()º¯ÊýÖУ¬µ÷ÓÃwake_one_more ()º¯Êý£¬Ô­×ӵضÁsem->count, Èç¹ûsem->count <=0,Ôòsem->waking ++,²¢»½ÐÑËùÓеȴýÔÚ¸Ãsem-->waitÉϵĽø³Ì¡£
void __up(struct semaphore *sem)
{
        wake_one_more(sem);
        wake_up(&sem->wait);
}


int __do_down(struct semaphore * sem, int task_state):
ÉêÇëÁÙ½çÇø×ÊÔ´µÄ½ø³Ì»áͨ¹ýµ÷ÓÃ__do_down()À´¾ºÕù×ÊÔ´¡£ÔÚ__do_down()º¯ÊýÖУ¬µ÷ÓÃwaking_non_zero(struct semaphore *sem)»òwaking_non_zero_interruptible(struct semaphore *sem)ÇÀÕ¼ÁÙ½çÇø×ÊÔ´£¬Èç¹ûÇÀÕ¼µ½£¬Ôò½«µ±Ç°½ø³ÌÖÃΪTASK_RUNNING,·ñÔò½«µ±Ç°½ø³ÌµÄ״̬ÖÃΪtask_state£¬²¢´¦ÓÚÑ­»·µÈ´ý״̬¡£
½ø³Ìͨ¹ýwaking_non_zero£¨£©À´¾ºÕùÁÙ½çÇø×ÊÔ´£¬Ôڸú¯ÊýÖÐÅжÏsem-->wakingµÄÖµ£¬Èç¹ûsem-->waking ´óÓÚ0,sem->waking -- ²¢·µ»Ø1£¬·ñÔò·µ»Ø0¡£
int __do_down(struct semaphore * sem, int task_state)
{
        struct task_struct *tsk = current;
        struct wait_queue wait = { tsk, NULL };
        int                  ret = 0 ;

        tsk->state = task_state;
        add_wait_queue(&sem->wait, &wait);  /*½«½ø³Ì¼ÓÈëµ½µÈ´ý¶ÓÁÐ*/

        for (;;)
        {
                if (waking_non_zero(sem))        /* ÊÇ·ñÒѾ­±»»½ÐÑ  */
                    break ;                            /* Êǵģ¬Ìø³öÑ­»· */

                if (   task_state == TASK_INTERRUPTIBLE
                    && (tsk->signal & ~tsk->blocked)
        /* Èç¹û½ø³Ì״̬ΪTASK_INTERRUPTIBLE£¬ÇÒÊÕµ½ÐźÅÁ¿£¬²¢Î´±»ÆÁ±Î*/
                   )
                {
                    ret = -EINTR ;                     /* ÖÐ¶Ï */
                    atomic_inc(&sem->count) ;        /* ·ÅÆúdown²Ù×÷£¬Ô­×ÓµÝÔöÐźÅÁ¿µÄcountÖµ */
                    break ;
                }

                schedule();                    /* ÖØÐµ÷¶È */
                tsk->state = task_state;      /*δÄܾºÕùµ½ÐźÅÁ¿µÄ½ø³ÌÖØÐÂÖóÉÖ´ÐÐdown²Ù
                                        ×÷ǰµÄ״̬*/
        }

        tsk->state = TASK_RUNNING;        /*¾ºÕùµ½ÐźÅÁ¿µÄ½ø³ÌÖÃΪTASK_RUNNING״̬*/
        remove_wait_queue(&sem->wait, &wait);/*½«½ø³Ì´ÓµÈ´ý¶ÓÁÐÖÐɾ³ý*/
        return(ret) ;

} /* __do_down */

ÆäÖÐ_do__down()ÓÖ·Ö±ðÓÉ__down()ºÍ__do_down()µ÷Ó㬽ø³Ìת»»µ½²»Í¬×´Ì¬¡£
void __down(struct semaphore * sem):    TASK_RUNNING ->TASK_UNINTERRUPTIBLE£»
void __down(struct semaphore * sem)
{
        __do_down(sem,TASK_UNINTERRUPTIBLE) ;
}

int __down_interruptible (struct semaphore * sem)£º TASK_RUNNING ->TASK_INTERRUPTIBLE;
int __down_interruptible(struct semaphore * sem)
{
        return(__do_down(sem,TASK_INTERRUPTIBLE)) ;
}

ÔÚLinuxÖж¨ÒåÁËÁ½ÖÖ²»Í¬µÄÐźŵƣº
£¨1£©¶¨ÒåÔÚij¸öÊý¾Ý½á¹¹ÉÏ£º
   ÔÚlinuxϵͳÖÐÓкܶàÊý¾Ý½á¹¹Öж¨ÒåÁËÕâÑùµÄÐźŵƣ¬À´¿ØÖƶÔÕâ¸öÊý¾Ý½á¹¹µÄ×ÊÔ´·ÃÎÊ£¬±ÈÈç²»ÔÊÐí¶Ôij¸öÄÚ´æµ¥Ôª½øÐÐ¶à½ø³Ì·ÃÎÊ£¬¾Íͨ¹ý¶¨ÒåÔÚ¸ÃÄÚ´æµ¥ÔªÉϵÄij¸öÐźŵÆmmap_sem½øÐÐ__up()¡¢_down()¡¢up()¡¢down()²Ù×÷¡£
È磺
struct mm_structÖÐÓÐmmap_semÐźŵƣ»
struct inodeÖÐÓÐi_sem¡¢i_atomic_writeÐźŵƣ»
struct nlm_fileÖÐÓÐf_semaÐźŵƣ»
struct nlm_hostÖÐÓÐh_semaÐźŵƣ»
struct superblockÖÐÓÐs_vfs_rename_semÐźŵƣ»
struct vfsmountÖÐÓÐmnt_dquot.semaphoreÐźŵƣ»
struct task_structÖÐÓÐvfork_semÐźŵƣ»//×¢£ºÕâ¸öÐźŵÆÔÚ2.0.36°æ±¾ÊÇûÓеģ¬Ð°汾2.2.8ÖвÅÓеģ¬ÓÃÓÚvfork()¡£
struct unix_optÖÐÓÐreadsemÐźŵƣ»
struct smb_sb_infoÖÐÓÐsemÐźŵƣ»
ÉêÇëÕâЩÊý¾Ý½á¹¹ÖеÄÁÙ½çÇø×ÊÔ´£¬¾ÍÒª½øÐÐÏàÓ¦µÄÐźŵƲÙ×÷¡£

£¨2£©¶¨ÒåÔÚÈ«¾ÖµÄµ¥¶ÀÐźŵÆÊý¾Ý£º
   »¹ÓÐһЩµ¥¶ÀµÄÈ«¾ÖÐźŵƣ¬ËüÃDz¢²»ÊôÓÚijһ¸öÊý¾Ý½á¹¹£¬¶øÊÇϵͳ¶¨ÒåµÄÈ«¾Ö¾²Ì¬µÄÐźŵƣ¬¿ÉÄÜÓжà¸ö½ø³Ì¶ÔÕâÖÖ²»ÊôÓÚij¸öÌØ¶¨Êý¾Ý½á¹¹µÄÈ«¾ÖÁÙ½ç×ÊÔ´µÄÉêÇ룬Ôòϵͳͨ¹ýÕâЩȫ¾ÖÐźŵÆÀ´·ÖÅä×ÊÔ´¡£
È磺
nlm_file_sema£»
nlmsvc_sema£»
lockd_start£»
read_sem£»
nlm_host_sema£»
read_semaphore£»
uts_sem
mount_sem£»
cache_chain_sem£»
rpciod_sema£»
rpciod_running£»
mfw_sema£»
firewall_sem£»

   ÎÒÃÇÀ´·ÖÎöÒ»¸öÀý×Ó˵Ã÷ÐźŵƵIJÙ×÷¡£ÀýÈç¶ÔÎļþµÄд²Ù×÷£¬ÎÒÃǼÙÉèÓÐÐí¶àЭ×÷µÄ½ø³Ì¶ÔÒ»¸öµ¥Ò»µÄÊý¾ÝÎļþ½øÐÐд²Ù×÷¡£ÎÒÃÇÏ£Íû¶ÔÎļþµÄ·ÃÎʱØÐëÑϸñµØÐ­µ÷¡£Òò´ËÕâÀï¾ÍÀûÓÃÁËinode½á¹¹É϶¨ÒåµÄÐźŵÆinode->i_sem¡£
ÔÚ /usr/src/linux/mm/filemap.cÖУº
static int filemap_write_page(struct vm_area_struct * vma,
        unsigned long offset,
        unsigned long page)
{
        int result;
        struct file file;
    struct inode * inode;
        struct buffer_head * bh;

        ¡­¡­¡­¡­¡­

        down(&inode->i_sem);
        result = do_write_page(inode, &file, (const char *) page, offset);
        up(&inode->i_sem);
        return result;
}

   ÔÚ¸ÃÎļþд²Ù×÷µÄ´úÂëÖУ¬¼ÓÈëÁ½¸öÐźŵƲÙ×÷£¬µÚÒ»¸ödown(&inode->i_sem)¼ì²é²¢°ÑÐźŵƵÄÖµ¼õС£¬µÚ¶þ¸öup(&inode->i_sem)¼ì²é²¢Ôö¼ÓËü¡£·ÃÎÊÎļþµÄµÚÒ»¸ö½ø³ÌÊÔͼ¼õСÐźŵƵÄÊýÖµ£¬Èç¹û³É¹¦£¬ÐźŵƵÄcountȡֵ³ÉΪ0¡£Õâ¸ö½ø³ÌÏÖÔÚ¿ÉÒÔ¼ÌÐøÔËÐв¢Ê¹ÓÃÊý¾ÝÎļþ¡£µ«ÊÇ£¬Èç¹ûÁíÒ»¸ö½ø³ÌÐèҪʹÓÃÕâ¸öÎļþ£¬ÏÖÔÚËüÊÔͼ¼õÉÙÐźŵƵÄcountÊýÖµ£¬Ëü»áʧ°ÜÒòΪ½á¹û»áÊÇ-1¡£Õâ¸ö½ø³Ì»á±»¹ÒÆðÖ±µ½µÚÒ»¸ö½ø³Ì´¦ÀíÍêÊý¾ÝÎļþ¡£µ±µÚÒ»¸ö½ø³Ì´¦ÀíÍêÊý¾ÝÎļþ£¬Ëü»áÔö¼ÓÐźŵƵÄwakingÊýÖµ³ÉΪ1¡£ÏÖÔڵȴý½ø³Ì»á±»»½ÐÑ£¬Õâ´ÎËü¼õСÐźŵƵij¢ÊÔ»á³É¹¦¡£

   ÿһ¸ö¶ÀÁ¢µÄÐźŵƲÙ×÷¿ÉÄܶ¼ÐèҪά»¤Ò»¸öµ÷Õû¶¯×÷¡£LinuxÖÁÉÙΪÿһ¸ö½ø³ÌµÄÿһ¸öÐźŵÆÊý×鶼ά»¤Ò»¸ösem_undoµÄÊý¾Ý½á¹¹¡£Èç¹ûÇëÇóµÄ½ø³ÌûÓУ¬¾ÍÔÚÐèÒªµÄʱºòΪËü´´½¨Ò»¸ö¡£Õâ¸öеÄsem_undoÊý¾Ý½á¹¹Í¬Ê±ÔÚ½ø³ÌµÄtask_structÊý¾Ý½á¹¹ºÍÐźŵƶÓÁеÄsemid_dsÊý¾Ý½á¹¹µÄ¶ÓÁÐÖÐÅŶӡ£¶ÔÐźŵƶÓÁÐÖеÄÐźŵÆÖ´ÐвÙ×÷µÄʱºò£¬ºÍÕâ¸ö²Ù×÷ÖµÏàµÖÏûµÄÖµ¼Óµ½Õâ¸ö½ø³ÌµÄsem_undoÊý¾Ý½á¹¹µÄµ÷Õû¶ÓÁÐÕâ¸öÐźŵƵÄÌõÄ¿ÉÏ¡£ËùÒÔ£¬Èç¹û²Ù×÷ֵΪ2£¬ÄÇôÕâ¸ö¾ÍÔÚÕâ¸öÐźŵƵĵ÷ÕûÌõÄ¿ÉÏÔö¼Ó-2¡£

   µ±½ø³Ì±»É¾³ý£¬±ÈÈçÍ˳öµÄʱºò£¬Linux±éÀúËüµÄsem_undoÊý¾Ý½á¹¹×飬²¢ÊµÊ©¶ÔÓÚÐźŵÆÊý×éµÄµ÷Õû¡£Èç¹ûɾ³ýÐźŵƣ¬ËüµÄsem_undoÊý¾Ý½á¹¹ÈÔ¾ÉÍ£ÁôÔÚ½ø³ÌµÄtask_struct¶ÓÁÐÖУ¬µ«ÊÇÏàÓ¦µÄÐźŵÆÊý×é±êʶ·û±ê¼ÇΪÎÞЧ¡£ÕâÖÖÇé¿öÏ£¬Çå³ýÐźŵƵĴúÂëÖ»ÊǼòµ¥µØ·ÏÆúÕâ¸ösem_undoÊý¾Ý½á¹¹¡£


3.Ëø»úÖÆ
   lock_¡­£¨£©£»
   unlock_¡­£¨£©£»
   wait_on_¡­£¨£©£ºTASK_RUNNING ->TASK_UNINTERRUPTIBLE£»
   ½ø³ÌÔÚRUNNING,WAITING״̬¼äת»»Ê±£¬Ëø»úÖÆÒ²ÊÇLinuxÖнâ¾ö½ø³ÌÖ®¼ä¹²Ïí×ÊÔ´µÄÒ»¸ö·½·¨¡£Ëø¾ÍÊÇÔÚ×ÊÔ´µÄ½á¹¹¶¨ÒåÖмÓÈëÒ»¸öËø³ÉÔ±£¬»òΪһ¸ö±ê־λ,ËüµÄȡֵ¿ÉÒÔÓɶà¸ö½ø³Ì¼ìÑéºÍÉèÖá£Ëø¿ÉÒÔÓÃÓÚʵÏÖ¶Ô×ÊÔ´µÄ¹²Ïí¾ºÕù¡£¾ßÌåÀ´Ëµµ±Ò»¸ö½ø³ÌÕ¼ÓÃÒ»¸ö×ÊԴʱ£¬ÏÈ¶ÔÆäÉÏËø£¬È»ºóÔÙ½øÐÐÏà¹ØµÄ²Ù×÷£¬Èç¹ûÕâʱ±ðµÄ½ø³ÌÒ²ÒªÓÃÕâ¸ö×ÊÔ´£¬Ôò±ØÐëµÈ´ýÕâ¸öËø±»½â¿ªºó£¬²Å¿ÉÒÔ½øÐÐÏÂÈ¥¡£
   µ«ÊÇ£¬Ëø½öÔÚijЩÊý¾Ý½á¹¹ºÍ×ÊÔ´ÉêÇëÖвŻáÓõ½£¬½ø³ÌÔÚÉêÇëijÖÖÌØ¶¨×ÊԴʱ£¬»áµ÷ÓÃÏàÓ¦µÄ__wait_on_¡­ º¯ÊýÀ´ÅжÏÊÇ·ñ¸Ã×ÊÔ´ÒѾ­±»ÉÏËø£¬Èç¹ûδÉÏËø»òÒѱ»½âËø£¬Ôò·ÖÅä×ÊÔ´¸ø½ø³Ì£¬·ñÔò½ø³Ì¼ÓÈëµ½µÈ´ý¶ÓÁÐÖÐÈ¥¡£ÕâÖÖÀàÐ͵ÄÉêÇëÓУº__wait_on_dquot¡¢__wait_on_buffer¡¢__wait_on_inode¡¢__wait_on_page¡¢__wait_on_superµÈ¡£
   ÖµµÃ×¢ÒâµÄÊÇ£¬Èç¹ûÉêÇë²»µ½ÕâÖÖ×ÊÔ´£¬½ø³ÌµÄ״̬¶¼ÊÇת±ä³ÉTASK_UNINTERRUPTIBLE¡£
   ¶¨ÒåËøµÄ·½Ê½ÓÐÁ½ÖÖ£º
רÃŵÄijÏîÊý¾Ý½á¹¹£º
È磺SuperblockµÄÊý¾Ý½á¹¹ÖÐרÃŶ¨ÒåÁËËøÊý¾ÝÏs_lock£»
ÖÃÊý¾Ý½á¹¹ÖÐijһÏîµÄij¸ö±êÖ¾Î»ÎªËø±êÖ¾£º
È磺
struct inodeÖж¨ÒåÁËi_stateµÄÊý¾ÝÏͨ¹ýÅжÏi_state ÊÇ·ñÖÃÁË I_LOCK£¬À´ÅжϸÃinode½ÚµãÊÇ·ñÉÏËø¡££¨2.2.8°æ±¾Öж¨Ò壩//×¢Ò⣺ÔÚ2.2.0.34°æ±¾ÖÐÊDzÉÓÃÁËרÃŵÄÊý¾ÝÏîi_lockÀ´½øÐÐËø²Ù×÷µÄ¡£
struct buffer_head Öж¨ÒåÁËb_stateµÄÊý¾ÝÏͨ¹ýÅжÏb_stateÊÇ·ñÖÃÁË BH_Lockλ,À´Åжϸûº³åÇøÍ·ÊÇ·ñÉÏËø¡£
struct dquotÖж¨ÒåÁËdq_flagsµÄÊý¾ÝÏͨ¹ýÅжÏdq_flagsÊÇ·ñÖÃÁËDQ_LOCKEDλ,À´ÅжϸÃdquotÊÇ·ñÉÏËø¡£
struct pageÖж¨ÒåÁËflagsµÄÊý¾ÝÏͨ¹ýÅжÏflagsÊÇ·ñÖÃÁËPG_locked λ,À´ÅжϸÃÒ³ÊÇ·ñÉÏËø¡£//×¢£º³ÌÐòÖÐÒ»°ã²ÉÓÃPageLocked(page)º¯ÊýÀ´ÅжÏÊÇ·ñÉÏËø¡£

   ÎÒÃÇÒÔbuffer_headµÄ¼ÓËøºÍ½âËø²Ù×÷ΪÀýÀ´½âÊÍÒ»ÏÂͨ¹ýËø»úÖÆ½øÐеÄ״̬ת»»£¬ÔÚÕâÀïÒªÉêÇëbuffer_head ×ÊÔ´£¬ÏÈÒªÉêÇëµ½Ëø£¬buffer_headµÄ¼ÓËøºÍ½âËø¾ÍÊÇͨ¹ýÖÃλºÍ¸´Î»bh->b_stateÀ´ÊµÏֵģº
//ÉêÇë×ÊԴʱ½«¸Ã»º³åÇøÉÏËø£¬ÖÃËøÎ»£¬Èç¹ûÉêÇë²»µ½£¬Ë¯ÃßÔڵȴý¶ÓÁÐÉÏ£¬µÈ´ý¸ÃËøµÄÊÍ·Å¡£
extern inline void lock_buffer(struct buffer_head * bh)
{
        while (set_bit(BH_Lock, &bh->b_state))
                __wait_on_buffer(bh);
}

//×ÊÔ´ÊÍ·Åʱ£¬Çå¸Ã»º³åÇøËøÎ»£¬²¢»½Ðѵȴý¶ÓÁÐÉϵĽø³Ì£¬²ÎÓ뾺Õù×ÊÔ´¡£
void unlock_buffer(struct buffer_head * bh)
{
        ......

        clear_bit(BH_Lock, &bh->b_state);
        wake_up(&bh->b_wait);
        ......
}

//¼ìÑé¸ÃËøÎ»ÊÇ·ñÒѾ­ÖÃλ
static inline int buffer_locked(struct buffer_head * bh)
{
        return test_bit(BH_Lock, &bh->b_state);
}

//ÔÚ \USR\SRC\LINUX\FS\BUFFER.CÖж¨ÒåÁË__wait_on_buffer(stuct buffer_head * bh);¸Ãº¯ÊýÅжϸÃbuffer_headÊÇ·ñÒѾ­±»ÉÏÁËËø£¬Èç¹ûÊÇ£¬Ôò²»Äܵõ½×ÊÔ´£¬½«½ø³ÌÖóÉTASK_UNINTERRUPTIBLE£¬¼ÓÈëbh-->b_wait¶ÓÁÐÖУ¬µ÷ÓÃschedule()תȥµ÷ÓÃÆäËûµÄ½ø³Ì£¬·ñÔò£¬·ÖÅ䏸×ÊÔ´£¬½ø³Ì½øÈëTASK_running״̬¡£
void __wait_on_buffer(struct buffer_head * bh)
{
        struct wait_queue wait = { current, NULL };

        bh->b_count++;
        add_wait_queue(&bh->b_wait, &wait);/*½ø³Ì¼ÓÈëµ½µÈ´ýËøµÄ¶ÓÁÐ*/
repeat:
        run_task_queue(&tq_disk);
        current->state = TASK_UNINTERRUPTIBLE;/*½ø³Ì״̬ÖÃΪTASK_UNINTERRUPTIBLE*/
        if (buffer_locked(bh)) {
                schedule();    /*Èç¹ûÉêÇë²»µ½Ëø£¬ÖØÐµ÷¶ÈCPU*/
                goto repeat;
        }
        remove_wait_queue(&bh->b_wait, &wait);/*½ø³Ì´ÓµÈ´ý¶ÓÁÐÖÐɾ³ý*/
        bh->b_count--;
        current->state = TASK_RUNNING; /*½ø³Ì״̬ÖÃΪTASK_ RUNNING*/
}


4. ¹ÜµÀ£¨Á÷£©
   ¹ÜµÀ×öΪϵͳµÄÌØÊâÉ豸Îļþ,¿ÉÒÔÊÇÄڴ淽ʽµÄ,Ò²¿ÉÒÔÊÇÍâ´æ·½Ê½µÄ¡£¹ÜµÀµÄ´«ÊäÒ»°ãÊǵ¥ÏòµÄ,¼´Ò»¸ö¹ÜµÀÒ»Ïò,ÈôÁ½¸ö½ø³ÌÒª×öË«Ïò´«ÊäÔòÐèÒª2¸ö¹ÜµÀ.¹ÜµÀÉú³Éʱ¼´ÓÐÁ½¶Ë,Ò»¶ËΪ¶Á,Ò»¶ËΪд,Á½¸ö½ø³ÌҪЭµ÷ºÃ,Ò»¸ö½ø³Ì´Ó¶Á·½¶Á,ÁíÒ»¸ö½ø³ÌÏòд·½Ð´¡£¹ÜµÀµÄ¶ÁдʹÓÃÁ÷É豸µÄ¶Áдº¯Êý,¼´:read(),write.¹ÜµÀµÄ´«Ê䷽ʽΪFIFO,Á÷·½Ê½µÄ.²»ÏóÏûÏ¢¶ÓÁпÉÒÔ°´ÀàÐͶÁÈ¡.¹ÜµÀ·ÖΪÓÐÃû¹ÜµÀºÍÎÞÃû¹ÜµÀ£º
1£® ÓÐÃû¹ÜµÀ
    Ò»°ãÎªÏµÍ³ÌØÊâÎļþ·½Ê½,ʹÓõĽø³ÌÖ®¼ä²»Ò»¶¨ÒªÓи¸×Ó¹ØÏµ»òÐֵܹØÏµ.
2£® ÎÞÃû¹ÜµÀ
    Ò»°ãΪÄڴ淽ʽ,ʹÓõĽø³ÌÖ®¼äÒ»¶¨ÒªÓи¸×Ó¹ØÏµ»òÐֵܹØÏµ.

  Linux shellÔÊÐíÖØ¶¨Ïò¡£ÀýÈ磺

  $ ls | pr | lpr

  °ÑÁгöĿ¼ÎļþµÄÃüÁîlsµÄÊä³öͨ¹ý¹ÜµÀ½Óµ½prÃüÁîµÄ±ê×¼ÊäÈëÉϽøÐзÖÒ³¡£×îºó£¬prÃüÁîµÄ±ê×¼Êä³öͨ¹ý¹ÜµÀÁ¬½Óµ½lprÃüÁîµÄ±ê×¼ÊäÈëÉÏ£¬ÔÚȱʡ´òÓ¡»úÉÏ´òÓ¡³ö½á¹û¡£¹ÜµÀÊǵ¥ÏòµÄ×Ö½ÚÁ÷£¬°ÑÒ»¸ö½ø³ÌµÄ±ê×¼Êä³öºÍÁíÒ»¸ö½ø³ÌµÄ±ê×¼ÊäÈëÁ¬½ÓÔÚÒ»Æð¡£Ã»ÓÐÒ»¸ö½ø³ÌÒâʶµ½ÕâÖÖÖØ¶¨Ïò£¬ºÍËüƽ³£Ò»Ñù¹¤×÷¡£ÊÇshell½¨Á¢Á˽ø³ÌÖ®¼äµÄÁÙʱ¹ÜµÀ¡£ÔÚLinuxÖУ¬Ê¹ÓÃÖ¸Ïòͬһ¸öÁÙʱVFS INODE½Úµã£¨±¾ÉíÖ¸ÏòÄÚ´æÖеÄÒ»¸öÎïÀíÒ³£©µÄÁ½¸öfileÊý¾Ý½á¹¹À´ÊµÏֹܵÀ¡£µ±Ð´½ø³ÌÏò¹ÜµÀÖÐдµÄʱºò£¬×Ö½Ú¿½±´µ½Á˹²ÏíµÄÊý¾ÝÒ³£¬µ±´Ó¹ÜµÀÖжÁµÄʱºò£¬×Ö½Ú´Ó¹²ÏíÒ³Öп½±´³öÀ´¡£Linux±ØÐëͬ²½¶ÔÓڹܵÀµÄ·ÃÎÊ¡£±ØÐë±£Ö¤¹ÜµÀµÄдºÍ¶Á²½µ÷Ò»Ö£¬ËüʹÓÃËø¡¢µÈ´ý¶ÓÁкÍÐźš£
        ÔËÓùܵÀ·½Ê½½øÐÐͨѶµÄ½ø³Ì£¬ÓÉÓÚ¶¼Êǵ÷ÓÃsleep_on_interruptible,Òò´Ë¶¼ÊÇ˯ÃßÔÚTASK_INTERRUPTIBLE״̬µÄ¡£

¹ÜµÀ½á¹¹µÄ¶¨ÒåÔÚinclude\linux\pipe_fs_i.hÖУ¬
struct pipe_inode_info {
        struct wait_queue * wait;
        char * base;
        unsigned int start;
        unsigned int len;
        unsigned int lock; //Óõ½ÁËËø
        unsigned int rd_openers;
        unsigned int wr_openers;
        unsigned int readers;
        unsigned int writers;
};

¶Ô¹ÜµÀµÄ²Ù×÷Ö÷ÒªÓжÁºÍдÁ½ÖÖ£º
1£®ÏòÒ»¸ö¹ÜµÀдpipe_write()£º
   ÔÚ\fs\pipe.cÖж¨ÒåÁËstatic int pipe_write(struct inode * inode, struct file * filp, const char * buf, int count)£»
ʵÏÖ»úÖÆ£ºµ±Ð´½ø³ÌÏò¹ÜµÀдµÄʱºò£¬ËüʹÓñê×¼µÄwrite¿âº¯Êý¡£ÕâЩ¿âº¯Êý´«µÝµÄÎļþÃèÊö·ûÊǽø³ÌµÄfileÊý¾Ý½á¹¹×éÖеÄË÷Òý£¬Ã¿Ò»¸ö¶¼±íʾһ¸ö´ò¿ªµÄÎļþ£¬ÔÚÕâÖÖÇé¿öÏ£¬ÊÇ´ò¿ªµÄ¹ÜµÀ¡£Linuxϵͳµ÷ÓÃʹÓÃÃèÊöÕâ¸ö¹ÜµÀµÄfileÊý¾Ý½á¹¹Ö¸ÏòµÄwriteÀý³Ì¡£Õâ¸öwriteÀý³ÌʹÓñíʾ¹ÜµÀµÄVFS INODE½Úµã´æ·ÅµÄÐÅÏ¢£¬À´¹ÜÀíдµÄÇëÇó¡£Èç¹ûÓÐ×ã¹»µÄ¿Õ¼ä°ÑËùÓеÄ×Ö½Ú¶¼Ð´µ¼¹Üµ½ÖУ¬Ö»Òª¹ÜµÀûÓб»¶Á½ø³ÌËø¶¨£¬LinuxΪд½ø³ÌÉÏËø£¬²¢°Ñ×Ö½Ú´Ó½ø³ÌµÄµØÖ·¿Õ¼ä¿½±´µ½¹²ÏíµÄÊý¾ÝÒ³¡£Èç¹û¹ÜµÀ±»¶Á½ø³ÌËø¶¨»òÕ߿ռ䲻¹»£¬µ±Ç°½ø³Ì˯Ãߣ¬²¢·ÅÔڹܵÀINODE½ÚµãµÄµÈ´ý¶ÓÁÐÖУ¬²¢µ÷Óõ÷¶È³ÌÐò£¬ÔËÐÐÁíÍâÒ»¸ö½ø³Ì¡£ËüÊÇ¿ÉÒÔÖжϵģ¬ËùÒÔËü¿ÉÒÔ½ÓÊÕÐźš£µ±¹ÜµÀÖÐÓÐÁË×ã¹»µÄ¿Õ¼äдÊý¾Ý»òÕßËø¶¨½â³ý£¬Ð´½ø³Ì¾Í»á±»¶Á½ø³Ì»½ÐÑ¡£µ±Êý¾ÝдÍêÖ®ºó£¬¹ÜµÀµÄVFS INODE ½ÚµãËø¶¨½â³ý£¬¹ÜµÀINODE½ÚµãµÄµÈ´ý¶ÓÁÐÖеÄËùÓжÁ½ø³Ì¶¼»á±»»½ÐÑ¡£

2£®´ÓÒ»¸ö¹ÜµÀ¶ÁPipe_read()£º
   ÔÚ\fs\pipe.cÖж¨ÒåÁËstatic int pipe_read(struct inode * inode, struct file * filp, char * buf, int count)£»
ʵÏÖ»úÖÆ£º´Ó¹ÜµÀÖжÁÈ¡Êý¾ÝºÍдÊý¾Ý·Ç³£ÏàËÆ¡£½ø³ÌÔÊÐí½øÐзÇ×èÈûµÄ¶Á£¨ÒÀÀµÓÚËüÃÇ´ò¿ªÎļþ»òÕ߹ܵÀµÄģʽ£©£¬Õâʱ£¬Èç¹ûûÓÐÊý¾Ý¿É¶Á»òÕ߹ܵÀ±»Ëø¶¨£¬»á·µ»ØÒ»¸ö´íÎó¡£ÕâÒâζ׎ø³Ì»á¼ÌÐøÔËÐС£ÁíÒ»ÖÖ·½Ê½ÊÇÔڹܵÀµÄINODE½ÚµãµÄµÈ´ý¶ÓÁÐÖеȴý£¬Ö±µ½Ð´½ø³ÌÍê³É¡£Èç¹û¹ÜµÀµÄ½ø³Ì¶¼Íê³ÉÁ˲Ù×÷£¬¹ÜµÀµÄINODE½ÚµãºÍÏàÓ¦µÄ¹²ÏíÊý¾ÝÒ³±»·ÏÆú¡£

½ø³ÌÔÚTASK_RUNNINGºÍTASK_STOPPED¼äµÄת»»£º
1£®½ø³Ì´ÓTASK_RUNNING->TASK_STOPPEDµÄת»»£º
TASK_STOPPED״̬ÊÇÒ»ÖÖÔÝͣ״̬£¬ºÍTASK_STOPPED״̬ÅäºÏ¹¤×÷µÄ±ê־ΪPF_PTRACEDºÍPF_TRACESYS£¬·Ö±ð±íʾ±»¸ú×ÙºÍÕýÔÚ¸ú×Ùϵͳµ÷Óã¬Ò»¸öÊDZ»¶¯µÄ£¬Ò»¸öÊÇÖ÷¶¯µÄ¡£
½ø³Ì¿Éͨ¹ýÁ½ÖÖ;¾¶½øÈëTASK_STOPPED״̬£º
1)£®ÊÜÆäËü½ø³ÌµÄsyscall_trace£¨£©ÏµÍ³µ÷ÓõĿØÖƶøÔÝʱ½«CPU½»¸ø¿ØÖƽø³Ì¡£
ÔÚµ÷ÓÃsyscall_trace£¨£©Ö®Ç°±ØÐëÏȵ÷ÓÃsys_ptrace()£¨¼ò³Æptrace£¨£©£©£¬½øÐиú×Ùϵͳµ÷ÓÃ֮ǰµÄ×¼±¸¹¤×÷¡£Ö»Óе÷ÓÃsys_ptrace()ºó£¬currentµÄPF_PTRACEDºÍPF_TRACESYS±êÖ¾¶¼ÒÑÖÃ룬¸ú×ٺͱ»¸ú×ٵĹØÏµ¶¼ÒÑÃ÷È·£¬ÔÙµ÷ÓÃsyscall_trace£¨£©²ÅÄÜÕæÕýʹ½ø³ÌתÈëSTOPPED״̬¡£
        syscall_trace£¨£©ÊµÏÖ²½Ö裺
£¨1£©¼ìÑéÊÇ·ñµ÷Óùýptrace£¨£©×ö¹ý×¼±¸£¬Ã»ÓÐÔò·µ»Ø£»
        £¨2£©ÖÃ״̬STOPPED £¬Í¨Öª¸¸½ø³Ì£¬×Ó½ø³Ì״̬Òѱ䣻
        £¨3£©½øÐÐCPUÖØÐµ÷¶È£¬½«current½ø³Ì´Órunqueueɾ³ý¡£
£¨4£©Èç¹ûexit_code·Ç¿Õ£¬½«ËüµÄÖµ×÷Ϊ½ÓÊÕµ½µÄÐźŷŵ½signalÖС£ÈôÊÇSIGTRAP
     Ôòcurrent½ø³Ì½«Ò»Ö±´¦ÓÚstopped£¬Ö±µ½ÊÕµ½ÆäËüÐźš£

sys_ptrace()ʵÏÖ²½Ö裺
£¨1£©Èç¹ûrequest == PTRACE_TRACEME£¬ÔòÓнø³ÌÒªÇó¸ú×Ùcurrent½ø³Ì:
                Èôcurrent½ø³ÌÒѱ»ÆäËü½ø³Ì¸ú×Ù·µ»Ø£»
    ·ñÔòÖÃcurrent½ø³ÌÒѱ»½ø³Ì¸ú×ٵıê¼Ç£»
£¨2£©Èç¹ûcurrent½ø³ÌÏë¸ú×ÙÆäËü½ø³Ì:
            a.²»Äܸú×Ùinit½ø³Ì£»
                b.ÕÒpid¶ÔÓ¦µÄ½ø³Ìchild£¬ÕÒ²»µ½·µ»Ø³ö´í£»
                c.Èç¹ûrequestΪPTRACE_ATTACH
    Èç¹ûcurrent½ø³ÌÊÔͼATTACH×Ô¼º£¬³ö´í£»
                Èç¹ûÊÔͼattachµÄ½ø³ÌchildÒѱ»attach£¬³ö´í£»
                ·ñÔò        child->flags |= PF_PTRACED;×öÉϱê¼Ç£¬childÒѱ»attach£»Èç¹ûchild
    ²»ÊÇcurrentµÄ×Ó½ø³Ì£¬½«Ëü±ä³ÉcurrentµÄ×Ó½ø³Ì£»²¢ÇÒ·¢SIGSTOPÐźţ¬ÔÝ
    Í£Ëü¡£
£¨3£©½øÐÐÆäËûºÏ·¨ÐÔ¼ì²é£»
    £¨4£©ÅжÏrequest£¬Ö´ÐÐÏàÓ¦²Ù×÷£º
                case PTRACE_SYSCALL:¼ÌÐøÖ´ÐУ¬ÔÚÏÂÒ»¸öϵͳµ÷Ó÷µ»Ø´¦Í£Ï¡£
    case PTRACE_CONT:·¢ÐźźóÖØÐ¿ªÊ¼ÔËÐС£
                        Èç¹ûrequest == PTRACE_SYSCALL£¬ÖÃchild±ê־λPF_TRACESYS;
                        ·ñÔò        Çåchild±ê־λPF_TRACESYS£¬ÒÔ·ÀÖ¹ÖØÐÂÔËÐкóÒòÀúÊ·Ô­ÒòÔÚÏÂÒ»¸ö
        ϵͳµ÷Ó÷µ»Ø´¦Í£Ï£»
                        »½ÐÑchild½ø³Ì¡£
          case PTRACE_KILL: ÏëÒª½áÊøchild½ø³Ì£¬»½ÐÑchild½ø³Ì£¬²¢ÔÚÍ˳öÐÅÏ¢
                      exit_codeÖдæ·ÅSIGKILLÐźš£
                case PTRACE_SINGLESTEP:  ½øÐе¥²½ÔËÐл·¾³ÉèÖá£
                case PTRACE_DETACH: »Ö¸´child½ø³ÌµÄ×ÔÓÉ¡£Çå¸ú×Ù±êÖ¾£¬²¢»½ÐÑchild½ø³Ì                                        »Ö¸´child½ø³ÌµÄԭʼÇ×Êô¹ØÏµ¡£

2)£®ÊÕµ½ÒªÇóËüÔÝÍ£µÄÐźš£
ÁíÒ»ÖÖ½øÈëSTOPPED״̬µÄ·½·¨ÊÇÐźţ¬SIGSTOPÐźÅʹ×ÔÓɵÄcurrent½ø³Ì£¬´òÉÏPF_PTRACED±ê¼Ç£¬²¢½«ËüתÈëSTOPPED״̬¡£do_signalÔÚ¼ì²é½ø³ÌÊÕµ½µÄÐźÅʱ£¬Èô·¢ÏÖcurrent½ø³ÌÒÑ´òÉÏPF_PTRACED±ê¼Ç£¬Ôò³ýÊÕµ½µÄSIGKILLÐźŵÄÇé¿öÍ⣬current½ø³Ì¶¼½«ÂíÉϽøÈëSTOPPED״̬¡£
do_signal£¨£©ÊµÏÖ²½Ö裺
£¨1£©current½ø³ÌÒÑ´òÉÏPF_PTRACED±ê¼Ç£¬Ôò³ýÊÕµ½µÄSIGKILLÐźŵÄÇé¿öÍ⣬½ø³Ì¶¼½«½øÈëTASK_STOPPED״̬£¬Í¨Öª¸¸½ø³Ì£¬²¢ÖØÐµ÷¶È£»
        £¨2£©Èç¹ûÊÕµ½ÐźÅSIGSTOP:Èç¹ûµ±Ç°½ø³Ì±ê־λ²»ÊÇPF_PTRACED£¬ÔòÖõ±Ç°½ø³Ì״̬ΪTASK_STOPPED; ֪ͨ¸¸½ø³Ì£¬²¢ÖØÐµ÷¶È£»

2.½ø³Ì´ÓTASK_STOPPED->TASK_RUNNINGµÄת»»:
´ÓTASK_STOPPED״̬תµ½TASK_RUNNING״̬ͨ¹ý¡°ÐźŻ½ÐÑ¡±¡£µ±ÓÐSIGKILL»òSIGCONTÐźŷ¢¸øTASK_STOPPED״̬ϵĽø³Ìʱ£¬½ø³Ì½«±»wake_up_process()»½ÐÑ¡£
int send_sig(unsigned long sig,struct task_struct * p,int priv)
{
        ¡­¡­¡­;
        save_flags(flags); cli();   /*±£´æ±êÖ¾£¬¹ØÖжÏ*/
        if ((sig == SIGKILL) || (sig == SIGCONT)) {
                if (p->state == TASK_STOPPED)
                        wake_up_process(p);     /*Èô½ø³ÌpµÄ״̬ÊÇSTOPPED£¬²¢ÇÒËù·¢Ë͵ÄÐźÅÊÇSIGKILLºÍSIGCONT£¬½«p״̬¸³³ÉRUNNING£¬²¢¹Òµ½run-queue*/
p->exit_code = 0;      /*Í˳öÐÅϢûÓÐ*/
                p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) |
                                (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) );         /*´¦Àí¹ýÐźź󣬽«pµÄ¿ÉÄÜÔø½ÓÊܵ½µÄSIGSTOP¡¢SIGTSTP¡¢SIGTTIN¡¢SIGTTOUÐźÅÇåµô*/
        }
        if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
                p->signal &= ~(1<<(SIGCONT-1));     /*ÈôÐźÅΪSIGSTOP¡¢SIGTSTP¡¢SIGTTIN¡¢SIGTTOUÖеÄÈÎÒ»ÖÖ£¬½«p¿ÉÄÜÔø½ÓÊܵ½µÄSIGCONTÐźÅÇåµô*/
        restore_flags(flags);          /*»Ö¸´CPU±ê־ͬʱ´ò¿ªÖжÏ*/
        generate(sig,p);     /*µÇ¼Ç²»ÄÜÁ¢¼´±»´¦ÀíµÄÐźš£*/
        return 0;
}

½ø³ÌµÄÖÕÖ¹:´ÓTASK_RUNNING->TASK_ZOMBIEµÄת»»
½ø³ÌÖÕÖ¹ÓÉ¿ÉÖÕÖ¹½ø³ÌµÄϵͳµ÷ÓÃͨ¹ýµ÷ÓÃdo_exit£¨£©ÊµÏÖ£¬do_exit£¨£©ÖÕÖ¹current½ø³Ì£¬Ê×ÏÈΪcurrent½ø³Ì×öÉÏPF_EXITINGµÄ±ê¼Ç£¬ÊÍ·Åcurrent½ø³ÌµÄ´æ´¢¹ÜÀíÐÅÏ¢¡¢Îļþϵͳ¡¢ÎļþÐÅÏ¢¡¢ÐźÅÏìÓ¦º¯ÊýÖ¸ÕëÊý×飬½«×´Ì¬ÖóÉTASK_ZOMBIE£¬Í¨ÖªcurrentµÄ¸¸½ø³Ì£¬×îºó½øÐÐÖØÐµ÷¶È¡£do_exit()´øÒ»¸ö²ÎÊýcode£¬ÓÃÓÚ´«µÝÖÕÖ¹½ø³ÌµÄÔ­Òò¡£

do_exit(long code)Á÷³Ì£º
    £¨1£©Èç¹û½ø³ÌÔÚÖжϷþÎñ³ÌÐòÖе÷ÓÃdo_exit£¨£©£¬Ôò´òÓ¡ÌáʾÐÅÏ¢
    £¨2£©¼Ç¼½ø³ÌµÄ¼ÇÕÊÐÅÏ¢
    £¨3£©½ø³Ì±êÖ¾ÖÃΪPF_EXITING
£¨4£©ÊͷŶ¨Ê±Æ÷Á´±í
        £¨5£©ÊÍ·ÅÁÙ½çÇøÊý¾Ý
        £¨6£©½«ÏûÏ¢¶ÓÁÐÖкÍcurrent½ø³ÌÓйØÏîɾ³ý
        £¨7£©ÊͷŽø³ÌµÄ´æ´¢¹ÜÀíÐÅÏ¢
        £¨8£©ÊͷŽø³ÌÒÑ´ò¿ªÎļþµÄÐÅÏ¢
        £¨9£©ÊͷŽø³ÌµÄÎļþϵͳ
        £¨10£©ÊͷŽø³ÌµÄÐźÅÏìÓ¦º¯ÊýÖ¸ÕëÊý×éµÈ¹ÜÀíÐÅÏ¢
          £¨11£©ÊͷŽø³ÌµÄLDT
        £¨12£©½ø³Ì״̬ÖÃΪTASK_ZOMBIE
        £¨13£©ÖÃÉÏÍ˳öÐÅÏ¢£¬Í¨ÖªËùÓнø³ÌÇ×ÆÝ£¬ËüÒªÍ˳öÁË#
        £¨14£©exec_domain½á¹¹¹²Ïí¼ÆÊý¼õ1£¬ binfmt½á¹¹¹²Ïí¼ÆÊý¼õ1
£¨15£©ÖØÐµ÷¶È£¬½«current½ø³Ì´Órun-queueÖÐɾ³ý£¬½»³öCPU

exit_notify £¨£©º¯ÊýÏòËùÓкÍcurrent½ø³ÌÓйصĽø³Ì·¢ÏàÓ¦µÄÏûÏ¢£¬ÒÔ±ãËüÃÇ¿ªÕ¹¹¤×÷£¬exit_notify £¨£©»¹ÅжÏcueernt½ø³ÌËùÔÚ×éÊÇ·ñ»áÒòcurrent½ø³ÌµÄÍ˳ö¶øÐü¿Õ£¬Èç¹ûÐü¿Õ²¢ÇÒ×éÄÚÓÐstopped״̬µÄ½ø³ÌÔò·¢Ðźţ»Í¬Ê±½øÐÐһϵÁеÄÖ¸Õëµ÷Õû£¬µ÷ÕûÒòcurrent½ø³ÌµÄËÀÍöÒýÆðµÄ½ø³Ì¹ØÏµ×ª±ä¡£
exit_notify £¨£©Á÷³Ì£º
½«ËùÓÐԭʼ½ø³ÌΪcurrentµÄ½ø³Ì±ä³Éinit½ø³ÌµÄËï×Ó¡£
Èç¹û¸¸½ø³ÌºÍcurrent½ø³Ì²»ÔÚͬһ×飬µ«ÔÚͬһsessionÄÚ²¢ÇÒcurrent½ø³Ì×éÄÚËùÓнø³ÌµÄ¸¸½ø³ÌºÍËüÔÚͬһ×飬Ҳ¾ÍÊÇ˵£¬current½ø³ÌËùÔÚ×é»áÒòcurrentµÄÍ˳ö¶øÐü¹Ò£¬Í¬Ê±current½ø³ÌËùÔÚ×éÄÚÓÐstopped½ø³Ì£¬¾ÍÏòÕû¸ö×é·¢SIGHUPºÍSIGCONTÐźš£
֪ͨ¸¸½ø³Ì½ø³ÌËÀÁË¡£
µ÷ÕûËùÓÐcurrent½ø³ÌµÄ×Ó½ø³ÌµÄ¸¸½ø³ÌÖ¸Õ룬½«ËüÃǹҵ½ËüÃǵÄԭʼ½ø³ÌÏ£¬
     ½«ÒÔÍùµÄ¸ú×Ù±»¸ú×ÙÀúÊ·Çå³ý£¬µ÷ÕûËüºÍеÄÐֵܵĹØÏµ£»¼ì²éÿһ¸öcurrent
     ½ø³ÌµÄ×Ó½ø³ÌËùÔÚµÄ×éÊÇ·ñ»áÐü¹Ò£¬Èç¹û×Ó½ø³ÌºÍcurrent½ø³Ì²»ÔÚͬһ×飬²¢
     ÇÒÕâ¸ö×éÒÑÐü¹Ò£¬×éÄÚÓÐstoppedµÄ½ø³Ì£¬¾ÍÏò×éÔ±·¢SIGHUP ºÍ SIGCONTÐźš£        £¨5£©Èç¹ûcurrent½ø³ÌÊÇsessionµÄÖ÷¹Ü£¬ ¾ÍºÍËüËù¿ØÖƵÄttyÍÑÀ룬Ïòcurrent
     ½ø³ÌÏÔʾÖÕ¶ËËùÔÚµÄ×é·¢SIGHUP ºÍ SIGCONTÐźš£


½ø³ÌÖ±½Ó»ò¼ä½ÓµØµ÷ÓÃdo_exit() ºó£¬½ø³Ì½øÈëZOMBIE״̬£¬»¹ÓÐÒ»¿éPCBδÊÍ·Å¡£PCBµÄÊͷűØÐëÓÉËüµÄ¸¸½ø³ÌÖ´ÐУ¬µ±¸¸½ø³Ìµ÷ÓÃsys_wait4£¨£©Ê±ÊͷŽøÈëZOMBIE״̬µÄ×Ó½ø³ÌµÄPCB¡£

¾ßÌåµ÷ÓÃdo_exit()µÄº¯ÊýÓÐÒÔÏÂÇé¿ö£º
¾ßÌå¶ÔÓ¦µÄϵͳµ÷Óóö´í£¬²»µÃ²»ÖÕÖ¹½ø³Ì£¬È磺
do_page_fault£¨£©£ºÕâ¸öϵͳµ÷Óô¦ÀíÒ³Ãæ´íÎó£¬ËüÕÒµ½Ò³ÃæµØÖ·£¬³ö´íÔ­Òò£¬²¢½«ËüתÈëÏàÓ¦µÄ´¦Àíº¯Êý¡£µ±·¢ÉúÔ½½ç£¨out of memory£©µÈbad pageµÄÖÂÃü´íÎó¡£

sys_sigreturn£¨£©£ºÒ»°ãÇé¿öÏÂsys_sigreturn£¨£©½«sigcontextµÄÄÚÈݱ£´æµ½¶ÑÕ»ÖУ¬±£´æ¹ý³ÌÖе±·¢ÏֶμĴæÆ÷Ô½½çÁË£¬Õâ¸öÖÂÃü´íÎó¾Í½«µ¼Ö½ø³Ì½áÊø¡£

setup_frame£¨£©£ºsetup_frame£¨£©½¨Á¢ÐźÅÏìÓ¦º¯ÊýµÄÔËÐеĻ·¾³£¬±£´æµ±Ç°¼Ä´æÆ÷£¬½«ÏàÓ¦¼Ä´æÆ÷¸³ÉÏÐźÅÏìÓ¦º¯ÊýµÄÐÅÏ¢¡£ÔÚ¾ßÌåÉ趨֮ǰÊ×ÏȽøÐд洢Ìõ¼þ¼ìÑ飬²»Âú×ã¾Í²»µÃ²»½áÊø½ø³Ì¡£

save_v86_state£¨£©£ºsave_v86_state£¨£©±£´æÐéÄâ86ģʽÏ£¨virtual 86 mode£©µÄÐÅÏ¢£¬Èç¹û½ø³ÌPCBÖÐvm86µÄÐÅϢΪ¿ÕµÄ£¬ÎÞ·¨¼ÌÐø½øÐвÙ×÷£¬Ö»ÄܽáÊø½ø³Ì¡£

£¨2£©ÆäËûÖÕÖ¹½ø³ÌµÄÇé¿ö£¬Í¨¹ýµ÷ÓÃÒÔϺ¯ÊýʵÏÖÖÕÖ¹£º
sys_exit£¨£©£ºÊÇÒ»¸öϵͳµ÷Óã¬ÊµÏÖÖÕÖ¹µ÷ÓÃËüµÄµ±Ç°½ø³Ì¡£

sys_reboot()£ºsys_reboot()Ö»Äܱ»ÌØÈ¨¼¶Óû§µ÷Óã¬ÓÃÓÚÖØÐÂÆô¶¯ÏµÍ³¡£

do_signal£¨£©£ºdo_signal£¨£©ÊÇ´¦ÀíÐźŵÄÒ»¸öº¯Êý¡£¼ì²écurrent½ø³Ìÿһ¸ö½ÓÊÕµ½µÄsignal£¬Èç¹ûÊǽáÊø½ø³ÌµÄÐźţ¬½áÊø½ø³Ì½øÐÐÏàÓ¦´¦Àí¡£

die_if_kernel£¨£©¡£

[Ŀ¼]


Ïß³Ì

1        ¸ÅÊö
1.1        Ï̵͍߳Òå(Introduction)
Threads can best be described as ¡°lightweight processes¡±. The traditional UNIX-style notion of a process has been found to be inconvenient, if not inadequate for several applications in distributed systems development. The needs of these applications are best served by threads, which generalize the notion of a process so that it can be associated with multiple activities. The popularity of threads has resulted in their implementation on UNIX systems and thread libraries are now widely available to programmers for the development of concurrent applications.

1.2        Threads Implementation
Threads can be implemented in one of two ways:
1. User-level threads:
There is no kernel support for multi-threaded processes. Hence, the kernel only has a single-threaded process abstraction, but multi-threaded processes are implemented in a library of procedures linked with application programs. The kernel has no knowledge of lightweight processes (threads), and therefore cannot schedule them independently. A threads run-time library organizes the scheduling of threads. A thread would block the process and therefore all threads within it if it made a blocking system call, so the asynchronous I/O facilities of UNIX are used. The major disadvantage of this scheme is that threads within a process cannot take advantage of a multi-processor.
£¨É϶ÎÒëÎÄ£©User-levelûÓкËÐÄÖ§³ÖµÄ¶àÏ̵߳Ľø³Ì¡£Òò´Ë£¬ºËÐÄÖ»Óе¥Ï߳̽ø³Ì¸ÅÄ¶ø¶àÏ߳̽ø³ÌÓÉÓëÓ¦ÓóÌÐòÁ¬½ÓµÄ¹ý³Ì¿âʵÏÖ¡£ºËÐIJ»ÖªµÀÏ̵߳ĴæÔÚ£¬Ò²¾Í²»ÄܶÀÁ¢µÄµ÷¶ÈÕâЩÏß³ÌÁË¡£Ò»¸öÏß³ÌÔËÐпâ×éÖ¯Ï̵߳ĵ÷¶È¡£Èç¹ûÒ»¸öÏ̵߳÷ÓÃÁËÒ»¸ö×èÈûµÄϵͳµ÷Ó㬽ø³Ì¿ÉÄܱ»×èÈû£¬µ±È»ÆäÖеÄËùÓÐÏß³ÌҲͬʱ±»×èÈû£¬ËùÒÔUNIXʹÓÃÁËÒì²½I/O¹¤¾ß¡£ÕâÖÖ»úÖÆµÄµÄ×î´óȱµãÊDz»ÄÜ·¢»Ó¶à´¦ÀíÆ÷µÄÓÅÊÆ¡£
The advantages include:
£¨ÏµÍ³ÏûºÄС£©Certain thread operations are significantly less costly. For example, switching between threads belonging to the same process do not necessarily involve a system call, and hence save this over-head.
£¨¿ÉÒÔÐÞ¸ÄÒÔÊÊÓ¦ÌØÊâµÄÓ¦Óã©User-level thread implementations can be customized or changed to suit the particular application requirements. This is particularly useful for real-time multimedia processing etc. Also, it is possible to support many more user-level threads than can by default by a kernel.
2. Kernel-level threads:
This implementation allows threads within different processes to be scheduled according to a single scheme of relative prioritizing. This is suited for exploiting the concurrence of multiprocessors.
ºËÐļ¶Ïß³ÌÈçÐí²»Í¬½ø³ÌÀïµÄḬ̈߳´ÕÕͬһÏà¶ÔÓÅÏÈ·½·¨µ÷¶È£¬ÕâÊʺÏÓÚ·¢»Ó¶à´¦ÀíÆ÷µÄ²¢·¢Óŵ㡣
Most of the current thread library implementations available today implement user-level threads. There have been several research projects that have implemented some form of Kernel-level threads. Notable among these are the Mach distributed OS, which combines the advantages of user-level and kernel-level threads by allowing user-level code to provide scheduling hints to the kernel thread scheduler. By providing such a two-level scheduling scheme, the kernel retains control over the allocation of processor time, but also allows a process to take advantage of multiple processors.

1.3        Thread Libraries
The two most widely used thread libraries are POSIX and Solaris thread libraries. Both implementations are inter-operable, their functionality is similar, and can be used within the same application. However, only POSIX threads are guaranteed to be fully portable to other POSIX-compliant environments.
Similarities:
Most of the functions in both libraries, libpthread and libthread, have a counterpart in the other library. POSIX functions and Solaris functions, whose names have similar endings, usually have similar functionality, number of arguments, and use of arguments. All POSIX threads function names begin with the prefix pthread? where as the Solaris threads function names begin with the prefix thr?
Differences:
POSIX
is more portable
establishes characteristics for each thread according to configurable attribute objects
implements thread cancellation
enforces scheduling algorithms
allows for clean-up handlers for fork(2) calls
Solaris
threads can be suspended and continued
implements an optimized mutex, readers/writer locking
may increase the concurrency
implements daemon threads, for whose demise the process does not wait


1.4        Threads Standards
There are three different definitions for thread libraries competing for attention today: Win32, OS/2, and POSIX. The first two are proprietary and limited to their individual platforms (Win32 threads run only under NT and Win95, OS/2 threads on OS/2). The POSIX specification (IEEE 1003.1c, aka Pthreads) is intended for all computing platforms, and implementations are available or in the works for almost all major UNIX systems (including Linux), along with VMS.

POSIX Threads
The POSIX standard defines the API and behavior that all the Pthreads libraries must meet. It is part of the extended portion of POSIX, so it is not a requirement for meeting XPG4, but it is required for X/Open UNIX 98, and all major UNIX vendors have committed to meeting this standard. As of this writing, (7/97) almost all UNIX vendors have released a library.

Win32 and OS/2 Threads
Both the NT and OS/2 implementations contain some fairly radical differences
from the POSIX standard--to the degree that even porting from one or the other
to POSIX will prove moderately challenging. Microsoft has not announced any
plans to adopt POSIX. There are freeware POSIX libraries for Win32 (see
Commercial Products on page 249), and OS/2 also has an optional POSIX library.

DCE Threads
Before POSIX completed work on the standard, it produced a number of drafts which it published for comment. Draft 4 was used as the basis for the threads library in DCE. It is similar to the final spec, but it does contain a number of significant differences. Presumably, no one is writing any new DCE code.

Solaris Threads
Also known as UI threads, this is the library, which SunSoft used in developing Solaris 2 before the POSIX, committee completed their work. It will be available on Solaris 2 for the foreseeable future, although we expect most applications writers will opt for Pthreads. The vast majority of the two libraries are virtually identical.
1.5        LinuxÏ̵߳Ä˼Ïë¼°ÌØµã
1.5.1        LinuxThreads
http://pauillac.inria.fr/~xleroy/linuxthreads
Xavier Leroy at INRIA (Paris, France), with input from Pavel Krauz, Richard Henderson and others, has developed a Pthreads library that implements the One-to-One model, allowing it to take advantage of multiple processors. It is based on the new Linux system call, clone()2 . It runs on Linux 2.0 and up, on Intel, Alpha, SPARC, m68k, and MIPS machines. One limitation is its non-standard implementation of signal handling.
1.5.2        Implementation model for LinuxThreads
LinuxThreads follows the so-called "one-to-one" model: each thread is actually a separate process in the kernel. The kernel scheduler takes care of scheduling the threads, just like it schedules regular processes. The threads are created with the Linux clone() system call, which is a generalization of fork() allowing the new process to share the memory space, file descriptors, and signal handlers of the parent.
LinuxThreads²ÉÓóÆÎª1-1Ä£ÐÍ£ºÃ¿¸öÏß³Ìʵ¼ÊÉÏÔÚºËÐÄÊÇÒ»¸ö¸öµ¥¶ÀµÄ½ø³Ì£¬ºËÐĵĵ÷¶È³ÌÐò¸ºÔðÏ̵߳ĵ÷¶È£¬¾ÍÏóµ÷¶ÈÆÕͨ½ø³Ì¡£Ïß³ÌÊÇÓÃϵͳµ÷ÓÃclone()´´½¨µÄ£¬clone()ϵͳµ÷ÓÃÊÇfork()µÄÆÕ±éÐÎʽ£¬ËüÔÊÐíнø³Ì¹²Ïí¸¸½ø³ÌµÄ´æ´¢¿Õ¼ä¡¢ÎļþÃèÊö·ûºÍÈíÖжϴ¦Àí³ÌÐò¡£
Advantages of the "one-to-one" model include:

Minimal overhead on CPU-intensive multiprocessing (with about one thread per processor); ×îСÏÞ¶ÈÏûºÄµÄCPU¼¶¶à´¦Àí¼¼Êõ£¨Ã¿¸öCPUÒ»¸öỊ̈߳©£»
Minimal overhead on I/O operations; ×îСÏÞ¶ÈÏûºÄµÄI/O²Ù×÷£»
A simple and robust implementation (the kernel scheduler does most of the hard work for us)£»Ò»ÖÖ¼òµ¥ºÍǿ׳µÄʵÏÖ£¨ºËÐĵ÷¶È³ÌÐòΪÎÒÃÇ×öÁ˴󲿷ּèÄѵŤ×÷£©¡£

The main disadvantage is more expensive context switches on mutex and condition operations, which must go through the kernel. This is mitigated by the fact that context switches in the Linux kernel are pretty efficient.

1.5.3        Consider other implementation models

There are basically two other models. The "many-to-one" model relies on a user-level scheduler that context-switches between the threads entirely in user code; viewed from the kernel, there is only one process running. This model is completely out of the question for me, since it does not take advantage of multiprocessors, and require unholy magic to handle blocking I/O operations properly. There are several user-level thread libraries available for Linux, but I found all of them deficient in functionality, performance, and/or robustness.
»¹ÓÐÁíÍâÁ½ÖÖ»ù±¾Ä£ÐÍ¡£¶à¶ÔһģÐÍÒÀÀµÓÚÓû§¼¶µÄµ÷¶È³ÌÐò£¬Ïß³ÌÇл»ÍêÈ«ÓÉÓû§³ÌÐòÍê³É£»´ÓºËÐĽǶȿ´£¬Ö»ÓÐÒ»¸ö½ø³ÌÕýÔÚÔËÐС£ÕâÖÖÄ£ÐͲ»ÊÇÎÒÃÇËù¹ØÐĵģ¬ÒòΪËüÎÞ·¨ÀûÓöദÀíÆ÷µÄÓŵ㣬¶øÇÒÒªÓò»ºÏÀíµÄ·½·¨´¦ÀíI/O²Ù×÷×èÈû¡£
The "many-to-many" model combines both kernel-level and user-level scheduling: several kernel-level threads run concurrently, each executing a user-level scheduler that selects between user threads. Most commercial Unix systems (Solaris, Digital Unix and IRIX) implement POSIX threads this way. This model combines the advantages of both the "many-to-one" and the "one-to-one" model, and is attractive because it avoids the worst-case behaviors of both models -- especially on kernels where context switches are expensive, such as Digital Unix. Unfortunately, it is pretty complex to implement, and requires kernel supporting which Linux does not provide. Linus Torvalds and other Linux kernel developers have always been pushing the "one-to-one" model in the name of overall simplicity, and are doing a pretty good job of making kernel-level context switches between threads efficient. LinuxThreads is just following the general direction they set.
2        LinuxºËÐĶÔÏ̵߳ÄÖ§³Ö
LinuxºËÐĶÔÏ̵߳ÄÖ§³ÖÖ÷ÒªÊÇͨ¹ýÆäϵͳµ÷Óã¬ÏÂÎĽ«½øÐÐϵͳµÄ½éÉÜ¡£
2.1        ϵͳµ÷ÓÃclone()
ÒÔÏÂÊÇϵͳµ÷ÓÃcloneµÄ´úÂ룺
asmlinkage int sys_clone(struct pt_regs regs)
{
        unsigned long clone_flags;
        unsigned long newsp;

        clone_flags = regs.ebx;
        newsp = regs.ecx;
if (!newsp)
                newsp = regs.esp;
        return do_fork(clone_flags, newsp, &regs);
}

Óëϵͳµ÷ÓÃclone¹¦ÄÜÏàËÆµÄϵͳµ÷ÓÃÓÐfork,µ«forkÊÂʵÉÏÖ»ÊÇcloneµÄ¹¦ÄܵÄÒ»²¿·Ö£¬cloneÓëforkµÄÖ÷񻂿±ðÔÚÓÚ´«µÝÁ˼¸¸ö²ÎÊý£¬¶øµ±ÖÐ×îÖØÒªµÄ²ÎÊý¾ÍÊÇconle_flags,ϱíÊÇϵͳ¶¨ÒåµÄ¼¸¸öclone_flags±êÖ¾£º
±êÖ¾        Value        º¬Òå
CLONE_VM        0x00000100        ÖÃÆð´Ë±êÖ¾ÔÚ½ø³Ì¼ä¹²ÏíVM
CLONE_FS        0x00000200        ÖÃÆð´Ë±êÖ¾ÔÚ½ø³Ì¼ä¹²ÏíÎļþϵͳÐÅÏ¢
CLONE_FILES        0x00000400        ÖÃÆð´Ë±êÖ¾ÔÚ½ø³Ì¼ä¹²Ïí´ò¿ªµÄÎļþ
CLONE_SIGHAND        0x00000800        ÖÃÆð´Ë±êÖ¾ÔÚ½ø³Ì¼ä¹²ÏíÐźŴ¦Àí³ÌÐò
Èç¹ûÖ