之前有写过一个协程库,用的是libco的context_swap.s作为协程切换,为了了解与ucontext的区别,去读了源码进行了解。
#include <sysdep.h>
#include "ucontext_i.h"
/* 这个函数的功能是获得当前协程(或者此时还不能称为协程)的上下文将他存入参数中 */
ENTRY(__getcontext)
/* 4(%esp)就是函数所提供参数的地址,将他赋值给eax */
movl 4(%esp), %eax
/* 将eax的值作为0传入 */
movl $0, oEAX(%eax)
/* 下面是一系列将寄存器内容保存的操作,这些寄存器参数与libco相同 */
movl %ecx, oECX(%eax)
movl %edx, oEDX(%eax)
movl %edi, oEDI(%eax)
movl %esi, oESI(%eax)
movl %ebp, oEBP(%eax)
movl (%esp), %ecx
/* eip存入的是esp的内容,因为esp未动过所以一直指向的是返回地址 */
movl %ecx, oEIP(%eax)
leal 4(%esp), %ecx /* Exclude the return address. */
/* esp并非真正的栈顶位置,取出时需要进行修改,这个在libco中也是同样的实现 */
movl %ecx, oESP(%eax)
movl %ebx, oEBX(%eax)
/* FS寄存器指向当前活动线程的TEB结构(线程结构)libco中并未保存此寄存器 */
xorl %edx, %edx
movw %fs, %dx
movl %edx, oFS(%eax)
/* 这是设置浮点计数器,libco中舍弃了浮点计数器,因为浮点数在服务器中使用不多 */
leal oFPREGSMEM(%eax), %ecx
movl %ecx, oFPREGS(%eax)
/* Save the floating-point context. */
fnstenv (%ecx)
/* And load it right back since the processor changes the mask.
Intel thought this opcode to be used in interrupt handlers which
would block all exceptions. */
fldenv (%ecx)
/* 这是保存当前线程信号屏蔽掩码,这里会有系统调用在性能上有所损耗,这也是libco优化的一个点 */
pushl %ebx
cfi_adjust_cfa_offset (4)
cfi_rel_offset (ebx, 0)
leal oSIGMASK(%eax), %edx
xorl %ecx, %ecx
movl $SIG_BLOCK, %ebx
movl $__NR_sigprocmask, %eax
ENTER_KERNEL
popl %ebx
cfi_adjust_cfa_offset (-4)
cfi_restore (ebx)
cmpl $-4095, %eax /* Check %eax for error. */
jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */
/* All done, return 0 for success. */
xorl %eax, %eax
ret
PSEUDO_END(__getcontext)
weak_alias (__getcontext, getcontext)