Skip to content
bruceEeZhao edited this page Apr 22, 2023 · 2 revisions

本wiki根据commit 7ec84872b8ac4beb81ce252bc164224d23faf2f4所写,如需对照代码,请查看此commit下的代码。

前言

本文档对libgo的设计进行梳理,对libgo中重要的代码进行分析,包括协程的创建,上下文切换,调度器的设计等。

介绍每一部分时首先对其设计思路进行介绍,之后根据类图UML,介绍涉及的函数,对函数流程和其中涉及的数据结构和算法进行介绍,例如Scheduler中使用的双端队列及Dispatcher中协程负载均衡使用的算法。

epoll

epoll 全称 eventpoll,是 linux 内核实现IO多路复用(IO multiplexing)的一个实现。IO多路复用的意思是在一个操作里同时监听多个输入输出源,在其中一个或多个输入输出源可用的时候返回,然后对其的进行读写操作。

通过一个epoll 实例,向其中添加自己感兴趣的fd,fd就绪可以从epoll中获取。

关键函数

  • epoll_create1: 创建一个epoll实例,文件描述符
  • epoll_ctl: 将监听的文件描述符添加到epoll实例中,实例代码为将标准输入文件描述符添加到epoll中
  • epoll_wait: 等待epoll事件从epoll实例中发生, 并返回事件以及对应文件描述符

边沿触发vs水平触发

epoll事件有两种模型,边沿触发:edge-triggered (ET), 水平触发:level-triggered (LT)

水平触发(level-triggered)

  • socket接收缓冲区不为空 有数据可读 读事件一直触发
  • socket发送缓冲区不满 可以继续写入数据 写事件一直触发

边沿触发(edge-triggered)

  • socket的接收缓冲区状态变化时触发读事件,即空的接收缓冲区刚接收到数据时触发读事件
  • socket的发送缓冲区状态变化时触发写事件,即满的缓冲区刚空出空间时触发读事件

边沿触发仅触发一次,水平触发会一直触发。

libgo 目录结构

libgo-menu-structure

libgo的目录结构如上图,libgo文件夹存放libgo的代码,test存放测试代码,tutorial存放教程代码。其中libgo.libgo的目录结构为:

image-20230117091556952

  • cls: 协程本地变量
  • common: 队列、错误定义、config等
  • context: 上下文切换
  • debug: 调试、协程事件监听器
  • defer: 延迟执行。Go语言的 defer 语句会将其后面跟随的语句进行延迟处理
  • netio: 网络相关syscall hook
  • pool: 协程池
  • routine_sync: channel、条件变量、mutex
  • routine_sync_libgo: 定义了协程的switcher,供Rutex在”协程同步“相关的操作使用。
  • scheduler: 协程调度
  • sync: channel、条件变量、mutex
  • task: 协程task定义
  • timer: 定时器

目录

1-libgo使用 该文档介绍了如何使用libgo,从代码编译开始。libgo的使用主要在tutorial文件夹下,包含了多种使用示例。

2-scheduler 该文档介绍了libgo中协程调度的全部内容,首先调度器的整体结构,之后对调度系统包含的三个角色(scheduler、processer和dispatcher)分别进行介绍。还介绍了协程的重要结构Task和系统调用HOOK。

3-gc 该文档介绍了libgo中gc相关的内容,包括两个部分scheduler和task中的gc机制。

4-debug 该文档介绍libgo中调试相关内容。

5-锁机制 该文档介绍协程锁和协程读写锁

6-channel 该文档介绍libgo的channel机制

7-switcher 该文档介绍libgo为了实现锁机制实现的switcher

8-timer 该文档主要介绍libgo中的定时器机制,并主要介绍自定义定时器CoTimer

Clone this wiki locally