197 lines
6.5 KiB
C++
197 lines
6.5 KiB
C++
/*
|
|
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
|
|
*
|
|
* Author : Bruce Liang
|
|
* Website : https://github.com/ldcsaa
|
|
* Project : https://github.com/ldcsaa/HP-Socket
|
|
* Blog : http://www.cnblogs.com/ldcsaa
|
|
* Wiki : http://www.oschina.net/p/hp-socket
|
|
* QQ Group : 44636872, 75375912
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "../hpsocket/GlobalDef.h"
|
|
#include "Singleton.h"
|
|
#include "RingBuffer.h"
|
|
#include "Thread.h"
|
|
|
|
#include <sys/epoll.h>
|
|
#include <sys/eventfd.h>
|
|
#include <sys/timerfd.h>
|
|
|
|
#include <memory>
|
|
|
|
using namespace std;
|
|
|
|
#define _EPOLL_READ_PRI_EVENTS (EPOLLPRI | EPOLLRDHUP)
|
|
#define _EPOLL_READ_EVENTS (EPOLLIN | EPOLLRDHUP)
|
|
#define _EPOLL_ALL_READ_EVENTS (_EPOLL_READ_EVENTS | _EPOLL_READ_PRI_EVENTS)
|
|
#define _EPOLL_WRITE_EVENTS (EPOLLOUT)
|
|
#define _EPOLL_NORMAL_RW_EVENTS (_EPOLL_READ_EVENTS | _EPOLL_WRITE_EVENTS)
|
|
#define _EPOLL_ALL_RW_EVENTS (_EPOLL_ALL_READ_EVENTS | _EPOLL_WRITE_EVENTS)
|
|
#define _EPOLL_ERROR_EVENTS (EPOLLERR)
|
|
#define _EPOLL_HUNGUP_EVENTS (EPOLLHUP | EPOLLRDHUP)
|
|
#define _EPOLL_ALL_ERROR_EVENTS (_EPOLL_ERROR_EVENTS | _EPOLL_HUNGUP_EVENTS)
|
|
#define _EPOLL_ALL_NORMAL_EVENTS (_EPOLL_NORMAL_RW_EVENTS | _EPOLL_ALL_ERROR_EVENTS)
|
|
#define _EPOLL_ALL_EVENTS (_EPOLL_ALL_RW_EVENTS | _EPOLL_ALL_ERROR_EVENTS)
|
|
|
|
#define DISP_EVENT_FLAG_R 1
|
|
#define DISP_EVENT_FLAG_W 2
|
|
#define DISP_EVENT_FLAG_H 4
|
|
#define RETRIVE_EVENT_FLAG_R(evt) ((evt) & (_EPOLL_ALL_READ_EVENTS) ? DISP_EVENT_FLAG_R : 0)
|
|
#define RETRIVE_EVENT_FLAG_W(evt) ((evt) & (_EPOLL_WRITE_EVENTS) ? DISP_EVENT_FLAG_W : 0)
|
|
#define RETRIVE_EVENT_FLAG_RW(evt) (RETRIVE_EVENT_FLAG_R(evt) | RETRIVE_EVENT_FLAG_W(evt))
|
|
#define RETRIVE_EVENT_FLAG_H(evt) ((evt) & (_EPOLL_HUNGUP_EVENTS) ? DISP_EVENT_FLAG_H : 0)
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------- //
|
|
|
|
struct TDispCommand
|
|
{
|
|
USHORT type;
|
|
UINT_PTR wParam;
|
|
UINT_PTR lParam;
|
|
|
|
static TDispCommand* Construct(USHORT t, UINT_PTR wp = 0, UINT_PTR lp = 0)
|
|
{return new TDispCommand(t, wp, lp);}
|
|
|
|
static VOID Destruct(TDispCommand* p)
|
|
{if(p) delete p;}
|
|
|
|
private:
|
|
TDispCommand(USHORT t, UINT_PTR wp = 0, UINT_PTR lp = 0)
|
|
: type(t), wParam(wp), lParam(lp)
|
|
{
|
|
}
|
|
|
|
~TDispCommand() = default;
|
|
};
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------- //
|
|
|
|
class IIOHandler
|
|
{
|
|
public:
|
|
|
|
virtual VOID OnCommand(TDispCommand* pCmd) = 0;
|
|
virtual VOID OnTimer(ULLONG llExpirations) = 0;
|
|
|
|
virtual BOOL OnBeforeProcessIo(PVOID pv, UINT events) = 0;
|
|
virtual VOID OnAfterProcessIo(PVOID pv, UINT events, BOOL rs) = 0;
|
|
virtual BOOL OnReadyRead(PVOID pv, UINT events) = 0;
|
|
virtual BOOL OnReadyWrite(PVOID pv, UINT events) = 0;
|
|
virtual BOOL OnHungUp(PVOID pv, UINT events) = 0;
|
|
virtual BOOL OnError(PVOID pv, UINT events) = 0;
|
|
virtual BOOL OnReadyPrivilege(PVOID pv, UINT events) = 0;
|
|
|
|
virtual VOID OnDispatchThreadStart(THR_ID tid) = 0;
|
|
virtual VOID OnDispatchThreadEnd(THR_ID tid) = 0;
|
|
|
|
public:
|
|
virtual ~IIOHandler() = default;
|
|
};
|
|
|
|
class CIOHandler : public IIOHandler
|
|
{
|
|
public:
|
|
virtual VOID OnCommand(TDispCommand* pCmd) override {}
|
|
virtual VOID OnTimer(ULLONG llExpirations) override {}
|
|
|
|
virtual BOOL OnBeforeProcessIo(PVOID pv, UINT events) override {return TRUE;}
|
|
virtual VOID OnAfterProcessIo(PVOID pv, UINT events, BOOL rs) override {}
|
|
virtual BOOL OnReadyWrite(PVOID pv, UINT events) override {return TRUE;}
|
|
virtual BOOL OnHungUp(PVOID pv, UINT events) override {return TRUE;}
|
|
virtual BOOL OnError(PVOID pv, UINT events) override {return TRUE;}
|
|
virtual BOOL OnReadyPrivilege(PVOID pv, UINT events) override {return TRUE;}
|
|
virtual VOID OnDispatchThreadStart(THR_ID tid) override {}
|
|
virtual VOID OnDispatchThreadEnd(THR_ID tid) override {}
|
|
};
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------- //
|
|
|
|
class CIODispatcher
|
|
{
|
|
public:
|
|
static const int DEF_WORKER_MAX_EVENTS = 64;
|
|
|
|
using CCommandQueue = CCASQueue<TDispCommand>;
|
|
using CWorkerThread = CThread<CIODispatcher, VOID, int>;
|
|
|
|
public:
|
|
BOOL Start(IIOHandler* pHandler, int iWorkerMaxEvents = DEF_WORKER_MAX_EVENTS, int iWorkers = 0, LLONG llTimerInterval = 0);
|
|
BOOL Stop(BOOL bCheck = TRUE);
|
|
|
|
BOOL SendCommand(TDispCommand* pCmd);
|
|
BOOL SendCommand(USHORT t, UINT_PTR wp = 0, UINT_PTR lp = 0);
|
|
|
|
template<class _List, typename = enable_if_t<is_same<remove_reference_t<typename _List::reference>, TDispCommand*>::value>>
|
|
BOOL SendCommands(const _List& cmds)
|
|
{
|
|
size_t size = cmds.size();
|
|
if(size == 0) return FALSE;
|
|
|
|
for(auto it = cmds.begin(), end = cmds.end(); it != end; ++it)
|
|
m_queue.PushBack(*it);
|
|
|
|
return VERIFY_IS_NO_ERROR(eventfd_write(m_evCmd, size));
|
|
}
|
|
|
|
BOOL AddFD(FD fd, UINT mask, PVOID pv) {return CtlFD(fd, EPOLL_CTL_ADD, mask, pv);}
|
|
BOOL ModFD(FD fd, UINT mask, PVOID pv) {return CtlFD(fd, EPOLL_CTL_MOD, mask, pv);}
|
|
BOOL DelFD(FD fd) {return CtlFD(fd, EPOLL_CTL_DEL, 0, nullptr);}
|
|
BOOL CtlFD(FD fd, int op, UINT mask, PVOID pv);
|
|
|
|
BOOL ProcessIo(PVOID pv, UINT events);
|
|
|
|
FD AddTimer (LLONG llInterval, PVOID pv);
|
|
BOOL DelTimer (FD fdTimer);
|
|
|
|
private:
|
|
int WorkerProc(PVOID pv = nullptr);
|
|
BOOL ProcessExit(UINT events);
|
|
BOOL ProcessTimer(UINT events);
|
|
BOOL ProcessCommand(UINT events);
|
|
BOOL DoProcessIo(PVOID pv, UINT events);
|
|
|
|
VOID Reset();
|
|
VOID MakePrefix();
|
|
|
|
public:
|
|
BOOL HasStarted() {return m_pHandler && m_pWorkers;}
|
|
const CWorkerThread* GetWorkerThreads() {return m_pWorkers.get();}
|
|
|
|
CIODispatcher() {MakePrefix(); Reset();}
|
|
~CIODispatcher() {if(HasStarted()) Stop();}
|
|
|
|
private:
|
|
static LPCTSTR WORKER_THREAD_PREFIX;
|
|
static volatile UINT sm_uiNum;
|
|
|
|
volatile UINT m_uiSeq;
|
|
CString m_strPrefix;
|
|
|
|
private:
|
|
IIOHandler* m_pHandler;
|
|
FD m_epoll;
|
|
FD m_evCmd;
|
|
FD m_evExit;
|
|
FD m_evTimer;
|
|
int m_iWorkers;
|
|
int m_iMaxEvents;
|
|
|
|
CCommandQueue m_queue;
|
|
unique_ptr<CWorkerThread[]> m_pWorkers;
|
|
};
|