好用的epoll接口封装

/// 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;
}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值