免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1169 | 回复: 0
打印 上一主题 下一主题

linux2.6.29 swtich_to 详细分析(二) [复制链接]

论坛徽章:
2
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:57:09
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-05-05 08:53 |只看该作者 |倒序浏览
内敛汇编版本的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\n" /* regparm call  */ \
       "1:\t"      \
       "popl %%ebp\n\t"  /* restore EBP   */ \
       "popfl\n"   /* restore flags */ \
         \
       /* output parameters */                       \
       : [prev_sp] "=m" (prev->thread.sp),  \
       /*m表示把变量放入内存,即把[prev_sp]存储的变量放入内存,最后再写入prev->thread.sp*/\
         [prev_ip] "=m" (prev->thread.ip),  \
         "=a" (last),                                           \
         /*=表示输出,a表示把变量last放入ax,eax = last*/         \
         \
         /* clobbered output registers: */  \
         "=b" (ebx), "=c" (ecx), "=d" (edx),  \
         /*b 变量放入ebx,c表示放入ecx,d放入edx,S放入si,D放入edi*/\
         "=S" (esi), "=D" (edi)    \
                \
         /* input parameters: */    \
       : [next_sp]  "m" (next->thread.sp),  \
       /*next->thread.sp 放入内存中的[next_sp]*/\
         [next_ip]  "m" (next->thread.ip),  \
                \
         /* regparm parameters for __switch_to(): */ \
         [prev]     "a" (prev),    \
         /*eax = prev  edx = next*/\
         [next]     "d" (next)    \
         \
       : /* reloaded segment registers */   \
   "memory");     \
} while (0)


标准汇编版本的switch_to:
1 把prev和next分别保存在寄存器中,即寄存器传参
movl prev,%eax
movl next,%edx

2 把eflags和ebp保存在当前的堆栈中
pushfl
pushl %ebp

3 把esp的内容保存到prev->thread.esp中,以使该字段指向prev内核栈的栈顶
movl %esp,484(%eax)
注:484(%eax) ,表示内存但愿的地址=(%eax) + 484

4 把next->thread.sp装入esp,内核开始在next的指令空间中操作,这条指令完成了进程之间的切换。
可以会想thread_info数据结构,内核栈和进程描述符组成的8K的数据结构
movl 484(%edx),%esp

5 把标记为1f的地址存入prev->thread.eip,即被替换出的进程在下次被schedule()选择执行时,从这条指令开始执行
movl $1f,480(%eax)

6 把next->thread.eip(绝大多数情况是一个被标记为1的地址)的值压入next的内核栈
pushl 480(%edx)

7 跳到__swtich_to() c语言函数开始执行
jmp __swtich_to

8 这里被进程next替换的进程prev再次获得CPU:它执行一些保存eflags和ebp的寄存器内容指令,这两条指令的第一条指令被标记为1(这是《深入理解unix》书上说的)。感觉从__swtich_to返回时ip已经指向了next的第一条指令,因为在执行ret指令的时候,把sp处保存的next->ip弹出赋给了next的eip,所以书上说prev再次获得cpu应该是不对的。
1:
    pop %ebp
    popfl

从标号1:开始已经进入了next的指令空间,可以这么理解1:就是next进程的第一条指令,执行


    pop %ebp
    popfl
后完成了最后的切换,即栈和状态字的恢复,恢复成next的堆栈基址和状态字。

个人理解:linux里面的每个进程(新创建的进程除外)的第一条指令应该都是
1:
    pop %ebp
    popfl
每个进程一开始全是执行这两条指令,之后才各自干自己的事去
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP