Switching of implementation of cooperative process

Switching of implementation of cooperative process

Question: how to switch the context of a collaboration? How is the switch code implemented?

Let's first review x86_64 register related knowledge. X86_ The 64 registers have 16 64 bit registers, which are:%rax,%rbx,%rcx,%esi,%edi,%rbp,%rsp,%r8,%r9,%r10,%r11,%r12,
%r13, %r14, %r15.
%rax is used as the return value of the function.
%rsp stack pointer register, pointing to the top of the stack
%RDI,%rsi,%rdx,%rcx,%r8,%r9 are used as function parameters, corresponding to the first parameter, the second parameter in turn...
%RBX,%rbp,%r12,%r13,%r14,%r15 are used as data stores and follow the rules of the caller. In other words, they are used casually. Back up a child function before calling it to prevent it from being modified
%R10 and R11 are used as data storage, that is, the original value must be saved before use.

Context switching is to save the CPU registers temporarily, and then mov the context registers of the running coroutines to the corresponding registers. The context switch is now complete. As shown in the following figure:

switch_ switch function definition:

int _switch(nty_cpu_ctx *new_ctx, nty_cpu_ctx *cur_ctx);

Parameter 1: the context of the coroutine to be run, register list
Parameter 2: context of running coroutine, register list
We nty_ CPU_ The definition of CTX structure. In order to be compatible with x86, the structure item command is named by the register name of x86.

typedef struct _nty_cpu_ctx {
    void *esp; //
    void *ebp;
    void *eip;
    void *edi;
    void *esi;
    void *ebx;
    void *r1;
    void *r2;
    void *r3;
    void *r4;
    void *r5;
} nty_cpu_ctx;

_The After the switch returns, execute the context of the collaboration to be run. Context switching

_The Implementation code of switch:

0: __asm__ (
1: "    .text                                  \n"
2: "       .p2align 4,,15                                   \n"
3: ".globl _switch                                          \n"
4: ".globl __switch                                         \n"
5: "_switch:                                                \n"
6: "__switch:                                               \n"
7: "       movq %rsp, 0(%rsi)      # save stack_pointer     \n"
8: "       movq %rbp, 8(%rsi)      # save frame_pointer     \n"
9: "       movq (%rsp), %rax       # save insn_pointer      \n"
10: "       movq %rax, 16(%rsi)                              \n"
11: "       movq %rbx, 24(%rsi)     # save rbx,r12-r15       \n"
12: "       movq %r12, 32(%rsi)                              \n"
13: "       movq %r13, 40(%rsi)                              \n"
14: "       movq %r14, 48(%rsi)                              \n"
15: "       movq %r15, 56(%rsi)                              \n"
16: "       movq 56(%rdi), %r15                              \n"
17: "       movq 48(%rdi), %r14                              \n"
18: "       movq 40(%rdi), %r13     # restore rbx,r12-r15    \n"
19: "       movq 32(%rdi), %r12                              \n"
20: "       movq 24(%rdi), %rbx                              \n"
21: "       movq 8(%rdi), %rbp      # restore frame_pointer  \n"
22: "       movq 0(%rdi), %rsp      # restore stack_pointer  \n"
23: "       movq 16(%rdi), %rax     # restore insn_pointer   \n"
24: "       movq %rax, (%rsp)                                \n"
25: "       ret                                              \n"
26: );

Per x86_ 64,%rdi saves the value of the first parameter, that is, new_ctx value,%rsi saves the value of the second parameter, that is, cur_ The value of CTX. X86_ 64 each register is 64bit, 8byte.
Movq%rsp, 0 (%rsi) saved from stack pointer to cur_ RSP item of CTX instance
Movq %rbp, 8(%rsi)
Movq (%rsp),%rax \x stores the value in the stack top address in the rax register. Exit the stack after Ret and execute the top of the stack
Movq%rbp, 8 (%rsi) \_ In each item of CTX
Movq 8 (%rdi),%rbp \_ Value of CTX
Movq 16 (%rdi),%rax \x store the value of instruction pointer rip in rax
Movq%rax, (%rsp) \r \q assigns the rax register of the stored rip value to the value of the address of the stack pointer.
Ret \n \s exit the stack, return to the stack pointer, and execute the instruction pointed to by rip.
The context switching is completed.

Unfinished to be continued~

Tags: C Java C++ Go Back-end

Posted by tmyonline on Tue, 31 May 2022 23:41:54 +0530