state thread库阅读笔记(一)

    一直以来,读过的代码和做过的项目都没有什么笔记,以至于很多学过的看过的,到后面居然记不起来,所以好记性不如烂笔头,好好总结,画图记录下来,总是有好处的,而且有很多东西也是没有去深入研究。

    之前有幸在学习srs服务器中,接触到了state thread库,并且将srs改造成了支持多线程,多协程的版本,让srs不再只使用单一cpu,发挥多核优势的同时保持多协程的高效处理方式。

    想想多协程在高并发中还是很好的处理方式,对一个网络请求来说,只要能将请求正确处理并返回,中间能不切换线程尽量不切换线程,这样能省下大量CPU时间,线程切换虽然不需要切换页表,但是线程间经常需要做事件等待,阻塞等消耗CPU的操作,因此引入了协程的概念,在应用层面实现类似CPU的多线程,主要用到了setjmp及longjmp系统调用。

    setjmp及longjmp是C语言标准库中的函数,所以任何操作系统都支持。

    int setjmp(jmp_buf envbuf):它将当前程序的栈内容保存到jmp_buf中,对于一段代码而言,如果不切换页表,那么能让它还原需要保存的变量主要应该是一些CPU寄存器,比如X86 CPU包括:CS,IP,EAX,EBX,ECX,EDX,SS,ESP,DS,ES,FS等【以后有时间再研究此结构体具体定义】。

    定义:

    typedef size_t jmp_buf[6];

    int setjmp(size_t* buf);

    void longjmp(size_t* buf, int);

setjmp源码:

setjmp:

mov eax, [esp+4]

mov [eax], ebx

mov [eax+4], ebp

mov [eax+8], esi

mov [eax+12], edi

mov [eax+16], esp

mov ecx, [esp]

mov [eax+20], ecx

mov eax, 0

ret

其实也比较简单,如下图:


图1 setjmp调用栈

setjmp调用后,按照C语言的生成方法,先push 参数,也就是jmp_buf(其实是个指针)到stack中,也就是图1中的P1;然后再执行jmp汇编指令,该指令会将eip存入栈中(由于是短跳转,所以CS不必要入栈),所以ESP+4指向的就是P1,也就是jmp_buf指针存放地址;

mov eax, jmp_buf

push eax

call $setjmp

add esp,$4 #还原栈

#上面这段应该是C语言调用方法

setjmp:

mov eax, [esp+4]   #取到jmp_buf指针存到eax中

mov [eax], ebx    #ebx存到jmp_buf[0]中(假设jmp_buf是DWORD*类型);

mov [eax+4], ebp #ebp存到jmp_buf[1]中

mov [eax+8], esi #esi存到jmp_buf[2]中

mov [eax+12], edi #edi存到jmp_buf[3]中

mov [eax+16], esp #esp存到jmp_buf[4]中

mov ecx, [esp] #EIP存到ECX中

mov [eax+20], ecx  #EIP存到jmp_buf[5]中

mov eax, 0 #c语言规定函数返回值用eax返回,所以这里setjmp返回值为0

ret  #ret后,会将ESP指向的内容存入EIP,ESP会加4,将EIP出栈,所以上面要提前保存EIP到jmp_buf[5]中;

所以setmp就把上述的寄存器保存到jmp_buf结构中了,然后也不管,在返回0的判断后,该干嘛继续干嘛。

再来看看longjmp(longjmp顾名思义,就是长跳转):


图2 longjmp调用栈结构

mov eax, status  #这里应该是一个立即数地址,编译后的,这里只是示意

push eax

mov eax, jmp_buf 

push eax

call $longjmp

#上面这段应该是C语言函数调用实现,忘记X86汇编了,有错误请指正

longjmp:

mov eax, [esp+8]   #ESP指向EIP,ESP+4指向jmp_buf,ESP+8指向status

mov ecx, [esp+4]   #取出jmp_buf,存入ecx

mov esp, [ecx+16] #将jmp_buf[4]还原到esp中,此时esp就指回了原来setjmp时的栈

mov ebx, [ecx]       #将jmp_buf[0]还原到ebx中

mov ebp, [ecx+4]  #将jmp_buf[1]还原到ebp中

mov esi, [ecx+8]   #将jmp_buf[2]还原到esi中

mov edi, [ecx+12] #将jmp_buf[3]还原到edi中

mov edx, [ecx+20] #将jmp_buf[5]还原到edx中,也就是EIP存到edx中

mov [esp], edx      #将edx放到esp指向的地方,也就是图1的中ESP指向的地址,然后将EIP放回到栈中,至此,还原到了setjmp调用结束ret那一刻的状态,只是eax是longjmp自己设定的;

ret                        #返回到setjmp(这就是setjmp的第二次返回了,其返回值就是longjmp设置的status)

今天先写到这里吧,主要把协程机制中最主要的setjmp及longjmp函数分析了下,从这里还可以看出,一个协程最好有自己的一个栈空间,至于具体如何设计后面再看。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容