協程的建立和切換都是由使用者控制的,那麼協程切換時是如何儲存上下文資訊的呢,這一節我們介紹一下libco實現協程的關鍵資料結構。
1、協程實體:stcoroutine_t
2、協程上下文資訊:coctx_t
3、私有棧和共享棧:stack_mem&stsharestack_t
4、執行緒環境:stcoroutineenv_t
5、協程屬性:stcoroutineattr_t
這個結構實際上就是就是協程的主體結構,儲存著乙個協程相關的資料,每個協程對應乙個stcoroutine_t,它儲存這協程的私有資料和協程切換時的上下文資訊。每當呼叫co_create()建立乙個協程時,都會初始化這個結構體。
struct stcoroutine_t
;
這個結構儲存協程的上下文,實際就是暫存器的值,不管是c還是c++都沒有函式可以直接接觸暫存器,所以操作這個引數的時候需要嵌入一點彙編**。
struct coctx_t
;// 32 bit
// | regs[0]: ret |
// | regs[1]: ebx |
// | regs[2]: ecx |
// | regs[3]: edx |
// | regs[4]: edi |
// | regs[5]: esi |
// | regs[6]: ebp |
// | regs[7]: eax | = esp
// 64 bit
//low | regs[0]: r15 |
// | regs[1]: r14 |
// | regs[2]: r13 |
// | regs[3]: r12 |
// | regs[4]: r9 |
// | regs[5]: r8 |
// | regs[6]: rbp |
// | regs[7]: rdi |
// | regs[8]: rsi |
// | regs[9]: ret | //ret func addr
// | regs[10]: rdx |
// | regs[11]: rcx |
// | regs[12]: rbx |
//hig | regs[13]: rsp |
x86-64的16個64位暫存器分別是:%rax, %rbx, %rcx, %rdx, %esi, %edi, %rbp, %rsp, %r8-%r15。其中:
我們來看看兩個陌生的名詞呼叫者保護&被呼叫者保護:
stack_mem是執行協程私有棧的結構,stsharestack_t則是共享棧的結構。libco有兩種協程棧的策略:
struct ststackmem_t
;struct stsharestack_t
;
stcoroutineenv_t是乙個非常關鍵的結構,這個結構是所有資料中最特殊的乙個,因為它是乙個執行緒內所有協程共享的結構,也就是說同乙個執行緒建立的所有協程的此結構指標指向同乙個資料。其中存放了一些協程排程相關的資料,當然叫排程有些勉強,因為libco實現的非對稱式協程實際上沒有什麼排程策略,完全就是協程切換會呼叫這個協程的協程或者執行緒。
struct stcoroutineenv_t
;
協程屬性的結構體stcoroutineattr_t標記了棧的大小和是否使用共享棧。
struct stcoroutineattr_t
}__attribute__ ((packed));
Webpack 原始碼(二) 如何閱讀原始碼
如果想要了解 webpack 的流程,只要閱讀 七珏 細說 webpack 之流程篇 所述的內容就夠了,講解地比較全面了 本文就不對 webpack 流程再做重複的描述,而是從另外乙個角度補充分析 webpack 原始碼 webpack 中最為重要的無非是 compiler compilation ...
STL原始碼閱讀 二
vector的記憶體分配基類 template class vector alloc base vector alloc base的偏特化版本,不需要儲存記憶體分配器 template class vector alloc base tp,allocator,true template struct...
vue原始碼閱讀(二)
那麼下邊這個則是例項化建構函式,也就是開始使用了,不管是作為框架,還是作為外掛程式,都需要new一下。翻篇回去,先看vue的建構函式,this.init options 是呼叫的第乙個方法,包括傳進來的引數options,不過在這之前,還判斷了下呼叫vue的是不是先new出來的。根據注入的檔案 找到...