Boost.ASIO源码:epoll和套接字描述符包装类epoll_reactor之descriptor_state

io_service(在这里实现类为scheduler)需要一个监听描述符的epoll机制,而这个机制的实现,便是来源于epoll_reactor和descriptor_state,下面详细介绍。

大致介绍

descriptor_state保存所有描述符(就我观察应该都是socket描述符)的状态、处理函数handler、以及epoll相关数据等信息。而epoll_reactor算是Linux原生epoll和io_service之间的接口,核心逻辑当然还是调用原生的epoll,但是epoll_reactor借助descriptor_state对epoll监听的事件以及事件处理函数进行了很好的封装,内部实现了一套自动触发逻辑。
descriptor实际上继承自scheduler_operation,scheduler_operation是所有operation的基类,这个operation可以理解为各种各样的处理函数。所以descriptor中自然也就有相应的处理函数,一个是它自身的perform_io方法,用于在epoll_wait返回时触发的函数,该函数会传入一个uint32_t类型的参数,代表epoll触发的事件类型,内部会根据触发的事件类型去触发该descriptor绑定的描述符的同类型的处理函数;而另一个处理函数是全局静态的do_complete函数,这个函数没什么特别,仅用来触发perform_io,相当于外界调用的接口函数。
epoll_reactor虽然代码很多,但几乎都是操作已注册的描述符及其处理函数的方法,理解了descriptor的机制之后再来看epoll_reactor的这些操作方法就比较容易理解了,所以这里就不细讲了。
descriptor_state是以一种单链表的形式保存在epoll_reactor中的一个类型为object_poll的registered_descriptors_成员中,这个object_poll比较有意思,稍后再讲。

descriptor_operation

从descriptor_operation继承自scheduler_operation看来,它的语义依旧是一种处理函数,处理的是epoll_wait返回这一事件,而epoll_wait实际上是对其它事件的一种监听形式,所以对epoll真正监听到的事件,需要更具体地处理函数来处理,descriptor_operation就提供了一种组织管理这些具体的处理函数的机制。
descriptor_operation的源码实际不长,它是epoll_reactor的内部类:

class descriptor_state : operation
  {
   
    friend class epoll_reactor;
    friend class object_pool_access;  // 封装了操作descriptor_state链表的函数

    descriptor_state* next_;  // 方便用链表的形式来组织
    descriptor_state* prev_;

    mutex mutex_;  // 对自身内部数据的访问锁
    epoll_reactor* reactor_;   // 对持有自身的epoll_reactor的引用
    int descriptor_;  // 描述符
    uint32_t registered_events_;  // 在epoll中注册的所有事件,这个事件是用位标志来描述的
    op_queue<reactor_op> op_queue_[max_ops];   // 对所有的操作类型,每个操作类型维护一个队列。
    bool try_speculative_[max_ops];
    bool shutdown_;   // 本描述符是否已关闭

    BOOST_ASIO_DECL descriptor_state(bool locking);
    void set_ready_events(uint32_t events) {
    task_result_ = events; }
    void add_ready_events(uint32_t events) {
    task_result_ |= events; }
    BOOST_ASIO_DECL operation* perform_io(uint32_t events);
    BOOST_ASIO_DECL static void do_complete(
        void* owner, operation* base,
        const boost::system::error_code& ec, std::size_t bytes_transferred);
  };

可以看到里面的op_queue就是epoll监听到的事件的处理函数reactor_op,这个队列是个数组,以epoll监听到的事件类型分类。reactor_op也是结成自scheduler_operation(operation是scheduler_operation的别名)

/* typedef scheduler_operation operation; */  // 另外某处的定义
class reactor_op
  : public operation
{
   
public:
  // The error code to be passed to the completion handler.
  boost::system::error_code ec_;

  // The number of bytes transferred, to be passed to the completion handler.
  std::size_t bytes_transferred_;

  // Status returned by perform function. May be used to decide whether it is
  // worth performing more operations on the descriptor immediately.
  enum status {
    not_done, done, done_and_exhausted };

  // Perform the operation. Returns true if it is finished.
  status perform()
  {
   
    return perform_func_(this);
  }

protected:
  typedef status (*perform_func_type)(reactor_op*);

  reactor_op(perform_func_type perform_func, func_type complete_func)
    : operation(complete_func),
      bytes_transferred_(0),
      perform_func_(perform_func)
  {
   
  }

private:
  perform_func_type perform_func_;
};

可以看得出reactor结构也很鉴定,仅是封装了一个处理函数,调用perform就相当于调用该处理函数。
这里再引入reactor_op的类型枚举类:

enum op_types {
    read_op = 0, write_op = 1,
    connect_op = 1, except_op = 2, max_ops = 3 };

可以看到max_ops也在此定义,说明操作类型最多就三种,write_op和connect_op的枚举值是一样的。

object_pool——descriptor_state的回收与分配机制

object_pool也可以看成是一个组织descriptor_state的数据结构,epoll_reactor的成员registered_descriptors_就是该类型,这个成员中保存着所有已经注册在该epoll中的描述符object_poolregistered_descriptors_;
接下来放object_pool的源码,里面有用到object_pool_access封装的操作函数,实际上非常简单,但为了完整性我还是一起放出来吧。

template <typename Object>  // 这个传入的Object直接代入descriptor_state就行了
class object_pool
  : private noncopyable
{
   
public:
  // Constructor.
  object_pool()
    : live_list_(0),
      free_list_(0)
  {
   
  }

  // Destructor destroys all objects.
  ~object_pool()
  {
   
    destroy_list(live_list_);
    destroy_list(free_list_);
  }

  // Get the object at the start of the live list.
  Object* first()
  {
   
    return live_list_;
  }

  // Allocate a new object.
  Object* alloc()
  {
   
    Object* o = free_list_;
    if (o)
      free_list_ = object_pool_access::next(free_list_);
    else
      o =

你可能感兴趣的:(源码阅读笔记,ASIO,epoll_reactor)