打印
[其他ST产品]

ST源码分析-st_thread_create - 弦外之音

[复制链接]
楼主: 9dome猫
手机看帖
扫描二维码
随时随地手机跟帖
21
9dome猫|  楼主 | 2023-4-21 12:23 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
上面的代码,ST_KEYS_MAX 等于 16,(void *) 在 32位占 4字节,在 64 位占 8字节。所以上面的代码逻辑是 从之前申请的内存里面拿出 16 * 8 个字节的内存 存储协程的私有数据,这块内存在 ST 代码里没有使用,是留给使用者自由发挥的。想存什么就存什么变量 ptds 的全称是 private_data,ptds 指向数据的开始地址。

sp = sp - sizeof(_st_thread_t);
thread = (_st_thread_t *) sp;

使用特权

评论回复
22
9dome猫|  楼主 | 2023-4-21 12:23 | 只看该作者
再 从 之前申请的内存里面拿出 sizeof(_st_thread_t) 大小的内存来存储 _st_thread_t 协程。

/* Make stack 64-byte aligned */
if ((unsigned long)sp & 0x3f)
  sp = sp - ((unsigned long)sp & 0x3f);
stack->sp = sp - _ST_STACK_PAD_SIZE;

使用特权

评论回复
23
9dome猫|  楼主 | 2023-4-21 12:25 | 只看该作者
上面的代码就是把 sp 做 64位对齐,最后 再拿走 _ST_STACK_PAD_SIZE 大小的内存,_ST_STACK_PAD_SIZE 等于 128 。

使用特权

评论回复
24
9dome猫|  楼主 | 2023-4-21 12:25 | 只看该作者
上面全部代码执行完之后,栈的内存布局如下:

使用特权

评论回复
25
9dome猫|  楼主 | 2023-4-21 12:25 | 只看该作者
从上图可以看出,stack->stk_bottom ~ stack->stk_sp 中间的空白区域,这块区域 是 协程函数局部变量用的。

使用特权

评论回复
26
9dome猫|  楼主 | 2023-4-21 12:25 | 只看该作者
继续 分析 st_thread_create() 的后续代码逻辑。

memset(thread, 0, sizeof(_st_thread_t));
memset(ptds, 0, ST_KEYS_MAX * sizeof(void *));

/* Initialize thread */
thread->private_data = ptds;
thread->stack = stack;
thread->start = start;
thread->arg = arg;

使用特权

评论回复
27
9dome猫|  楼主 | 2023-4-21 12:26 | 只看该作者
上面这些都是 变量操作,初始化逻辑,跳过,继续看下面代码。

_ST_INIT_CONTEXT(thread, stack->sp, _st_thread_main);

使用特权

评论回复
28
9dome猫|  楼主 | 2023-4-21 12:26 | 只看该作者
_ST_INIT_CONTEXT 实际上就是 MD_INIT_CONTEXT,我的环境是 Linux + x86_64,所以MD_INIT_CONTEXT 宏定义如下:

#define MD_INIT_CONTEXT(_thread, _sp, _main) \
  ST_BEGIN_MACRO                             \
  if (MD_SETJMP((_thread)->context))         \
    _main();                                 \
  MD_GET_SP(_thread) = (long) (_sp);         \
  ST_END_MACRO

使用特权

评论回复
29
9dome猫|  楼主 | 2023-4-21 12:26 | 只看该作者
_ST_INIT_CONTEXT 实际上就是 MD_INIT_CONTEXT,我的环境是 Linux + x86_64,所以MD_INIT_CONTEXT 宏定义如下:

#define MD_INIT_CONTEXT(_thread, _sp, _main) \
  ST_BEGIN_MACRO                             \
  if (MD_SETJMP((_thread)->context))         \
    _main();                                 \
  MD_GET_SP(_thread) = (long) (_sp);         \
  ST_END_MACRO

使用特权

评论回复
30
9dome猫|  楼主 | 2023-4-21 12:31 | 只看该作者
_st_md_cxt_save 函数的汇编实现如下:

.globl _st_md_cxt_save
        .type _st_md_cxt_save, @function
        .align 16
_st_md_cxt_save:
        /*
         * Save registers.
         */
        movq %rbx, (JB_RBX*8)(%rdi)
        movq %rbp, (JB_RBP*8)(%rdi)
        movq %r12, (JB_R12*8)(%rdi)
        movq %r13, (JB_R13*8)(%rdi)
        movq %r14, (JB_R14*8)(%rdi)
        movq %r15, (JB_R15*8)(%rdi)
        /* Save SP */
        leaq 8(%rsp), %rdx
        movq %rdx, (JB_RSP*8)(%rdi)
        /* Save PC we are returning to */
        movq (%rsp), %rax
        movq %rax, (JB_PC*8)(%rdi)
        xorq %rax, %rax
        ret
        .size _st_md_cxt_save, .-_st_md_cxt_save

使用特权

评论回复
31
9dome猫|  楼主 | 2023-4-21 12:31 | 只看该作者
回到 MD_SETJMP((_thread)->context) 这里的 context 是一个 jmp_buf 的结构, jmp_buf 是操作系统提供的

使用特权

评论回复
32
9dome猫|  楼主 | 2023-4-21 12:31 | 只看该作者
为了理清楚 MD_SETJMP((_thread)->context) 这句代码干了什么事情,需要一步一步分析。

MD_SETJMP((_thread)->context) 等于 _st_md_cxt_save(env),_st_md_cxt_save 是一个汇编函数,之前没有讲过 汇编函数,如果传参,这个参数是怎么压进去堆栈,寄存器又是如何变换,现在就用 gdb 演示一次。

使用特权

评论回复
33
9dome猫|  楼主 | 2023-4-21 12:48 | 只看该作者
命令如下:

gdb ./obj/lookupdns
# 设置参数
set args xianwaizhiyin.net www.baidu.com
# 断点 1
b *st_thread_create
# 断点 2
b sched.c:588
# 查看 寄存器
layout regs
# 查看 C 源码
layout src
# 查看 汇编 源码
layout asm
# 打印地址
print &(thread->context)

使用特权

评论回复
34
9dome猫|  楼主 | 2023-4-21 12:49 | 只看该作者

使用特权

评论回复
35
9dome猫|  楼主 | 2023-4-21 12:49 | 只看该作者
如上图所示,在调 callq 之前 ,rax 跟 rdi 的值 就是 thread->context 的内存地址。所以参数 env 是通过 rdi 寄存器传进去给 _st_md_cxt_save 函数用的。

使用特权

评论回复
36
chenho| | 2023-4-21 21:25 | 只看该作者
ptds 的全称应该是 pthread_data_register

使用特权

评论回复
37
langgq| | 2023-4-21 21:26 | 只看该作者
sp 的全称 是啥

使用特权

评论回复
38
chenho| | 2023-4-21 21:28 | 只看该作者
stack point

使用特权

评论回复
39
langgq| | 2023-4-21 21:30 | 只看该作者
用什么获取操作系统的内存页大小

使用特权

评论回复
40
dingy| | 2023-4-21 21:31 | 只看该作者
langgq 发表于 2023-4-21 21:30
用什么获取操作系统的内存页大小

getpagesize()

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则