打印
[其他ST产品]

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

[复制链接]
楼主: 9dome猫
手机看帖
扫描二维码
随时随地手机跟帖
61
9dome猫|  楼主 | 2023-4-21 23:20 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
上面的 Save SP 就是把 rsp+8 然后保存进去 jmf_buf 里面,为什么要加 8 ?rsp + 8 就是没 call _st_md_cxt_save 函数之前的 rsp 的值,因为 call 会把 rsp 减 8 字节。这里 保存 rsp+8 的值,应该是多余的,因为会被后面的 MD_GET_SP(thread) = (long) (stack->sp); 覆盖掉。

使用特权

评论回复
62
9dome猫|  楼主 | 2023-4-21 23:20 | 只看该作者
然后再把 rsp 的值 保存到 jmf_buf 。PC 是 Program Counter 的缩写,用于指示当前将要执行的下一条机器指令的内存地址 ,也就是 EIP 寄存器。

使用特权

评论回复
63
9dome猫|  楼主 | 2023-4-21 23:20 | 只看该作者
此时此刻 rsp ~ rsp +8 这 8 字节内存,存的是什么呢?存的是 调 call 的上层函数的下一条指令的位置,在 C代码里面就是 下面的 if 判断 返回值,

if (MD_SETJMP((_thread)->context)) 。

使用特权

评论回复
64
9dome猫|  楼主 | 2023-4-21 23:20 | 只看该作者
因为 执行完 call 之后要跳回调上层调用下一行指令的位置,这个位置 就存在 rsp ~ rsp +8 这 8 字节内存 里面。如下图:

使用特权

评论回复
65
9dome猫|  楼主 | 2023-4-21 23:20 | 只看该作者

使用特权

评论回复
66
9dome猫|  楼主 | 2023-4-21 23:20 | 只看该作者
上图,是刚刚用 si 跳进去 call 里面,call 指令已经执行了,但是里面的指令还没执行,此时此刻 0x7fffffffde88 ~ 0x7fffffffde90 存的就是 st_thread_create 函数的下一条指令。

使用特权

评论回复
67
9dome猫|  楼主 | 2023-4-21 23:21 | 只看该作者
保存好这些东西 进去 jmp_buf 之后,就会操作 rax 搞返回值 ,如下:

xorq %rax, %rax
上面这句代码是异或操作,只是把 rax 搞成 0 ,并没有什么特别。

使用特权

评论回复
68
9dome猫|  楼主 | 2023-4-21 23:21 | 只看该作者
_st_md_cxt_save 执行完了,回调之前的 宏函数 。由于 MD_SETJMP 把 rax 搞成 0 ,所以下面的 _main() 并不会执行。那 _main() 什么时候执行呢?这里先简单剧透一下,在 _st_md_cxt_restore() 函数里面会把 rax 设置 为 1 ,再跳回到这个 if 判断。因为 MD_SETJMP 已经把 if 代码的指令地址 存进去 jmp_buf里面了,所以可以跳回来。

使用特权

评论回复
69
9dome猫|  楼主 | 2023-4-21 23:21 | 只看该作者
#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

使用特权

评论回复
70
9dome猫|  楼主 | 2023-4-21 23:21 | 只看该作者
所以上面的代码, if 执行之后,只会执行 下面这句代码。

MD_GET_SP(_thread) = (long) (_sp);

使用特权

评论回复
71
9dome猫|  楼主 | 2023-4-21 23:21 | 只看该作者
MD_GET_SP 宏定义如下:

#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_RSP]

使用特权

评论回复
72
9dome猫|  楼主 | 2023-4-21 23:21 | 只看该作者
由于 参数 _sp 是 stack->sp,所以是把 stack->sp 存储在__jmpbuf[JB_RSP] 的位置,但之前在 _st_md_cxt_save 里面,__jmpbuf[JB_RSP] 已经被用了,如下:

/* Save SP */
leaq 8(%rsp), %rdx
movq %rdx, (JB_RSP*8)(%rdi)

使用特权

评论回复
73
9dome猫|  楼主 | 2023-4-21 23:21 | 只看该作者
这里又会被覆盖,为什么要覆盖,这里估计是作者写多了。我把他这句 movq %rdx, (JB_RSP*8)(%rdi) 注释掉也没问题,补充:这里可能是其他平台会用到这句 movq。覆盖之后的情况如下图:

使用特权

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

使用特权

评论回复
75
9dome猫|  楼主 | 2023-4-21 23:22 | 只看该作者
MD_GET_SP 是重量级函数,这个函数可以把 刚刚申请的内存的那段还未使用的空白内存,作为协程函数的栈内存。 什么是协程函数的栈内存,首先,协程函数里面如果使用局部变量,是不是要压栈?就会把 RSP 减少,把局部变量写进去 RSP 寄存器指向的内存。

使用特权

评论回复
76
9dome猫|  楼主 | 2023-4-21 23:22 | 只看该作者
所以上面 把 (_t)->context[0].__jmpbuf[JB_RSP] 修改为 stack->sp 就是为了分配 协程函数的 栈内存。因为在 _st_md_cxt_restore() 的时候,会把 这个 __jmpbuf[JB_RSP] 恢复到 RSP 寄存器。如下图:

使用特权

评论回复
77
9dome猫|  楼主 | 2023-4-21 23:22 | 只看该作者

使用特权

评论回复
78
9dome猫|  楼主 | 2023-4-21 23:22 | 只看该作者
至此 _ST_INIT_CONTEXT() 函数分析完毕。

使用特权

评论回复
79
9dome猫|  楼主 | 2023-4-21 23:22 | 只看该作者
现在 st_thread_create() 函数还有以下代码没有执行:

/* Make thread runnable */
  thread->state = _ST_ST_RUNNABLE;
  _st_active_count++;
  _ST_ADD_RUNQ(thread);

  return thread;

使用特权

评论回复
80
9dome猫|  楼主 | 2023-4-21 23:22 | 只看该作者
上面的代码只有 _ST_ADD_RUNQ 是重点,仔细分析一下这个函数,定义如下:

#define _ST_ADD_RUNQ(_thr)  ST_APPEND_LINK(&(_thr)->links, &_ST_RUNQ)
/* Append an element "_e" to the end of the list "_l" */
#define ST_APPEND_LINK(_e,_l) ST_INSERT_BEFORE(_e,_l)
/* Insert element "_e" into the list, before "_l" */
#define ST_INSERT_BEFORE(_e,_l)     \
    ST_BEGIN_MACRO     \
   (_e)->next = (_l);  \
   (_e)->prev = (_l)->prev; \
   (_l)->prev->next = (_e); \
   (_l)->prev = (_e);  \
    ST_END_MACRO

使用特权

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

本版积分规则