PageRenderTime 38ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/mordor/iomanager_iocp.h

http://github.com/mozy/mordor
C Header | 167 lines | 85 code | 29 blank | 53 comment | 0 complexity | 3c9e3e4ef7656d600e08e6dad7ab55d1 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. #ifndef __MORDOR_IOMANAGER_IOCP_H__
  2. #define __MORDOR_IOMANAGER_IOCP_H__
  3. #include <map>
  4. #include <boost/enable_shared_from_this.hpp>
  5. #include <boost/shared_ptr.hpp>
  6. #include <boost/thread/mutex.hpp>
  7. #include "scheduler.h"
  8. #include "timer.h"
  9. #include "version.h"
  10. #ifndef WINDOWS
  11. #error IOManagerIOCP is Windows only
  12. #endif
  13. namespace Mordor {
  14. class Fiber;
  15. struct AsyncEvent
  16. {
  17. AsyncEvent();
  18. OVERLAPPED overlapped;
  19. Scheduler *m_scheduler;
  20. tid_t m_thread;
  21. boost::shared_ptr<Fiber> m_fiber;
  22. };
  23. class IOManager : public Scheduler, public TimerManager
  24. {
  25. friend class WaitBlock;
  26. private:
  27. class WaitBlock : public boost::enable_shared_from_this<WaitBlock>
  28. {
  29. public:
  30. typedef boost::shared_ptr<WaitBlock> ptr;
  31. public:
  32. WaitBlock(IOManager &outer);
  33. ~WaitBlock();
  34. bool registerEvent(HANDLE handle, boost::function<void ()> dg,
  35. bool recurring);
  36. size_t unregisterEvent(HANDLE handle);
  37. private:
  38. void run();
  39. void removeEntry(int index);
  40. private:
  41. boost::mutex m_mutex;
  42. IOManager &m_outer;
  43. HANDLE m_reconfigured;
  44. HANDLE m_handles[MAXIMUM_WAIT_OBJECTS];
  45. Scheduler *m_schedulers[MAXIMUM_WAIT_OBJECTS];
  46. boost::shared_ptr<Fiber> m_fibers[MAXIMUM_WAIT_OBJECTS];
  47. boost::function<void ()> m_dgs[MAXIMUM_WAIT_OBJECTS];
  48. bool m_recurring[MAXIMUM_WAIT_OBJECTS];
  49. int m_inUseCount;
  50. };
  51. public:
  52. IOManager(size_t threads = 1, bool useCaller = true, bool autoStart = true);
  53. ~IOManager();
  54. bool stopping();
  55. // Associate the handle with the IOManagers completion port
  56. // This must be called one per handle before making Windows
  57. // system calls that use asynchronous IO
  58. void registerFile(HANDLE handle);
  59. // Callers who have registered a handle with registerFile() must
  60. // call this method to prepare the IOManager before performing a
  61. // Windows system call on that handle that expects a OVERLAPPED structure
  62. // (e.g. ConnectEx, WSASend, ReadDirectoryChanges etc)
  63. // The IOManager will add context information to the AsyncEvent structure.
  64. // The caller must then pass the AsyncEvent::overlapped member
  65. // as the lpOverlapped argument for the async IO call.
  66. // After making the async call the caller will normally call yieldTo() to stop
  67. // execution. The IOManager will resume the caller fiber when the IO call completes.
  68. // At that point the caller can use the AsyncEvent::overlapped member to learn
  69. // the result of the IO call.
  70. void registerEvent(AsyncEvent *e);
  71. // If a caller has called registerEvent to prepare for an Async IO call
  72. // but then the Async IO call fails this must be called so that the IOManager
  73. // does not wait for the Async IO call to complete.
  74. // This does not work to cancel a successfully launched Async IO call.
  75. void unregisterEvent(AsyncEvent *e);
  76. // Register a handle to an Windows Event.
  77. // The callback "dg" will be scheduled once the event
  78. // is signalled.
  79. void registerEvent(HANDLE handle, boost::function<void ()> dg,
  80. bool recurring = false);
  81. // Register a handle to an Windows Event.
  82. // Use this method when a fiber wants to sleep until an event is signalled.
  83. // The caller will typically yield its fiber immediately after
  84. // calling this method and the fiber will be rescheduled as
  85. // soon as the event is signalled.
  86. // (see CreateEventW, WaitForMultipleObjects, WSAEventSelect)
  87. // Note: See FiberEvent for a cross platform event primitive.
  88. void registerEvent(HANDLE handle, bool recurring = false)
  89. { registerEvent(handle, NULL, recurring); }
  90. // Cancel the registration of event handle that was previously
  91. // registered with the IOManager
  92. size_t unregisterEvent(HANDLE handle);
  93. // Cancel an Async IO call that has already been successfully launched.
  94. // If successfully the fiber that is waiting for the result
  95. // will be resumed and the AsyncEvent::overlapped will have the
  96. // ERROR_OPERATION_ABORTED result.
  97. void cancelEvent(HANDLE hFile, AsyncEvent *e);
  98. // #111932
  99. // HACK (hopefully temporary).
  100. // This method allows the caller to specify the number of errors to ignore when
  101. // calling PostQueuedCompletionStatus in the tickle() method. The default value is 0.
  102. // The Sync product has experienced some "Insufficient system resources" errors
  103. // returned by PostQueuedCompletionStatus, possibly indicating the the IOCP queue is full.
  104. // Be careful when using this method as it is possible for the corresponding
  105. // GetQueuedCompletionStatusEx call in idle() to wait infinitely, which could cause deadlock if
  106. // the PostQueuedCompletionStatus failure is ignored. (Sync makes use of many Timers which
  107. // should ensure that GetQueuedCompletionStatusEx will not ever wait infinitely.)
  108. // Parameters
  109. // count: The number of errors to allow
  110. // seconds: The time span within which the number of errors must exceed the maximum specified in count.
  111. static void setIOCPErrorTolerance(size_t count, size_t seconds);
  112. protected:
  113. bool stopping(unsigned long long &nextTimeout);
  114. void idle();
  115. void tickle();
  116. // Call when a new timer is added that will be the next timer
  117. // to expire. We have to tickle() the IOManager so that it can
  118. // adjust the timeout value in its blocking call to GetQueuedCompletionStatusEx
  119. // so that it doesn't miss the timer
  120. void onTimerInsertedAtFront() { tickle(); }
  121. private:
  122. HANDLE m_hCompletionPort;
  123. #ifndef NDEBUG
  124. std::map<OVERLAPPED *, AsyncEvent*> m_pendingEvents;
  125. #endif
  126. size_t m_pendingEventCount;
  127. boost::mutex m_mutex;
  128. std::list<WaitBlock::ptr> m_waitBlocks;
  129. // These variables are part of the hack for #111932.
  130. // See the comment for setIOCPErrorTolerance().
  131. static boost::mutex m_errorMutex;
  132. static size_t m_iocpAllowedErrorCount;
  133. static size_t m_iocpErrorCountWindowInSeconds;
  134. static size_t m_errorCount;
  135. static unsigned long long m_firstErrorTime;
  136. };
  137. }
  138. #endif