概述

EventCenter是Async异步消息通信的核心模块,通过事件/回调模型向上提供异步消息通信,每个Async下的worker线程负责处理一个EventCenter的事件集合。EventCenter针对不同类型的事件使用不同的事件监听来处理事件回调。

详细设计

事件类型

目前EventCenter共支持4种类型的事件,每个worker线程在进入事件处理逻辑的时候,会分别对这4种事件类型的事件进行处理

  • file_events:fd类事件
  • time_events/event_map:定时器类事件
  • external_events/external_num_events:外部事件(时间为0的定时事件)
  • pollers:轮询类事件(目前是DPDk模块在使用)

事件操作

event_center对外提供创建/删除:fd、time、external 3种类型的事件,poller事件则需要EventCenter::Poller的派生类自行实现poll方法。下面介绍下4种事件的监听方式:

  • fd类事件

  • time类事件

  • 外部事件

  • pollers 

事件的处理

每个worker的线程负责处理EventCenter的底层监听事件集合,因此对EventCenter事件的处理主要在每个worker的线程函数,每个事件的处理逻辑如下:



  • 处理fd类事件 


Pipe管道设计

fd类事件的监听方式,比如epoll,在使用epoll_wait的时候可能存在阻塞(timeout)会使线程睡眠,对于有些需要马上处理的消息,则线程无法及时处理,因此center就设计了一对Pipe管道,通过监听管道的写事件来唤醒睡眠的线程。管道的创建是在EventCenter初始化的时候

 EventCenter::init(...)
    .....
        notify_receive_fd = fds[0];
        notify_send_fd = fds[1];
		
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

在启动worker线程处理的时候,会在set_owner接口里面创建管道的读端监听事件。

 notify_handler = new C_handle_notify(this, cct); int r = create_file_event(notify_receive_fd, EVENT_READABLE, notify_handler);
		
  • 1
  • 2
  • 1
  • 2

管道的写端则是在wakeup接口里面

 int n = write(notify_send_fd, &buf, sizeof(buf));
		
  • 1
  • 1

因此通过这种机制就可以唤醒线程

global_center设计

global_center是为了维护一个全局的EventCenter表,它通过单例模式来实现一个唯一的全局变量。具体实现是:在启动每个worker线程处理的时候,每个worker都会调用

EventCenter::set_owner
		
  • 1
  • 1

这个接口来设置owner属性和添加EventCenter给global_center表

事件回调的设计

EventCenter封装了事件的回调基类EventCallback/EventCallbackRef,对于上层使用者来说,注册的事件回调必须是这个基类的派生类,封装这个基类最主要的逻辑是调用do_request接口,因此每个事件回调核心实现都在其do_request里面去实现即可。

结束

EventCenter的设计模型还是比较简单,但是是Async模块实现异步通信的核心,下个章节来介绍Async中间通信模型。

涉及源码:${ceph}/src/msg/async/Event*

10-17 21:23
查看更多