Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

265 lines
5.1 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) Microsoft Corporation
  4. //
  5. // SYNOPSIS
  6. //
  7. // Defines the class CommandPool.
  8. //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "ias.h"
  11. #include "commandpool.h"
  12. #include <climits>
  13. #include <new>
  14. CommandPool::CommandPool() throw ()
  15. : version(0),
  16. pool(0),
  17. maxCommands(1),
  18. numCommands(0),
  19. owners(0),
  20. waiters(0),
  21. semaphore(0)
  22. {
  23. }
  24. CommandPool::~CommandPool() throw ()
  25. {
  26. while (pool != 0)
  27. {
  28. delete Pop();
  29. }
  30. if (semaphore != 0)
  31. {
  32. DeleteCriticalSection(&lock);
  33. CloseHandle(semaphore);
  34. }
  35. }
  36. HRESULT CommandPool::FinalConstruct() throw ()
  37. {
  38. if (!InitializeCriticalSectionAndSpinCount(
  39. &lock,
  40. 0x80000000
  41. ))
  42. {
  43. DWORD error = GetLastError();
  44. return HRESULT_FROM_WIN32(error);
  45. }
  46. semaphore = CreateSemaphoreW(0, 0, LONG_MAX, 0);
  47. if (semaphore == 0)
  48. {
  49. DeleteCriticalSection(&lock);
  50. DWORD error = GetLastError();
  51. return HRESULT_FROM_WIN32(error);
  52. }
  53. return S_OK;
  54. }
  55. void CommandPool::SetMaxCommands(size_t newValue) throw ()
  56. {
  57. // Don't allow empty pools; otherwise, Alloc will block forever.
  58. if (newValue < 1)
  59. {
  60. newValue = 1;
  61. }
  62. // Number of waiters to release as a result of the change.
  63. long releaseCount = 0;
  64. Lock();
  65. maxCommands = newValue;
  66. // Are there any slots open? If so, we may need to release some waiters.
  67. if (owners < maxCommands)
  68. {
  69. // newOwners = min(open slots, waiters)
  70. size_t newOwners = maxCommands - owners;
  71. if (newOwners > waiters)
  72. {
  73. newOwners = waiters;
  74. }
  75. // Convert the threads from waiters to owners.
  76. waiters -= newOwners;
  77. owners += newOwners;
  78. releaseCount = static_cast<long>(newOwners);
  79. }
  80. // Delete any excess commands.
  81. while ((numCommands > maxCommands) && (pool != 0))
  82. {
  83. delete Pop();
  84. }
  85. Unlock();
  86. if (releaseCount > 0)
  87. {
  88. // Unlock before we release the semaphore because the other threads will
  89. // immediately try to acquire the lock.
  90. ReleaseSemaphore(semaphore, releaseCount, 0);
  91. }
  92. }
  93. ReportEventCommand* CommandPool::Alloc() throw ()
  94. {
  95. LockAndWait();
  96. ReportEventCommand* cmd;
  97. // If the pool isn't empty, ...
  98. if (pool != 0)
  99. {
  100. // ... then reuse one from the pool ...
  101. cmd = Pop();
  102. }
  103. else
  104. {
  105. // ... otherwise create a new object.
  106. cmd = new (std::nothrow) ReportEventCommand();
  107. if (cmd == 0)
  108. {
  109. // The resource acquired by the call to LockAndWait above is normally
  110. // released in Free, but since we're not returning a command to the
  111. // caller, we have to do it here.
  112. UnlockAndRelease();
  113. return 0;
  114. }
  115. ++numCommands;
  116. }
  117. cmd->SetVersion(version);
  118. Unlock();
  119. return cmd;
  120. }
  121. void CommandPool::Free(ReportEventCommand* cmd) throw ()
  122. {
  123. if (cmd != 0)
  124. {
  125. Lock();
  126. if (numCommands > maxCommands)
  127. {
  128. // There's too many commands, so delete.
  129. delete cmd;
  130. --numCommands;
  131. }
  132. else
  133. {
  134. // If the command is stale, reset it.
  135. if (cmd->Version() != version)
  136. {
  137. cmd->Unprepare();
  138. }
  139. // Return the command to the pool.
  140. Push(cmd);
  141. }
  142. UnlockAndRelease();
  143. }
  144. }
  145. void CommandPool::UnprepareAll() throw ()
  146. {
  147. Lock();
  148. ++version;
  149. for (ReportEventCommand* i = pool; i != 0; i = i->Next())
  150. {
  151. i->Unprepare();
  152. }
  153. Unlock();
  154. }
  155. inline void CommandPool::Lock() throw ()
  156. {
  157. EnterCriticalSection(&lock);
  158. }
  159. inline void CommandPool::Unlock() throw ()
  160. {
  161. LeaveCriticalSection(&lock);
  162. }
  163. inline void CommandPool::LockAndWait() throw ()
  164. {
  165. Lock();
  166. if (owners >= maxCommands)
  167. {
  168. // No available resources, so we wait.
  169. ++waiters;
  170. // Don't hold the lock while we're waiting.
  171. Unlock();
  172. WaitForSingleObject(semaphore, INFINITE);
  173. Lock();
  174. }
  175. else
  176. {
  177. ++owners;
  178. }
  179. }
  180. void CommandPool::UnlockAndRelease() throw ()
  181. {
  182. // Should we wake someone up?
  183. if ((waiters > 0) && (owners <= maxCommands))
  184. {
  185. // Convert one waiter to an owner. The owners count is unchanged since
  186. // the other thread is taking our place.
  187. --waiters;
  188. Unlock();
  189. // Unlock before we release the semaphore because the other thread will
  190. // immediately try to acquire the lock.
  191. ReleaseSemaphore(semaphore, 1, 0);
  192. }
  193. else
  194. {
  195. --owners;
  196. Unlock();
  197. }
  198. }
  199. inline void CommandPool::Push(ReportEventCommand* cmd) throw ()
  200. {
  201. cmd->SetNext(pool);
  202. pool = cmd;
  203. }
  204. inline ReportEventCommand* CommandPool::Pop() throw ()
  205. {
  206. ReportEventCommand* retval = pool;
  207. pool = retval->Next();
  208. return retval;
  209. }