改为V5.9.6
This commit is contained in:
@@ -27,10 +27,10 @@
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
|
||||
volatile UINT CIODispatcher::sm_uiNum = MAXUINT;
|
||||
volatile UINT CIODispatcher::sm_uiNum = 0;
|
||||
LPCTSTR CIODispatcher::WORKER_THREAD_PREFIX = _T("io-disp-");
|
||||
|
||||
BOOL CIODispatcher::Start(IIOHandler* pHandler, int iWorkerMaxEvents, int iWorkers)
|
||||
BOOL CIODispatcher::Start(IIOHandler* pHandler, int iWorkerMaxEvents, int iWorkers, LLONG llTimerInterval)
|
||||
{
|
||||
ASSERT_CHECK_EINVAL(pHandler && iWorkerMaxEvents >= 0 && iWorkers >= 0);
|
||||
CHECK_ERROR(!HasStarted(), ERROR_INVALID_STATE);
|
||||
@@ -42,42 +42,44 @@ BOOL CIODispatcher::Start(IIOHandler* pHandler, int iWorkerMaxEvents, int iWorke
|
||||
m_iWorkers = iWorkers;
|
||||
m_pHandler = pHandler;
|
||||
|
||||
m_epoll = epoll_create1(EPOLL_CLOEXEC);
|
||||
CHECK_ERROR_FD(m_epoll);
|
||||
|
||||
m_evCmd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
|
||||
if(IS_INVALID_FD(m_evCmd))
|
||||
goto START_ERROR;
|
||||
|
||||
if(!VERIFY(AddFD(m_evCmd, EPOLLIN | EPOLLET, &m_evCmd)))
|
||||
goto START_ERROR;
|
||||
|
||||
m_evExit = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC | EFD_SEMAPHORE);
|
||||
|
||||
if(IS_INVALID_FD(m_evExit))
|
||||
goto START_ERROR;
|
||||
|
||||
m_pContexts = make_unique<TDispContext[]>(m_iWorkers);
|
||||
if(!VERIFY(AddFD(m_evExit, EPOLLIN, &m_evExit)))
|
||||
goto START_ERROR;
|
||||
|
||||
if(llTimerInterval > 0)
|
||||
{
|
||||
m_evTimer = AddTimer(llTimerInterval, &m_evTimer);
|
||||
|
||||
if(IS_INVALID_FD(m_evTimer))
|
||||
goto START_ERROR;
|
||||
}
|
||||
|
||||
sigset_t ss;
|
||||
sigemptyset(&ss);
|
||||
sigaddset(&ss, SIGPIPE);
|
||||
|
||||
VERIFY_IS_NO_ERROR(pthread_sigmask(SIG_BLOCK, &ss, nullptr));
|
||||
|
||||
m_pWorkers = make_unique<CWorkerThread[]>(m_iWorkers);
|
||||
|
||||
for(int i = 0; i < m_iWorkers; i++)
|
||||
{
|
||||
TDispContext& ctx = m_pContexts[i];
|
||||
|
||||
ctx.m_iIndex = i;
|
||||
|
||||
ctx.m_epoll = epoll_create1(EPOLL_CLOEXEC);
|
||||
CHECK_ERROR_FD(ctx.m_epoll);
|
||||
|
||||
ctx.m_evCmd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
|
||||
if(IS_INVALID_FD(ctx.m_evCmd))
|
||||
goto START_ERROR;
|
||||
|
||||
if(!VERIFY(AddFD(i, ctx.m_evCmd, EPOLLIN | EPOLLET, &ctx.m_evCmd)))
|
||||
goto START_ERROR;
|
||||
|
||||
if(!VERIFY(AddFD(i, m_evExit, EPOLLIN, &m_evExit)))
|
||||
goto START_ERROR;
|
||||
|
||||
sigset_t ss;
|
||||
sigemptyset(&ss);
|
||||
sigaddset(&ss, SIGPIPE);
|
||||
|
||||
VERIFY_IS_NO_ERROR(pthread_sigmask(SIG_BLOCK, &ss, nullptr));
|
||||
|
||||
ctx.m_pWorker = make_unique<CWorkerThread>();
|
||||
|
||||
if(!VERIFY(ctx.m_pWorker->Start(this, &CIODispatcher::WorkerProc, &ctx)))
|
||||
if(!VERIFY(m_pWorkers[i].Start(this, &CIODispatcher::WorkerProc)))
|
||||
goto START_ERROR;
|
||||
}
|
||||
|
||||
@@ -94,38 +96,36 @@ BOOL CIODispatcher::Stop(BOOL bCheck)
|
||||
|
||||
BOOL isOK = TRUE;
|
||||
|
||||
if(m_pContexts)
|
||||
if(m_pWorkers)
|
||||
{
|
||||
isOK &= IS_NO_ERROR(eventfd_write(m_evExit, m_iWorkers));
|
||||
|
||||
for(int i = 0; i < m_iWorkers; i++)
|
||||
{
|
||||
TDispContext& ctx = m_pContexts[i];
|
||||
isOK &= m_pWorkers[i].Join();
|
||||
}
|
||||
|
||||
if(ctx.m_pWorker)
|
||||
isOK &= ctx.m_pWorker->Join();
|
||||
if(!m_queue.IsEmpty())
|
||||
{
|
||||
TDispCommand* pCmd = nullptr;
|
||||
|
||||
if(!ctx.m_queue.IsEmpty())
|
||||
{
|
||||
TDispCommand* pCmd = nullptr;
|
||||
while(m_queue.PopFront(&pCmd))
|
||||
TDispCommand::Destruct(pCmd);
|
||||
|
||||
while(ctx.m_queue.PopFront(&pCmd))
|
||||
TDispCommand::Destruct(pCmd);
|
||||
|
||||
VERIFY(ctx.m_queue.IsEmpty());
|
||||
}
|
||||
|
||||
if(IS_VALID_FD(ctx.m_evCmd))
|
||||
isOK &= IS_NO_ERROR(close(ctx.m_evCmd));
|
||||
|
||||
if(IS_VALID_FD(ctx.m_epoll))
|
||||
isOK &= IS_NO_ERROR(close(ctx.m_epoll));
|
||||
}
|
||||
VERIFY(m_queue.IsEmpty());
|
||||
}
|
||||
|
||||
if(IS_VALID_FD(m_evExit))
|
||||
isOK &= IS_NO_ERROR(close(m_evExit));
|
||||
|
||||
if(IS_VALID_FD(m_evCmd))
|
||||
isOK &= IS_NO_ERROR(close(m_evCmd));
|
||||
|
||||
if(IS_VALID_FD(m_evTimer))
|
||||
isOK &= IS_NO_ERROR(close(m_evTimer));
|
||||
|
||||
if(IS_VALID_FD(m_epoll))
|
||||
isOK &= IS_NO_ERROR(close(m_epoll));
|
||||
|
||||
Reset();
|
||||
|
||||
return isOK;
|
||||
@@ -133,78 +133,54 @@ BOOL CIODispatcher::Stop(BOOL bCheck)
|
||||
|
||||
VOID CIODispatcher::Reset()
|
||||
{
|
||||
m_uiSeq = MAXUINT;
|
||||
m_uiSeq = 0;
|
||||
m_iWorkers = 0;
|
||||
m_iMaxEvents= 0;
|
||||
m_evExit = INVALID_FD;
|
||||
m_pHandler = nullptr;
|
||||
m_pContexts = nullptr;
|
||||
m_pWorkers = nullptr;
|
||||
m_epoll = INVALID_FD;
|
||||
m_evCmd = INVALID_FD;
|
||||
m_evExit = INVALID_FD;
|
||||
m_evTimer = INVALID_FD;
|
||||
}
|
||||
|
||||
VOID CIODispatcher::MakePrefix()
|
||||
|
||||
void CIODispatcher::MakePrefix()
|
||||
{
|
||||
UINT uiNumber = ::InterlockedIncrement(&sm_uiNum);
|
||||
|
||||
m_strPrefix.Format(_T("%s%u-"), WORKER_THREAD_PREFIX, uiNumber);
|
||||
}
|
||||
|
||||
TDispContext& CIODispatcher::GetContext(int idx, FD fd)
|
||||
BOOL CIODispatcher::SendCommand(USHORT t, UINT_PTR wp, UINT_PTR lp)
|
||||
{
|
||||
if(idx < 0) idx = fd;
|
||||
ASSERT(idx >= 0);
|
||||
if(idx >= m_iWorkers) idx %= m_iWorkers;
|
||||
|
||||
return m_pContexts[idx];
|
||||
return SendCommand(TDispCommand::Construct(t, wp, lp));
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::SendCommandByIndex(int idx, USHORT t, UINT_PTR wp, UINT_PTR lp)
|
||||
BOOL CIODispatcher::SendCommand(TDispCommand* pCmd)
|
||||
{
|
||||
return SendCommandByIndex(idx, TDispCommand::Construct(t, wp, lp));
|
||||
m_queue.PushBack(pCmd);
|
||||
return VERIFY_IS_NO_ERROR(eventfd_write(m_evCmd, 1));
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::SendCommandByIndex(int idx, TDispCommand* pCmd)
|
||||
BOOL CIODispatcher::CtlFD(FD fd, int op, UINT mask, PVOID pv)
|
||||
{
|
||||
TDispContext& ctx = GetContextByIndex(idx);
|
||||
return SendCommand(ctx, pCmd);
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::SendCommandByFD(FD fd, USHORT t, UINT_PTR wp, UINT_PTR lp)
|
||||
{
|
||||
return SendCommandByFD(fd, TDispCommand::Construct(t, wp, lp));
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::SendCommandByFD(FD fd, TDispCommand* pCmd)
|
||||
{
|
||||
TDispContext& ctx = GetContextByFD(fd);
|
||||
return SendCommand(ctx, pCmd);
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::SendCommand(TDispContext& ctx, TDispCommand* pCmd)
|
||||
{
|
||||
ctx.m_queue.PushBack(pCmd);
|
||||
return VERIFY_IS_NO_ERROR(eventfd_write(ctx.m_evCmd, 1));
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::CtlFD(int idx, FD fd, int op, UINT mask, PVOID pv)
|
||||
{
|
||||
const TDispContext& ctx = GetContext(idx, fd);
|
||||
|
||||
epoll_event evt = {mask, pv};
|
||||
return IS_NO_ERROR(epoll_ctl(ctx.m_epoll, op, fd, &evt));
|
||||
return IS_NO_ERROR(epoll_ctl(m_epoll, op, fd, &evt));
|
||||
}
|
||||
|
||||
int CIODispatcher::WorkerProc(TDispContext* pContext)
|
||||
int CIODispatcher::WorkerProc(PVOID pv)
|
||||
{
|
||||
::SetSequenceThreadName(SELF_THREAD_ID, m_strPrefix, m_uiSeq);
|
||||
|
||||
m_pHandler->OnDispatchThreadStart(SELF_THREAD_ID);
|
||||
|
||||
BOOL bRun = TRUE;
|
||||
unique_ptr<epoll_event[]> pEvents = make_unique<epoll_event[]>(m_iMaxEvents);
|
||||
BOOL bRun = TRUE;
|
||||
unique_ptr<epoll_event[]> pEvents = make_unique<epoll_event[]>(m_iMaxEvents);
|
||||
|
||||
while(bRun)
|
||||
{
|
||||
int rs = NO_EINTR_INT(epoll_pwait(pContext->m_epoll, pEvents.get(), m_iMaxEvents, INFINITE, nullptr));
|
||||
int rs = NO_EINTR_INT(epoll_pwait(m_epoll, pEvents.get(), m_iMaxEvents, INFINITE, nullptr));
|
||||
|
||||
if(rs <= TIMEOUT)
|
||||
ERROR_ABORT();
|
||||
@@ -214,12 +190,14 @@ int CIODispatcher::WorkerProc(TDispContext* pContext)
|
||||
UINT events = pEvents[i].events;
|
||||
PVOID ptr = pEvents[i].data.ptr;
|
||||
|
||||
if(ptr == &pContext->m_evCmd)
|
||||
ProcessCommand(pContext, events);
|
||||
if(ptr == &m_evCmd)
|
||||
ProcessCommand(events);
|
||||
else if(ptr == &m_evTimer)
|
||||
ProcessTimer(events);
|
||||
else if(ptr == &m_evExit)
|
||||
bRun = ProcessExit(pContext, events);
|
||||
bRun = ProcessExit(events);
|
||||
else
|
||||
ProcessIo(pContext, ptr, events);
|
||||
ProcessIo(ptr, events);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +206,7 @@ int CIODispatcher::WorkerProc(TDispContext* pContext)
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::ProcessCommand(TDispContext* pContext, UINT events)
|
||||
BOOL CIODispatcher::ProcessCommand(UINT events)
|
||||
{
|
||||
if(events & _EPOLL_ALL_ERROR_EVENTS)
|
||||
ERROR_ABORT();
|
||||
@@ -240,7 +218,7 @@ BOOL CIODispatcher::ProcessCommand(TDispContext* pContext, UINT events)
|
||||
|
||||
eventfd_t v;
|
||||
|
||||
int rs = eventfd_read(pContext->m_evCmd, &v);
|
||||
int rs = eventfd_read(m_evCmd, &v);
|
||||
|
||||
if(IS_NO_ERROR(rs))
|
||||
{
|
||||
@@ -248,9 +226,9 @@ BOOL CIODispatcher::ProcessCommand(TDispContext* pContext, UINT events)
|
||||
|
||||
TDispCommand* pCmd = nullptr;
|
||||
|
||||
while(pContext->m_queue.PopFront(&pCmd))
|
||||
while(m_queue.PopFront(&pCmd))
|
||||
{
|
||||
m_pHandler->OnCommand(pContext, pCmd);
|
||||
m_pHandler->OnCommand(pCmd);
|
||||
TDispCommand::Destruct(pCmd);
|
||||
}
|
||||
}
|
||||
@@ -264,7 +242,26 @@ BOOL CIODispatcher::ProcessCommand(TDispContext* pContext, UINT events)
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::ProcessExit(const TDispContext* pContext, UINT events)
|
||||
BOOL CIODispatcher::ProcessTimer(UINT events)
|
||||
{
|
||||
if(events & _EPOLL_ALL_ERROR_EVENTS)
|
||||
ERROR_ABORT();
|
||||
|
||||
if(!(events & EPOLLIN))
|
||||
return TRUE;
|
||||
|
||||
BOOL isOK = FALSE;
|
||||
ULLONG ullExpirations;
|
||||
|
||||
if(::ReadTimer(m_evTimer, &ullExpirations, &isOK) && isOK)
|
||||
m_pHandler->OnTimer(ullExpirations);
|
||||
else
|
||||
ASSERT(IS_WOULDBLOCK_ERROR());
|
||||
|
||||
return isOK;
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::ProcessExit(UINT events)
|
||||
{
|
||||
if(events & _EPOLL_ALL_ERROR_EVENTS)
|
||||
ERROR_ABORT();
|
||||
@@ -289,40 +286,40 @@ BOOL CIODispatcher::ProcessExit(const TDispContext* pContext, UINT events)
|
||||
return bRun;
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::ProcessIo(const TDispContext* pContext, PVOID pv, UINT events)
|
||||
BOOL CIODispatcher::ProcessIo(PVOID pv, UINT events)
|
||||
{
|
||||
if(!m_pHandler->OnBeforeProcessIo(pContext, pv, events))
|
||||
if(!m_pHandler->OnBeforeProcessIo(pv, events))
|
||||
return FALSE;
|
||||
|
||||
BOOL rs = DoProcessIo(pContext, pv, events);
|
||||
m_pHandler->OnAfterProcessIo(pContext, pv, events, rs);
|
||||
BOOL rs = DoProcessIo(pv, events);
|
||||
m_pHandler->OnAfterProcessIo(pv, events, rs);
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::DoProcessIo(const TDispContext* pContext, PVOID pv, UINT events)
|
||||
BOOL CIODispatcher::DoProcessIo(PVOID pv, UINT events)
|
||||
{
|
||||
if(events & EPOLLERR)
|
||||
return m_pHandler->OnError(pContext, pv, events);
|
||||
if((events & EPOLLPRI) && !m_pHandler->OnReadyPrivilege(pContext, pv, events))
|
||||
return m_pHandler->OnError(pv, events);
|
||||
if((events & EPOLLPRI) && !m_pHandler->OnReadyPrivilege(pv, events))
|
||||
return FALSE;
|
||||
if((events & EPOLLIN) && !m_pHandler->OnReadyRead(pContext, pv, events))
|
||||
if((events & EPOLLIN) && !m_pHandler->OnReadyRead(pv, events))
|
||||
return FALSE;
|
||||
if((events & EPOLLOUT) && !m_pHandler->OnReadyWrite(pContext, pv, events))
|
||||
if((events & EPOLLOUT) && !m_pHandler->OnReadyWrite(pv, events))
|
||||
return FALSE;
|
||||
if((events & (_EPOLL_HUNGUP_EVENTS)) && !m_pHandler->OnHungUp(pContext, pv, events))
|
||||
if((events & (_EPOLL_HUNGUP_EVENTS)) && !m_pHandler->OnHungUp(pv, events))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
FD CIODispatcher::AddTimer(int idx, LLONG llInterval, PVOID pv)
|
||||
FD CIODispatcher::AddTimer(LLONG llInterval, PVOID pv)
|
||||
{
|
||||
FD fdTimer = ::CreateTimer(llInterval);
|
||||
|
||||
if(IS_VALID_FD(fdTimer))
|
||||
{
|
||||
if(!AddFD(idx, fdTimer, EPOLLIN | EPOLLET, pv))
|
||||
if(!AddFD(fdTimer, EPOLLIN | EPOLLET, pv))
|
||||
{
|
||||
close(fdTimer);
|
||||
fdTimer = INVALID_FD;
|
||||
@@ -332,13 +329,13 @@ FD CIODispatcher::AddTimer(int idx, LLONG llInterval, PVOID pv)
|
||||
return fdTimer;
|
||||
}
|
||||
|
||||
BOOL CIODispatcher::DelTimer(int idx, FD fdTimer)
|
||||
BOOL CIODispatcher::DelTimer(FD fdTimer)
|
||||
{
|
||||
BOOL isOK = FALSE;
|
||||
|
||||
if(IS_VALID_FD(fdTimer))
|
||||
{
|
||||
if(DelFD(idx, fdTimer))
|
||||
if(DelFD(fdTimer))
|
||||
isOK = TRUE;
|
||||
|
||||
close(fdTimer);
|
||||
|
||||
Reference in New Issue
Block a user