-
Notifications
You must be signed in to change notification settings - Fork 276
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Guide: Notes about code of state-threads. ST代码分析. #15
Comments
_st_iterate_threads分析如何迭代所有的coroutines。 _ST_THREADQ这个是所有线程的列表,迭代所有的coroutines当然是要迭代这个双向链表,它会在创建线程时把线程加到链表中。
这个ADD宏定义,详细实现如下图,简单来说就是把thread添加到双向链表 当我们迭代线程链表时,我们需要根据thread的成员tlinks,来获取thread的指针:
coroutine RSP上面我们可以拿到每个thread的jmp_buf,也就是保存的堆栈信息。我们可以拿到RSP地址:
倒数第二个就是RSP的值了,注意第一个是idle coroutine,第二个是一个原生coroutine也就是main(它的start是0x00):
堆栈分析看后面的注释。 iterator coroutines当能拿到coroutine的context时,就可以直接跳到这个coroutine执行:
注意这个函数,使用的是裸MD_LONGJMP和MD_SETJMP,它的执行顺序很不直观,需要逐步分析:
后面就开始迭代各个coroutine执行了:
注意下面代码实际上是迭代开始之后才会执行,而开始迭代并不会执行,从执行顺序看正好是反的:
上面的SWITCH的宏实际上是一段代码:
同样的这个setjmp在sleep第一次调用时为0,所以进入schedule切走。 最后一段代码,是如果中途改变了flag,则直接恢复thread的context,并结束迭代:
这个调用链条如下图所示: 这样也能看懂调度的逻辑: GDB scripts根据上面的分析,我们可以写一个GDB脚本gdb/srs.py,可以看当前或者coredump中有多少个coroutines:
从上面可以看出,一共有3.2万个coroutine,如果使用mmap会出问题,可以用这个程序验证。参考SRS #509。 Conclusion
|
_st_stack_newcoroutine的堆栈,是在调用函数st_thread_create时创建的,创建后顶部和尾部4k的区间mprotect设置为REDZONE,访问这个区间的内存时会直接报错,也就是堆栈消耗完了:
可以通过mmap看到分配的内存块:
但是在core中是看不到这块mmap的内存的:
内存分配后,会以下图方式布局,thread对象实际上是从里面分配的: 而实际分配内存是下面的函数,它可能从heap或者mmap分配:
mmap时,在coredump文件中,vaddr地址是不可访问,而在gdb运行时却不是:
实际上mmap的堆栈是不释放的,所以这个地方并不是内存破坏,而是就是这么显示的。
coroutine stack根据rsp和stack sp,就可以知道coroutine的堆栈信息,把堆栈打出来就可以看到调用过程了,比如第三个coroutine:
coroutine frameframe地址可以由jmpbuf算出:
下面详细分析setjmp的情况。 coroutine在调度时,是调用的宏定义
这个宏定义展开如下:
实际上就是setjmp。用一个最简单的调用例子,来看ST的寄存器变化,以及RBP和frame的关系:
当然fp这个寄存器我们并没有保存,所以我们继续执行三条汇编,看下RBP和frame关系:
从上面可以看到,如果我们知道了RBP,就可以知道Frame的地址了:
我们继续执行到st_usleep开始切换上下文的地方:
总结下,在setjmp/_st_md_cxt_save这个函数中几个关键寄存器的保存:
不过我们知道了frame地址,也无法直接切换过去,比如下面两个coroutine:
它们的frame地址是0x7ffff7fe9d60和0x7fffffffe560,但是却不能随意使用 coroutine backtrace当我们知道了线程的RBP,那么我们就可以知道整个堆栈,例如我们看当前线程的前一个线程:
注意:如果是当前线程,这个RBP可能是不对的,因为jmpbuf保存的是之前的一个位置。当前coroutine直接用bt就可以看到堆栈。 discovery in coredump第一个coroutine是idle,第二个就是main,也就是SrsServer的coroutine,我们可以看它的调用堆栈:
这里我们可以看到SrsServer对象了,可以找找它的this指针:
|
GDB nn_coroutinesSRS提供脚本nn_coroutines,可以看当前或者coredump中有多少个coroutines:
|
GDB show_coroutinesSRS提供脚本show_coroutines,可以看当前或者coredump中每个coroutine的调用函数:
|
代码分析备忘录。
The text was updated successfully, but these errors were encountered: