IODispatcher.h 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. * Copyright: JessMA Open Source (ldcsaa@gmail.com)
  3. *
  4. * Author : Bruce Liang
  5. * Website : https://github.com/ldcsaa
  6. * Project : https://github.com/ldcsaa/HP-Socket
  7. * Blog : http://www.cnblogs.com/ldcsaa
  8. * Wiki : http://www.oschina.net/p/hp-socket
  9. * QQ Group : 44636872, 75375912
  10. *
  11. * Licensed under the Apache License, Version 2.0 (the "License");
  12. * you may not use this file except in compliance with the License.
  13. * You may obtain a copy of the License at
  14. *
  15. * http://www.apache.org/licenses/LICENSE-2.0
  16. *
  17. * Unless required by applicable law or agreed to in writing, software
  18. * distributed under the License is distributed on an "AS IS" BASIS,
  19. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  20. * See the License for the specific language governing permissions and
  21. * limitations under the License.
  22. */
  23. #pragma once
  24. #include "hpsocket/GlobalDef.h"
  25. #include "Singleton.h"
  26. #include "RingBuffer.h"
  27. #include "Thread.h"
  28. #include <sys/epoll.h>
  29. #include <sys/eventfd.h>
  30. #include <sys/timerfd.h>
  31. #include <memory>
  32. using namespace std;
  33. #define _EPOLL_READ_PRI_EVENTS (EPOLLPRI | EPOLLRDHUP)
  34. #define _EPOLL_READ_EVENTS (EPOLLIN | EPOLLRDHUP)
  35. #define _EPOLL_ALL_READ_EVENTS (_EPOLL_READ_EVENTS | _EPOLL_READ_PRI_EVENTS)
  36. #define _EPOLL_WRITE_EVENTS (EPOLLOUT)
  37. #define _EPOLL_NORMAL_RW_EVENTS (_EPOLL_READ_EVENTS | _EPOLL_WRITE_EVENTS)
  38. #define _EPOLL_ALL_RW_EVENTS (_EPOLL_ALL_READ_EVENTS | _EPOLL_WRITE_EVENTS)
  39. #define _EPOLL_ERROR_EVENTS (EPOLLERR)
  40. #define _EPOLL_HUNGUP_EVENTS (EPOLLHUP | EPOLLRDHUP)
  41. #define _EPOLL_ALL_ERROR_EVENTS (_EPOLL_ERROR_EVENTS | _EPOLL_HUNGUP_EVENTS)
  42. #define _EPOLL_ALL_NORMAL_EVENTS (_EPOLL_NORMAL_RW_EVENTS | _EPOLL_ALL_ERROR_EVENTS)
  43. #define _EPOLL_ALL_EVENTS (_EPOLL_ALL_RW_EVENTS | _EPOLL_ALL_ERROR_EVENTS)
  44. #define DISP_EVENT_FLAG_R 0x1
  45. #define DISP_EVENT_FLAG_W 0x2
  46. #define DISP_EVENT_FLAG_H 0x4
  47. #define RETRIVE_EVENT_FLAG_R(evt) ((evt) & (_EPOLL_ALL_READ_EVENTS) ? DISP_EVENT_FLAG_R : 0)
  48. #define RETRIVE_EVENT_FLAG_W(evt) ((evt) & (_EPOLL_WRITE_EVENTS) ? DISP_EVENT_FLAG_W : 0)
  49. #define RETRIVE_EVENT_FLAG_RW(evt) (RETRIVE_EVENT_FLAG_R(evt) | RETRIVE_EVENT_FLAG_W(evt))
  50. #define RETRIVE_EVENT_FLAG_H(evt) ((evt) & (_EPOLL_HUNGUP_EVENTS) ? DISP_EVENT_FLAG_H : 0)
  51. #ifndef EPOLLEXCLUSIVE
  52. #define EPOLLEXCLUSIVE (1u << 28)
  53. #endif
  54. #define MAYBE_EPOLLEXCLUSIVE (::IsKernelVersionAbove(4, 5, 0) ? EPOLLEXCLUSIVE : 0)
  55. // ------------------------------------------------------------------------------------------------------------------------------------------------------- //
  56. struct TDispCommand;
  57. class CIODispatcher;
  58. struct TDispContext
  59. {
  60. friend class CIODispatcher;
  61. using CCommandQueue = CCASQueue<TDispCommand>;
  62. using CWorkerThread = CThread<CIODispatcher, TDispContext, int>;
  63. public:
  64. int GetIndex() const {return m_iIndex;}
  65. THR_ID GetThreadId() const {return m_pWorker != nullptr ? m_pWorker->GetThreadID() : 0;}
  66. public:
  67. TDispContext() {Reset();}
  68. ~TDispContext() = default;
  69. DECLARE_NO_COPY_CLASS(TDispContext)
  70. private:
  71. VOID Reset()
  72. {
  73. m_iIndex = -1;
  74. m_epoll = INVALID_FD;
  75. m_evCmd = INVALID_FD;
  76. m_pWorker = nullptr;
  77. }
  78. private:
  79. int m_iIndex;
  80. FD m_epoll;
  81. FD m_evCmd;
  82. CCommandQueue m_queue;
  83. unique_ptr<CWorkerThread> m_pWorker;
  84. };
  85. struct TDispCommand
  86. {
  87. USHORT type;
  88. UINT_PTR wParam;
  89. UINT_PTR lParam;
  90. static TDispCommand* Construct(USHORT t, UINT_PTR wp = 0, UINT_PTR lp = 0)
  91. {return new TDispCommand(t, wp, lp);}
  92. static VOID Destruct(TDispCommand* p)
  93. {if(p) delete p;}
  94. private:
  95. TDispCommand(USHORT t, UINT_PTR wp = 0, UINT_PTR lp = 0)
  96. : type(t), wParam(wp), lParam(lp)
  97. {
  98. }
  99. ~TDispCommand() = default;
  100. };
  101. // ------------------------------------------------------------------------------------------------------------------------------------------------------- //
  102. class IIOHandler
  103. {
  104. public:
  105. virtual VOID OnCommand(const TDispContext* pContext, TDispCommand* pCmd) = 0;
  106. virtual BOOL OnBeforeProcessIo(const TDispContext* pContext, PVOID pv, UINT events) = 0;
  107. virtual VOID OnAfterProcessIo(const TDispContext* pContext, PVOID pv, UINT events, BOOL rs) = 0;
  108. virtual BOOL OnReadyRead(const TDispContext* pContext, PVOID pv, UINT events) = 0;
  109. virtual BOOL OnReadyWrite(const TDispContext* pContext, PVOID pv, UINT events) = 0;
  110. virtual BOOL OnHungUp(const TDispContext* pContext, PVOID pv, UINT events) = 0;
  111. virtual BOOL OnError(const TDispContext* pContext, PVOID pv, UINT events) = 0;
  112. virtual BOOL OnReadyPrivilege(const TDispContext* pContext, PVOID pv, UINT events) = 0;
  113. virtual VOID OnDispatchThreadStart(THR_ID tid) = 0;
  114. virtual VOID OnDispatchThreadEnd(THR_ID tid) = 0;
  115. public:
  116. virtual ~IIOHandler() = default;
  117. };
  118. class CIOHandler : public IIOHandler
  119. {
  120. public:
  121. virtual VOID OnCommand(const TDispContext* pContext, TDispCommand* pCmd) override {}
  122. virtual BOOL OnBeforeProcessIo(const TDispContext* pContext, PVOID pv, UINT events) override {return TRUE;}
  123. virtual VOID OnAfterProcessIo(const TDispContext* pContext, PVOID pv, UINT events, BOOL rs) override {}
  124. virtual BOOL OnReadyWrite(const TDispContext* pContext, PVOID pv, UINT events) override {return TRUE;}
  125. virtual BOOL OnHungUp(const TDispContext* pContext, PVOID pv, UINT events) override {return TRUE;}
  126. virtual BOOL OnError(const TDispContext* pContext, PVOID pv, UINT events) override {return TRUE;}
  127. virtual BOOL OnReadyPrivilege(const TDispContext* pContext, PVOID pv, UINT events) override {return TRUE;}
  128. virtual VOID OnDispatchThreadStart(THR_ID tid) override {}
  129. virtual VOID OnDispatchThreadEnd(THR_ID tid) override {}
  130. };
  131. // ------------------------------------------------------------------------------------------------------------------------------------------------------- //
  132. class CIODispatcher
  133. {
  134. public:
  135. static const int DEF_WORKER_MAX_EVENTS = 64;
  136. using CCommandQueue = TDispContext::CCommandQueue;
  137. using CWorkerThread = TDispContext::CWorkerThread;
  138. public:
  139. BOOL Start(IIOHandler* pHandler, int iWorkerMaxEvents = DEF_WORKER_MAX_EVENTS, int iWorkers = 0);
  140. BOOL Stop(BOOL bCheck = TRUE);
  141. BOOL SendCommandByIndex(int idx, TDispCommand* pCmd);
  142. BOOL SendCommandByIndex(int idx, USHORT t, UINT_PTR wp = 0, UINT_PTR lp = 0);
  143. BOOL SendCommandByFD(FD fd, TDispCommand* pCmd);
  144. BOOL SendCommandByFD(FD fd, USHORT t, UINT_PTR wp = 0, UINT_PTR lp = 0);
  145. BOOL SendCommand(TDispContext& ctx, TDispCommand* pCmd);
  146. template<class _List, typename = enable_if_t<is_same<remove_reference_t<typename _List::reference>, TDispCommand*>::value>>
  147. BOOL SendCommandsByIndex(int idx, const _List& cmds)
  148. {
  149. TDispContext& ctx = GetContextByIndex(idx);
  150. return SendCommands(ctx, cmds);
  151. }
  152. template<class _List, typename = enable_if_t<is_same<remove_reference_t<typename _List::reference>, TDispCommand*>::value>>
  153. BOOL SendCommandsByFD(FD fd, const _List& cmds)
  154. {
  155. TDispContext& ctx = GetContextByFD(fd);
  156. return SendCommands(ctx, cmds);
  157. }
  158. template<class _List, typename = enable_if_t<is_same<remove_reference_t<typename _List::reference>, TDispCommand*>::value>>
  159. BOOL SendCommands(TDispContext& ctx, const _List& cmds)
  160. {
  161. size_t size = cmds.size();
  162. if(size == 0) return FALSE;
  163. for(auto it = cmds.begin(), end = cmds.end(); it != end; ++it)
  164. ctx.m_queue.PushBack(*it);
  165. return VERIFY_IS_NO_ERROR(eventfd_write(ctx.m_evCmd, size));
  166. }
  167. BOOL AddFD(int idx, FD fd, UINT mask, PVOID pv) {return CtlFD(idx, fd, EPOLL_CTL_ADD, mask, pv);}
  168. BOOL ModFD(int idx, FD fd, UINT mask, PVOID pv) {return CtlFD(idx, fd, EPOLL_CTL_MOD, mask, pv);}
  169. BOOL DelFD(int idx, FD fd) {return CtlFD(idx, fd, EPOLL_CTL_DEL, 0, nullptr);}
  170. BOOL CtlFD(int idx, FD fd, int op, UINT mask, PVOID pv);
  171. BOOL AddFD(FD fd, UINT mask, PVOID pv) {return CtlFD(-1, fd, EPOLL_CTL_ADD, mask, pv);}
  172. BOOL ModFD(FD fd, UINT mask, PVOID pv) {return CtlFD(-1, fd, EPOLL_CTL_MOD, mask, pv);}
  173. BOOL DelFD(FD fd) {return CtlFD(-1, fd, EPOLL_CTL_DEL, 0, nullptr);}
  174. BOOL CtlFD(FD fd, int op, UINT mask, PVOID pv) {return CtlFD(-1, fd, op, mask, pv);}
  175. BOOL ProcessIo(const TDispContext* pContext, PVOID pv, UINT events);
  176. FD AddTimer (int idx, LLONG llInterval, PVOID pv);
  177. BOOL DelTimer (int idx, FD fdTimer);
  178. FD AddTimer (LLONG llInterval, PVOID pv) {return AddTimer(-1, llInterval, pv);}
  179. BOOL DelTimer (FD fdTimer) {return DelTimer(-1, fdTimer);}
  180. private:
  181. int WorkerProc(TDispContext* pContext);
  182. BOOL ProcessExit(const TDispContext* pContext, UINT events);
  183. BOOL ProcessCommand(TDispContext* pContext, UINT events);
  184. BOOL DoProcessIo(const TDispContext* pContext, PVOID pv, UINT events);
  185. VOID Reset();
  186. VOID MakePrefix();
  187. TDispContext& GetContextByIndex(int idx) {return GetContext(idx, -1);}
  188. TDispContext& GetContextByFD(FD fd) {return GetContext(-1, fd);}
  189. TDispContext& GetContext(int idx, FD fd);
  190. public:
  191. const TDispContext& GetContextRefByIndex(int idx) {return GetContextByIndex(idx);}
  192. const TDispContext& GetContextRefByFD(FD fd) {return GetContextByFD(fd);}
  193. const TDispContext& GetContextRef(int idx, FD fd) {return GetContext(idx, fd);}
  194. BOOL HasStarted() {return m_pHandler && m_pContexts;}
  195. int GetWorkers() {return m_iWorkers;}
  196. const TDispContext* GetContexts() {return m_pContexts.get();}
  197. CIODispatcher() {MakePrefix(); Reset();}
  198. ~CIODispatcher() {if(HasStarted()) Stop();}
  199. DECLARE_NO_COPY_CLASS(CIODispatcher)
  200. private:
  201. static LPCTSTR WORKER_THREAD_PREFIX;
  202. static volatile UINT sm_uiNum;
  203. volatile UINT m_uiSeq;
  204. CString m_strPrefix;
  205. private:
  206. int m_iWorkers;
  207. int m_iMaxEvents;
  208. FD m_evExit;
  209. IIOHandler* m_pHandler;
  210. unique_ptr<TDispContext[]> m_pContexts;
  211. };