brpc 中 bthread 协程切换测试用例

bthread 中借用 boost 实现协程间的切换,下面的 x86_64 测试用例简单的将嵌汇编和 C++ 代码融合到了一起,测试下协程切换栈的过程。aarch64 测试用例只需要把嵌汇编代码换了就行,都是原封不动的抄的 boost 里协程实现的 make_fcontext 和 jump_fcontext 两个 S 文件。

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <iostream>

typedef void *bthread_fcontext_t;

extern "C" bthread_fcontext_t bthread_make_fcontext(void *sp, size_t size,
void (*fn)(intptr_t));
__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"
".previous\n");

extern "C" intptr_t bthread_jump_fcontext(bthread_fcontext_t *ofc,
bthread_fcontext_t nfc, intptr_t vp);
__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"
" movq %rsp, (%rdi)\n"
" movq %rsi, %rsp\n"
" leaq 0x8(%rsp), %rsp\n"
" popq %r12 \n"
" popq %r13 \n"
" popq %r14 \n"
" popq %r15 \n"
" popq %rbx \n"
" popq %rbp \n"
" popq %r8\n"
" movq %rdx, %rax\n"
" movq %rdx, %rdi\n"
" jmp *%r8\n"
".size bthread_jump_fcontext,.-bthread_jump_fcontext\n"
".section .note.GNU-stack,\"\",%progbits\n"
".previous\n");

bthread_fcontext_t fcm;
bthread_fcontext_t fc;

typedef std::pair<int, int> pair_t;
static void f(intptr_t param) {
pair_t *p = (pair_t *)param;
printf("In Routine: fcm %p fc %p\n", fcm, fc);

p = (pair_t *)bthread_jump_fcontext(&fc, fcm,
(intptr_t)(p->first + p->second));

printf("In Routine Again: fcm %p fc %p\n", fcm, fc);
bthread_jump_fcontext(&fc, fcm, (intptr_t)(p->first + p->second));
}

int main() {
fcm = NULL;
std::size_t size(8192);
void *sp = malloc(size);

pair_t p(std::make_pair(2, 7));
fc = bthread_make_fcontext((char *)sp + size, size, f);

printf("Start Routine: fcm %p fc %p\n", fcm, fc);
int res = (int)bthread_jump_fcontext(&fcm, fc, (intptr_t)&p);
printf("Back to Main: %d + %d = %d\n", p.first, p.second, res);

p = std::make_pair(5, 6);
printf("Resume Routine: fcm %p fc %p\n", fcm, fc);
res = (int)bthread_jump_fcontext(&fcm, fc, (intptr_t)&p);
printf("Back to Main Again: %d + %d = %d\n", p.first, p.second, res);

return 0;
}
1
2
3
4
5
6
7
8
lhx@ubuntu:~/test$ g++ -g brpc_bthread_test.cpp 
lhx@ubuntu:~/test$ ./a.out
Start Routine: fcm (nil) fc 0x5654fcb19e68
In Routine: fcm 0x7ffe13ee5570 fc 0x5654fcb19e68
Back to Main: 2 + 7 = 9
Resume Routine: fcm 0x7ffe13ee5570 fc 0x5654fcb19e40
In Routine Again: fcm 0x7ffe13ee5570 fc 0x5654fcb19e40
Back to Main Again: 5 + 6 = 11