Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1255573
  • 博文数量: 404
  • 博客积分: 10011
  • 博客等级: 上将
  • 技术积分: 5382
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-03 16:29
文章存档

2010年(40)

2009年(140)

2008年(224)

我的朋友

分类: LINUX

2009-04-20 13:28:46

Linux2.6 使用了软件来实现进程切换,忽略了Intel X86架构提供的硬件切换机制。
为什么要使用软件切换?
1)可控制性更大。硬件切换仅仅用jump far即可,而软件切换需要一系列的判断和mov
2)性能差不多。软件可优化的余地更大。
进程切换发生在switch()函数中。切换主要包括用户空间(pgd)和运行上下文(hardware context和堆栈等)的切换。
这里要谈的switch_to就是实现运行上下文的切换的。
#define switch_to(prev, next, last)                    \
do {                                    \
    /*                                \
     * Context-switching clobbers all registers, so we clobber    \
     * them explicitly, via unused output variables.        \
     * (EAX and EBP is not listed because EBP is saved/restored    \
     * explicitly for wchan access and EAX is the return value of    \
     * __switch_to())                        \
     */                                \
    unsigned long ebx, ecx, edx, esi, edi;                \
                                    \
    asm volatile("pushfl\n\t"        /* save    flags */    \
             "pushl %%ebp\n\t"        /* save    EBP   */    \
             "movl %%esp,%[prev_sp]\n\t"    /* save    ESP   */ \
             "movl %[next_sp],%%esp\n\t"    /* restore ESP   */ \
             "movl $1f,%[prev_ip]\n\t"    /* save    EIP   */    \
             "pushl %[next_ip]\n\t"    /* restore EIP   */    \
                                        //压入堆栈,因为下面调用的是jmp,而在__switch_to中采用ret返回,则返回地址就变成了[next_ip],也就是进程next的标号为1处,进入next执行。
             "jmp __switch_to\n"    /* regparm call  */    \
             "1:\t"                        \
             "popl %%ebp\n\t"        /* restore EBP   */    \
             "popfl\n"            /* restore flags */    \
                                    \
             /* output parameters */                \
             : [prev_sp] "=m" (prev->thread.sp),        \
               [prev_ip] "=m" (prev->thread.ip),        \
               "=a" (last),                    \  //将eax写入到last中
                                    \
               /* clobbered output registers: */        \
               "=b" (ebx), "=c" (ecx), "=d" (edx),        \
               "=S" (esi), "=D" (edi)                \
                                           \
               /* input parameters: */                \
             : [next_sp]  "m" (next->thread.sp),        \
               [next_ip]  "m" (next->thread.ip),        \
                                           \
               /* regparm parameters for __switch_to(): */    \
               [prev]     "a" (prev),                \  //将prev读入到eax中
               [next]     "d" (next));                \
} while (0)
在schedule中经常这样调用
switch_to(prev,next,prev)
设想这样一种情景:
A切换到B,则切换完成后。A的内核堆栈中
prev=A,next=B
现从进程C切换到进程A:
切换前:
C: prev=C,next=A
A: prev=A,next=B
切换(C的内核堆栈):
prev -> eax               eax中存放的是C
切换完成(A的进程堆栈)
要将eax值写入prev,得:
C:prev=C,next=A
A:prev=C,next=B
prev,next都是schedule中的局部变量。进程总是在schedule中让出处理器。切换后新进程运行的第一条指令总是:
"1:\t"                        \
             "popl %%ebp\n\t"        /* restore EBP   */    \
             "popfl\n"            /* restore flags */    \
因此prev,next在进程sleep的时候会在内核堆栈中保持

文章出处:
阅读(633) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~