bthread源码分析(五)上下文和栈实现

Context

context是bthread的上下文,提供上下文初始化和上下文切换功能

源码位置:bthread/context.h bthread/context.cpp

接口api

1

2

3

4

5

6

7

8

9

10

11

12

13

// 上下文切换,从ofc切换到nfc

intptr_t BTHREAD_CONTEXT_CALL_CONVENTION bthread_jump_fcontext(

    bthread_fcontext_t * ofc,

    bthread_fcontext_t nfc,

    intptr_t vp,

    bool preserve_fpu = false);

 

 

// 上下文初始化

bthread_fcontext_t BTHREAD_CONTEXT_CALL_CONVENTION bthread_make_fcontext(

    void* sp,   // 栈顶指针

    size_t size,// 栈长度

    void (* fn)( intptr_t)); // 栈初始化函数

x86_64下接口实现

bthread_make_fcontext:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

__asm (

".text\n"

".globl bthread_make_fcontext\n"

".type bthread_make_fcontext,@function\n"

".align 16\n"

"bthread_make_fcontext:\n"

"    movq  %rdi, %rax\n"

"    andq  $-16, %rax\n"

"    leaq  -0x48(%rax), %rax\n"

"    movq  %rdx, 0x38(%rax)\n"

"    stmxcsr  (%rax)\n"

"    fnstcw   0x4(%rax)\n"

"    leaq  finish(%rip), %rcx\n"

"    movq  %rcx, 0x40(%rax)\n"

"    ret \n"

"finish:\n"

"    xorq  %rdi, %rdi\n"

"    call  _exit@PLT\n"

"    hlt\n"

".size bthread_make_fcontext,.-bthread_make_fcontext\n"

".section .note.GNU-stack,\"\",%progbits\n"

);

该函数执行完成后,栈如图

其中,栈顶保存finish函数的地址,finish函数中调用_exit(),sp - 0x08位置保存用户函数指针fn。由于寄存器惯例约定保存6个寄存器,因此预留6个64-bit,这样可以和上下文切换逻辑保持一致。将sp-0x48作为新的%rsp返回调用者,调用者保存此指针用于上下文切换作为bthread_jump_fcontext的参数

bthread_jump_fcontext:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

__asm (

".text\n"

".globl bthread_jump_fcontext\n"

".type bthread_jump_fcontext,@function\n"

".align 16\n"

"bthread_jump_fcontext:\n"

"    pushq  %rbp  \n"

"    pushq  %rbx  \n"

"    pushq  %r15  \n"

"    pushq  %r14  \n"

"    pushq  %r13  \n"

"    pushq  %r12  \n"

"    leaq  -0x8(%rsp), %rsp\n"

"    cmp  $0, %rcx\n"

"    je  1f\n"

"    stmxcsr  (%rsp)\n"

"    fnstcw   0x4(%rsp)\n"

"1:\n"

"    movq  %rsp, (%rdi)\n"  // 用ofc指针保存当前bthread的%rsp,用于下次从其他bthread切换回来使用

"    movq  %rsi, %rsp\n"    // 恢复nfc地址到rsp寄存器中

"    cmp  $0, %rcx\n"

"    je  2f\n"

"    ldmxcsr  (%rsp)\n"     // 恢复之前保存的MXCSR寄存器

"    fldcw  0x4(%rsp)\n"    // 恢复之前保存的FPU控制字

"2:\n"

"    leaq  0x8(%rsp), %rsp\n"   // rsp加0x8,跳过MXCSR和FPU

"    popq  %r12  \n"            // 恢复%r12寄存器,下同

"    popq  %r13  \n"

"    popq  %r14  \n"

"    popq  %r15  \n"

"    popq  %rbx  \n"

"    popq  %rbp  \n"

"    popq  %r8\n"               // 将之前保存的%rip恢复到r8,即上次发生上下文切换时此bthread的下一条指令地址

"    movq  %rdx, %rax\n"        // 将第3个参数vp保存到%rax

"    movq  %rdx, %rdi\n"        // 将第3个参数vp保存到%rdi用于下一个函数调用的第一个参数

"    jmp  *%r8\n"               // 跳转到%r8的函数地址,即之前的%rip,到这里完成一次上下文切换

".size bthread_jump_fcontext,.-bthread_jump_fcontext\n"

".section .note.GNU-stack,\"\",%progbits\n"

);

Stack

bthread当前实现提供三种大小类型的栈,分别为32K、1M、8M,默认使用1M大小的栈。bthread通过mmap分配page大小对齐的栈空间,并在底部通过mprotect将一段4096字节大小的空间设置为不可访问,目的是防止栈溢出。stack从bottom开始创建上下文,如图:

stack设计为工厂模式,根据提供的参数获取对应stack

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值