// func mcall(fn func(*g))
// Switch to m->g0's stack, call fn(g).
// Fn must never return. It should gogo(&g->sched)
// to keep running g.
// 上面的翻译:
// 切换到 m->g0 的栈上,然后调用 fn (g)函数。
// fn 必须不能返回。fn 应该 调用 gogo 函数 来保持运行 g。
TEXT runtime·mcall(SB), NOSPLIT, $0-8
    MOVQ    fn+0(FP), DI       // 很容易理解的,将fn这个函数指针存到DI寄存器。
    get_tls(CX)                     // 宏,顾名思义,tls 是线程局部存储,将这个存储的开始位置存到 CX
    MOVQ    g(CX), AX   // save state in g->sched     // g(CX)还是宏,在tls上可以拿到g,也就是当前正在跑的g,把这个g的地址存到AX寄存器
    MOVQ    0(SP), BX   // caller's PC                       // 这一句有点难懂,得明白整个golang的函数调用规则才能明白。简介:golang的函数栈的大小,不包含传入的参数和返回值,这两个部分由调用者管理,mcall例子中,fn是传入参数,这个fn是放在【调用mcall的函数】的函数栈里的。mcall除了一个传入参数fn之外,没有其他变量了,所以mcall的栈大小就是0。一个栈大小为0的函数,栈顶,也就是SP指向的位置,刚好就是存的调用mcall的函数的下一条指令,也就是这里所谓的 caller 的 PC。这个PC值为什么会出现在这里,那就是因为,这是CALL指令自动做的事情,也是golang编译器做的事情,调用某函数时,先把本函数的下一掉指令push进栈。话说回来了,既然mcall不需要额外的栈大小了,前面说了,栈大小是0,所以,自然而然的,SP,存的东西就是caller的PC。好,拿到了caller‘s PC,把他存到BX里。
    MOVQ    BX, (g_sched+gobuf_pc)(AX) // 这句简单,AX存了g的地址,BX存了caller's PC,那这句就是把caller's PC 存到 g 结构体的 sched 的 gobuf 的 pc 字段。
    LEAQ    fn+0(FP), BX    // caller's SP // 这句又难了。为什么栈上,存fn的地方,是caller的栈顶呢。根据上面的解释能猜到一点,因为栈上存fn这个事,就是由caller来处理的,caller的栈在往下生长的时候,最后一个数据项就是fn。再下面就是caller pc,等等等等。
    MOVQ    BX, (g_sched+gobuf_sp)(AX) // BX存的是caller的SP,将BX存到g的相应位置 
    MOVQ    AX, (g_sched+gobuf_g)(AX)   // AX存的就是g本身,也存起来
    MOVQ    BP, (g_sched+gobuf_bp)(AX) //  这一句不太重要,好像BP寄存器已经没啥用了。可能在debug的时候,有点用??不清楚,这个,但是肯定是跟切换上下文的主逻辑和函数调用的主逻辑没什么关系了。
    // switch to m->g0 & its stack, call fn // 切换到m->g0的栈,然后调用fn
    MOVQ    g(CX), BX // 把当前g的地址存到BX里
    MOVQ    g_m(BX), BX // 根据g,可以拿到m
    MOVQ    m_g0(BX), SI // 根据m,又可以拿到 g0,目的就是拿到 g0,下面要切换了。
    CMPQ    SI, AX  // if g == m->g0 call badmcall // 如果g0就是g,那不行,这种情况,我们不考虑先。
    JNE 3(PC) // 假如g!= g0,就跳到红色标记,继续执行。 
    MOVQ    $runtime·badmcall(SB), AX
    JMP AX
    红色标记:MOVQ    SI, g(CX)   // g = m->g0 // SI存的是g0,将g0变成当前g。
    MOVQ    (g_sched+gobuf_sp)(SI), SP  // sp = m->g0->sched.sp // 将g0的SP值,拿出来,交给寄存器SP,看见没,开始切换了,或者说,已经切完了,下面就是调用 fn (g)
    PUSHQ   AX // AX 是什么,存的就是刚才的g,不是现在的g0,将g放到栈上。这一步就是普通的,我要调用fn函数了,我要把参数g,先放到栈上。
    MOVQ    DI, DX // 这一步把fn存到DX不知道要干嘛,可能后续调用fn的时候,会用到??不知道,等再接着看。
    MOVQ    0(DI), DI // 这一步和下一步,就是调用 fn
    CALL    DI           // 调用fn
    POPQ    AX
    MOVQ    $runtime·badmcall2(SB), AX
    JMP AX
    RET

golang mcall的更多相关文章

  1. Golang网络库中socket阻塞调度源码剖析

    本文分析了Golang的socket文件描述符和goroutine阻塞调度的原理.代码中大部分是Go代码,小部分是汇编代码.完整理解本文需要Go语言知识,并且用Golang写过网络程序.更重要的是,需 ...

  2. Golang源码探索(二) 协程的实现原理

    Golang最大的特色可以说是协程(goroutine)了, 协程让本来很复杂的异步编程变得简单, 让程序员不再需要面对回调地狱, 虽然现在引入了协程的语言越来越多, 但go中的协程仍然是实现的是最彻 ...

  3. Golang源码探索(二) 协程的实现原理(转)

    Golang最大的特色可以说是协程(goroutine)了, 协程让本来很复杂的异步编程变得简单, 让程序员不再需要面对回调地狱,虽然现在引入了协程的语言越来越多, 但go中的协程仍然是实现的是最彻底 ...

  4. Golang源码学习:调度逻辑(四)系统调用

    Linux系统调用 概念:系统调用为用户态进程提供了硬件的抽象接口.并且是用户空间访问内核的唯一手段,除异常和陷入外,它们是内核唯一的合法入口.保证系统的安全和稳定. 调用号:在Linux中,每个系统 ...

  5. Golang源码学习:监控线程

    监控线程是在runtime.main执行的时候在系统栈中创建的,监控线程与普通的工作线程区别在于,监控线程不需要绑定p来运行. 监控线程的创建与启动 简单的调用图 先给出个简单的调用图,好心里有数,逐 ...

  6. 排查golang的性能问题 go pprof 实践

    小结: 1.内存消耗分析 list peek  定位到函数   https://mp.weixin.qq.com/s/_LovnIqJYAuDpTm2QmUgrA 使用pprof和go-torch排查 ...

  7. Golang, 以17个简短代码片段,切底弄懂 channel 基础

    (原创出处为本博客:http://www.cnblogs.com/linguanh/) 前序: 因为打算自己搞个基于Golang的IM服务器,所以复习了下之前一直没怎么使用的协程.管道等高并发编程知识 ...

  8. 说说Golang的使用心得

    13年上半年接触了Golang,对Golang十分喜爱.现在是2015年,离春节还有几天,从开始学习到现在的一年半时间里,前前后后也用Golang写了些代码,其中包括业余时间的,也有产品项目中的.一直 ...

  9. TODO:Golang指针使用注意事项

    TODO:Golang指针使用注意事项 先来看简单的例子1: 输出: 1 1 例子2: 输出: 1 3 例子1是使用值传递,Add方法不会做任何改变:例子2是使用指针传递,会改变地址,从而改变地址. ...

随机推荐

  1. Boost学习之语法解析器--Spirit

    Boost.Spirit能使我们轻松地编写出一个简单脚本的语法解析器,它巧妙利用了元编程并重载了大量的C++操作符使得我们能够在C++里直接使用类似EBNF的语法构造出一个完整的语法解析器(同时也把C ...

  2. 使用word文档直接发表博客 8 )

    目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...

  3. 16、Semantic-UI之模态窗口

    16.1 定义模态窗口 示例:定义基础的模态窗口 <!DOCTYPE html> <html lang="en"> <head> <met ...

  4. 阿里云vsftp安装和简单的配置

    1.系统环境 [root@jie ~]# cat /etc/redhat-release CentOS release 6.8 (Final) [root@jie ~]# [root@jie ~]# ...

  5. Dubbo RPC源码解读

    https://yq.aliyun.com/articles/272405#27 本文代码摘录的时候,将一些与本流程无关的内容去掉了,如有需要请看源码. 一.闲言碎语 使用rpc框架已经多年了,虽然之 ...

  6. mORMot使用synDBDataSet时字段类型不正确引起的问题

    当SQL表中的nvarchar字段类型内容为null时synDBDataSet使用ftwideMemo类型造成不能修改的问题,按下面红字修改synDBVCL.pas就可以: synDBVCL.pas ...

  7. Android-什么时候用ScrollView

    什么时候用 ScrollView ? 答:像以下这种情况,就是使用ScrollView: 摆放无顺序,无规律,并会超出屏幕的高度,就可以用ScrollView 错误的ScrollView示范,Scro ...

  8. python-数值类型转换

    常用的数据类型转换 函数 说明 int(x [,base ]) 将x转换为一个整数 long(x [,base ]) 将x转换为一个长整数 float(x ) 将x转换到一个浮点数 complex(r ...

  9. 691. Stickers to Spell Word

    We are given N different types of stickers. Each sticker has a lowercase English word on it. You wou ...

  10. Logstash 性能及其替代方案

    介绍 当谈及集中日志到 Elasticsearch 时,首先想到的日志传输(log shipper)就是 Logstash.开发者听说过它,但是不太清楚它具体是干什么事情的: 当深入这个话题时,我们才 ...