/// epoll接口封装
/// @file
/// @date 2012-02-14 15:21:53
/// @version 1.0.0
/// @author Zhou Ling(周龄), zhou.0@foxmail.com
/// @namespace hydra
#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;
}
}
好用的epoll接口封装
最新推荐文章于 2024-04-27 14:52:26 发布