/// epoll接口封装 /// @file /// @date 2012-02-14 15:21:53 /// @version 1.0.0 /// @author zhouling(周龄), [email protected] /// @copyright Tencent /// @namespace hydra // Revision: $Id: epoller.h 1519 2014-05-23 12:18:56Z zhouling $ #ifndef __HYDRA_EPOLLER_H__ #define __HYDRA_EPOLLER_H__ \ "$Id: epoller.h 1519 2014-05-23 12:18:56Z zhouling $" #include <sys/epoll.h> #include "hydra_base_define.h" namespace hydra { /// @attention /// 1: 系统的epoll_event很难用, 比如fd跟u32对应同一个内存块,名字不一样而已, /// 不能将fd跟u32用于存取不同的值,从epoll_event提取字段也不方便, /// 所以这里将epoll_event重新定义为EpollEvent。 /// 2: EpollEvent只是跟epoll_event大小相同而已,内存上字段并不完全对应, 所以 /// 使用时以EpollEvent为准,epoll_event只作为Epoller内部使用 /// 3: EpollEvent字段引用比epoll_event要方便,举例如下: /// EpollEvent myevent; epoll_event sysevent; /// myevent.events vs sysevent.events /// myevent.fd(!= myevent.u32) vs sysevent.data.fd(== sysevent.data.u32) /// myevent.u32(!= myevent.fd) vs sysevent.data.u32(== sysevent.data.fd) /// myevent.u64(== fd|u32 or u32|fd) vs sysevent.data.u64(包含fd/u32) /// myevent.ptr vs sysevent.data.ptr /// 4: 在调用 带参数uint32_t/uint64_t data的重载函数时,编译器可能报 /// ambiguous错误,需要给data参数加U/ULL后缀或者进行类型强转以去除二义性。有试 /// 过命名成2个不同的函数,但是发现容易调用到错误的函数从而引起bug,这里的二义 /// 性报错反而对调用者进行了提示,从而避免错误接口的调用! struct EpollEvent { uint32_t events; // Epoll events union // User data variable { struct { int fd; uint32_t u32; }; uint64_t u64; void* ptr; }; } __attribute__((__packed__)); class Epoller { public: Epoller(int trigger = 0); // 默认水平触发, 边沿触发填EPOLLET ~Epoller(); public: /// @brief epoll初始化 /// @param[in] num epoll的初始fd监听个数 /// @return 0 if succ, errcode if fail int Create(int num); /// @brief epoll轮询 /// @param[in] timeout 轮询超时,毫秒 /// @return 0: 无就绪事件,>0:就绪事件个数,<0:错误码 int Wait(int timeout); /// @brief 将fd从epoll监听中删除 /// @param[in] fd 需要删除的fd /// @return 0 if succ, errcode if fail int DelEvents(int fd); /// @brief 添加fd到epoll里面,用以监听其读事件 /// @attention fd跟data都保存到EpollEvent /// @param[in] fd 需要监听的fd /// @param[in] data 需要保管的数据 /// @return 0 if succ, errcode if fail int AddReadEvents(int fd, uint32_t data = 0); /// @brief 添加fd到epoll里面,用以监听其读事件 /// @attention data保存到EpollEvent, fd没地方存 /// @param[in] fd 需要监听的fd /// @param[in] data 需要保管的数据 /// @return 0 if succ, errcode if fail int AddReadEvents(int fd, uint64_t data); /// @brief 添加fd到epoll里面,用以监听其读事件 /// @attention ptr保存到EpollEvent, fd在x86_32下可存,x86_64下没地方存,统一不存 /// @param[in] fd 需要监听的fd /// @param[in] ptr 需要保管的指针 /// @return 0 if succ, errcode if fail int AddReadEvents(int fd, void* ptr); /// @brief 添加fd到epoll里面,用以监听其写事件 /// @attention fd跟data都保存到EpollEvent /// @param[in] fd 需要监听的fd /// @param[in] data 需要保管的数据 /// @return 0 if succ, errcode if fail int AddWriteEvents(int fd, uint32_t data = 0); /// @brief 添加fd到epoll里面,用以监听其写事件 /// @attention data保存到EpollEvent, fd没地方存 /// @param[in] fd 需要监听的fd /// @param[in] data 需要保管的数据 /// @return 0 if succ, errcode if fail int AddWriteEvents(int fd, uint64_t data); /// @brief 添加fd到epoll里面,用以监听其写事件 /// @attention ptr保存到EpollEvent, fd在x86_32下可存,x86_64下没地方存,统一不存 /// @param[in] fd 需要监听的fd /// @param[in] ptr 需要保管的指针 /// @return 0 if succ, errcode if fail int AddWriteEvents(int fd, void* ptr); /// @brief 添加fd到epoll里面,用以监听其读写事件 /// @attention fd跟data都保存到EpollEvent /// @param[in] fd 需要监听的fd /// @param[in] data 需要保管的数据 /// @return 0 if succ, errcode if fail int AddReadWriteEvents(int fd, uint32_t data = 0); /// @brief 添加fd到epoll里面,用以监听其读写事件 /// @attention data保存到EpollEvent, fd没地方存 /// @param[in] fd 需要监听的fd /// @param[in] data 需要保管的数据 /// @return 0 if succ, errcode if fail int AddReadWriteEvents(int fd, uint64_t data); /// @brief 添加fd到epoll里面,用以监听其读写事件 /// @attention ptr保存到EpollEvent, fd在x86_32下可存,x86_64下没地方存,统一不存 /// @param[in] fd 需要监听的fd /// @param[in] ptr 需要保管的指针 /// @return 0 if succ, errcode if fail int AddReadWriteEvents(int fd, void* ptr); /// @brief 改为监听读事件 /// @attention fd跟data都保存到EpollEvent /// @param[in] fd 需要更改的fd /// @param[in] data 需要保管的数据 /// @return 0 if succ, errcode if fail int ModifyToRead(int fd, uint32_t data = 0); /// @brief 改为监听读事件 /// @attention data保存到EpollEvent, fd没地方存 /// @param[in] fd 需要更改的fd /// @param[in] data 需要保管的数据 /// @return 0 if succ, errcode if fail int ModifyToRead(int fd, uint64_t data); /// @brief 改为监听读事件 /// @attention ptr保存到EpollEvent, fd在x86_32下可存,x86_64下没地方存,统一不存 /// @param[in] fd 需要更改的fd /// @param[in] ptr 需要保管的指针 /// @return 0 if succ, errcode if fail int ModifyToRead(int fd, void* ptr); /// @brief 改为监听写事件 /// @attention fd跟data都保存到EpollEvent /// @param[in] fd 需要更改的fd /// @param[in] data 需要保管的数据 /// @return 0 if succ, errcode if fail int ModifyToWrite(int fd, uint32_t data = 0); /// @brief 改为监听写事件 /// @attention data保存到EpollEvent, fd没地方存 /// @param[in] fd 需要更改的fd /// @param[in] data 需要保管的数据 /// @return 0 if succ, errcode if fail int ModifyToWrite(int fd, uint64_t data); /// @brief 改为监听写事件 /// @attention ptr保存到EpollEvent, fd在x86_32下可存,x86_64下没地方存,统一不存 /// @param[in] fd 需要更改的fd /// @param[in] ptr 需要保管的指针 /// @return 0 if succ, errcode if fail int ModifyToWrite(int fd, void* ptr); /// @brief 改为监听读写事件 /// @attention fd跟data都保存到EpollEvent /// @param[in] fd 需要更改的fd /// @param[in] data 需要保管的数据 /// @return 0 if succ, errcode if fail int ModifyToReadWrite(int fd, uint32_t data = 0); /// @brief 改为监听读写事件 /// @attention data保存到EpollEvent, fd没地方存 /// @param[in] fd 需要更改的fd /// @param[in] data 需要保管的数据 /// @return 0 if succ, errcode if fail int ModifyToReadWrite(int fd, uint64_t data); /// @brief 改为监听读写事件 /// @attention ptr保存到EpollEvent, fd在x86_32下可存,x86_64下没地方存,统一不存 /// @param[in] fd 需要更改的fd /// @param[in] ptr 需要保管的指针 /// @return 0 if succ, errcode if fail int ModifyToReadWrite(int fd, void* ptr); /// @brief 返回epoll观察到的就绪事件集合 /// @return epoll观察到的就绪事件集合 EpollEvent* GetEvents() const { return _events; } /// @brief 返回最近一次产生的错误信息 /// @return 最近一次产生的错误信息 const char* GetErrMsg() const { return _errmsg; } private: int EpollControl(int op, uint32_t flag, int fd, uint32_t data); int EpollControl(int op, uint32_t flag, int fd, uint64_t data); int EpollControl(int op, uint32_t flag, int fd, void* ptr); int EpollControl(int op, int fd, EpollEvent event_unit); private: char _errmsg[128]; EpollEvent* _events; int _epfd; int _maxevents; int _trigger; bool _init; }; } #endif /// cpp #include "epoller.h" #include "hydra_file_util.h" #include "hydra_log.h" namespace hydra { Epoller::Epoller(int trigger) { _errmsg[0] = 0; _events = NULL; _epfd = -1; _maxevents = -1; _trigger = trigger; _init = false; } Epoller::~Epoller() { if (_events != NULL) { delete[] _events; _events = NULL; } hydra::Close(_epfd); } int Epoller::AddReadEvents(int fd, uint32_t data) { return EpollControl(EPOLL_CTL_ADD, EPOLLIN, fd, data); } int Epoller::AddReadEvents(int fd, uint64_t data) { return EpollControl(EPOLL_CTL_ADD, EPOLLIN, fd, data); } int Epoller::AddReadEvents(int fd, void* ptr) { return EpollControl(EPOLL_CTL_ADD, EPOLLIN, fd, ptr); } int Epoller::AddWriteEvents(int fd, uint32_t data) { return EpollControl(EPOLL_CTL_ADD, EPOLLOUT, fd, data); } int Epoller::AddWriteEvents(int fd, uint64_t data) { return EpollControl(EPOLL_CTL_ADD, EPOLLOUT, fd, data); } int Epoller::AddWriteEvents(int fd, void* ptr) { return EpollControl(EPOLL_CTL_ADD, EPOLLOUT, fd, ptr); } int Epoller::AddReadWriteEvents(int fd, uint32_t data) { return EpollControl(EPOLL_CTL_ADD, EPOLLIN | EPOLLOUT, fd, data); } int Epoller::AddReadWriteEvents(int fd, uint64_t data) { return EpollControl(EPOLL_CTL_ADD, EPOLLIN | EPOLLOUT, fd, data); } int Epoller::AddReadWriteEvents(int fd, void* ptr) { return EpollControl(EPOLL_CTL_ADD, EPOLLIN | EPOLLOUT, fd, ptr); } int Epoller::ModifyToRead(int fd, uint32_t data) { return EpollControl(EPOLL_CTL_MOD, EPOLLIN, fd, data); } int Epoller::ModifyToRead(int fd, uint64_t data) { return EpollControl(EPOLL_CTL_MOD, EPOLLIN, fd, data); } int Epoller::ModifyToRead(int fd, void* ptr) { return EpollControl(EPOLL_CTL_MOD, EPOLLIN, fd, ptr); } int Epoller::ModifyToWrite(int fd, uint32_t data) { return EpollControl(EPOLL_CTL_MOD, EPOLLOUT, fd, data); } int Epoller::ModifyToWrite(int fd, uint64_t data) { return EpollControl(EPOLL_CTL_MOD, EPOLLOUT, fd, data); } int Epoller::ModifyToWrite(int fd, void* ptr) { return EpollControl(EPOLL_CTL_MOD, EPOLLOUT, fd, ptr); } int Epoller::ModifyToReadWrite(int fd, uint32_t data) { return EpollControl(EPOLL_CTL_MOD, EPOLLIN | EPOLLOUT, fd, data); } int Epoller::ModifyToReadWrite(int fd, uint64_t data) { return EpollControl(EPOLL_CTL_MOD, EPOLLIN | EPOLLOUT, fd, data); } int Epoller::ModifyToReadWrite(int fd, void* ptr) { return EpollControl(EPOLL_CTL_MOD, EPOLLIN | EPOLLOUT, fd, ptr); } int Epoller::DelEvents(int fd) { return EpollControl(EPOLL_CTL_DEL, 0U, fd, 0U); } int Epoller::EpollControl(int op, uint32_t flag, int fd, uint64_t data) { EpollEvent event_unit; event_unit.events = flag | _trigger; event_unit.u64 = data; return EpollControl(op, fd, event_unit); } int Epoller::EpollControl(int op, uint32_t flag, int fd, void* ptr) { EpollEvent event_unit; event_unit.events = flag | _trigger; event_unit.ptr = ptr; return EpollControl(op, fd, event_unit); } int Epoller::EpollControl(int op, uint32_t flag, int fd, uint32_t data) { EpollEvent event_unit; event_unit.events = flag | _trigger; event_unit.fd = fd; event_unit.u32 = data; return EpollControl(op, fd, event_unit); } int Epoller::EpollControl(int op, int fd, EpollEvent event_unit) { int ret = epoll_ctl(_epfd, op, fd, (epoll_event*)&event_unit); if (ret != 0) { SET_ERR_MSG("epoll_ctl(epfd=%d, op=%d, fd=%d) err: %m", _epfd, op, fd); return -errno; } return 0; } int Epoller::Create(int maxevents) { if (_init) return 0; _epfd = epoll_create(maxevents); if (_epfd < 0) { SET_ERR_MSG("epoll_create(size=%d) fail: %m", maxevents); return -errno; } _events = new EpollEvent[maxevents]; if (NULL == _events) { SET_ERR_MSG("new EpollEvent err: %m, sizeof(EpollEvent)=%u, maxevents=%d", (uint32_t)sizeof(EpollEvent), maxevents); int err = -errno; hydra::Close(_epfd); return err; } _maxevents = maxevents; _init = true; return 0; } int Epoller::Wait(int timeout) { int nevents = 0; while ((nevents = epoll_wait(_epfd, (epoll_event*)_events, _maxevents, timeout)) < 0 && EINTR == errno) ; // do nothing if (nevents < 0) { SET_ERR_MSG("epoll_wait(epfd=%d, maxevents=%d, timeout=%d) err: %m", _epfd, _maxevents, timeout); return -errno; } return nevents; } }