Skip to content

pihou/goroutine-simple-internal

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

接触go以后,一直很好奇goroutine是如何实现的(实际在go以前也会好奇python的协程实现).每每搜索golang internal之类的文章都没有发现什么有价值的东东(严格来说也不准确,比如找到了这个)。网络上关于gorouine的文章基本上都在大谈特谈go的GPM模型。但是GPM是什么鬼?它距离我们的程序式的理解goroutine还差了一万里。

好吧,我承认,当意识到gorotine的实现基石后,立马就不会感觉半点神奇了,但是在这之前,还是会觉得这玩意贼高大上的。

面对goroutine你会产生一些什么疑问了?

  1. goroutine之间的切换是怎么发生的?
  2. goroutine是如何保证在二进制原生程序的基础上,来维护多个调用栈的?(我看过python的虚拟机实现,所以很容易将他们的实现套到goroutine来思考go的实现,反而更加困顿)
  3. 同线程的goroutine的调用栈是通过系统调用来设置切换的调用栈?

好吧,最近有看到一些文章,勾起了对goroutine实现机制的思索,当然还是大谈特谈GPM。丝毫没有提及GPM到程序实现基石之间的那层薄薄的纸。

直到顺着文章多少找到一点点线索,然后又顺着线索找到asm_amd64.s runtime.mcall.

查看runtime的注释,说这个函数会切换gorouine,然后顺着猜到里这个函数的实现,汇编程序。

switch to m->go ? 看样子是这里没错了,然后细看下面的汇编

  1. 我以为会有一个系统调用来去完成切换操作的,没有(int 0x80)
  2. 再细看有一个sp寄存器的设置,哦,可能是通过sp的设置来切换堆栈
  3. 那pc的设置了,没有。。。再想想,哦,对了,笨啊,我自己直接跳转到堆栈上留的程序地址不也是跳转了么,只需要其它goroutine按照约定的留好地址就行了。

好吧,说破了之后就是这么浅显的一件事情...

动手简单了实践了一把,然后就有了这个git。

在linux下使用gcc和nasm来编译执行。命令:nasm -felf64 schedule.asm && gcc main.c schedule.o && ./a.out

当然实现的基石距离实现还差了很多,特多,超多细节,但是是不是就豁然开朗了呢?再看GPM模型是不是就有了底了呢?

线程的堆栈由sp 和ss来指定,ss是栈的段描述符寄存器,其指向的数据存有栈这块内存的一些属性信息,还有栈的最底位地址信息。不能被用户态程序所修改。所以推测goroutine需要很精巧的控制系统已经给线程分配好的堆栈,合理给每个gorutine来使用。

使用gdb来测试下?查看下汇编执行完后的调用栈?

nasm参考

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published