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.

569 lines
14 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. tpswait.h
  5. Abstract:
  6. Wait classes. Moved out of tpsclass.h
  7. Contents:
  8. CWait
  9. CWaitRequest
  10. CWaitAddRequest
  11. CWaitRemoveRequest
  12. CWaitThreadInfo
  13. Author:
  14. Richard L Firth (rfirth) 08-Aug-1998
  15. Revision History:
  16. 08-Aug-1998 rfirth
  17. Created
  18. --*/
  19. //
  20. // forward declarations
  21. //
  22. class CWaitThreadInfo;
  23. //
  24. // classes
  25. //
  26. //
  27. // CWait
  28. //
  29. class CWait : public CTimedListEntry {
  30. private:
  31. HANDLE m_hObject;
  32. WAITORTIMERCALLBACKFUNC m_pCallback;
  33. LPVOID m_pContext;
  34. CWaitThreadInfo * m_pThreadInfo;
  35. DWORD m_dwFlags;
  36. public:
  37. CWait(HANDLE hObject,
  38. WAITORTIMERCALLBACKFUNC pCallback,
  39. LPVOID pContext,
  40. DWORD dwWaitTime,
  41. DWORD dwFlags,
  42. CWaitThreadInfo * pInfo
  43. ) : CTimedListEntry(dwWaitTime) {
  44. m_hObject = hObject;
  45. m_pCallback = pCallback;
  46. m_pContext = pContext;
  47. m_pThreadInfo = pInfo;
  48. m_dwFlags = dwFlags;
  49. }
  50. CWait() {
  51. }
  52. CWait * Next(VOID) {
  53. return (CWait *)CTimedListEntry::Next();
  54. }
  55. CWaitThreadInfo * GetThreadInfo(VOID) const {
  56. return m_pThreadInfo;
  57. }
  58. VOID Execute(BOOL bTimeout) {
  59. //
  60. // execute function in this thread if required to do so, else we run
  61. // the callback in a non-I/O worker thread
  62. //
  63. //
  64. // APPCOMPAT - can't do this: the callback types for Wait & Work requests
  65. // are different: one takes 2 parameters, the other one. We
  66. // can't make this change until this issue is resolved with
  67. // NT guys
  68. //
  69. //if (m_dwFlags & WT_EXECUTEINWAITTHREAD) {
  70. m_pCallback(m_pContext, bTimeout != 0);
  71. //} else {
  72. //
  73. // //
  74. // // would have to allocate object from heap to hold callback
  75. // // function, context & bTimeout parameters in order to pass
  76. // // them to worker thread (we only have access to one APC
  77. // // parameter and we'd have to nominate different APC)
  78. // //
  79. //
  80. // Ie_QueueUserWorkItem((LPTHREAD_START_ROUTINE)m_pCallback,
  81. // m_pContext,
  82. // FALSE
  83. // );
  84. //}
  85. }
  86. HANDLE GetHandle(VOID) const {
  87. return m_hObject;
  88. }
  89. BOOL IsNoRemoveItem(VOID) {
  90. return (m_dwFlags & SRWSO_NOREMOVE) ? TRUE : FALSE;
  91. }
  92. };
  93. //
  94. // CWaitRequest
  95. //
  96. class CWaitRequest {
  97. private:
  98. BOOL m_bCompleted;
  99. CWait * m_pWait;
  100. public:
  101. CWaitRequest() {
  102. m_bCompleted = FALSE;
  103. }
  104. CWaitRequest(CWait * pWait) {
  105. m_bCompleted = FALSE;
  106. m_pWait = pWait;
  107. }
  108. VOID SetComplete(VOID) {
  109. m_bCompleted = TRUE;
  110. }
  111. VOID WaitForCompletion(VOID) {
  112. while (!m_bCompleted) {
  113. SleepEx(0, TRUE);
  114. }
  115. }
  116. VOID SetWaitPointer(CWait * pWait) {
  117. m_pWait = pWait;
  118. }
  119. CWait * GetWaitPointer(VOID) const {
  120. return m_pWait;
  121. }
  122. };
  123. //
  124. // CWaitAddRequest
  125. //
  126. class CWaitAddRequest : public CWait, public CWaitRequest {
  127. public:
  128. CWaitAddRequest(HANDLE hObject,
  129. WAITORTIMERCALLBACKFUNC pCallback,
  130. LPVOID pContext,
  131. DWORD dwWaitTime,
  132. DWORD dwFlags,
  133. CWaitThreadInfo * pInfo
  134. ) :
  135. CWait(hObject, pCallback, pContext, dwWaitTime, dwFlags, pInfo),
  136. CWaitRequest()
  137. {
  138. }
  139. };
  140. //
  141. // CWaitRemoveRequest
  142. //
  143. class CWaitRemoveRequest : public CWaitRequest {
  144. public:
  145. CWaitRemoveRequest(HANDLE hWait) : CWaitRequest((CWait *)hWait) {
  146. }
  147. };
  148. //
  149. // CWaitThreadInfo
  150. //
  151. class CWaitThreadInfo : public CDoubleLinkedList, public CCriticalSection {
  152. private:
  153. HANDLE m_hThread;
  154. DWORD m_dwObjectCount;
  155. HANDLE m_Objects[MAXIMUM_WAIT_OBJECTS];
  156. CWait * m_pWaiters[MAXIMUM_WAIT_OBJECTS];
  157. CWait m_Waiters[MAXIMUM_WAIT_OBJECTS];
  158. CDoubleLinkedList m_FreeList;
  159. CDoubleLinkedList m_WaitList;
  160. public:
  161. CWaitThreadInfo(CDoubleLinkedList * pList) {
  162. CDoubleLinkedList::Init();
  163. m_hThread = NULL;
  164. m_dwObjectCount = 0;
  165. m_FreeList.Init();
  166. m_WaitList.Init();
  167. for (int i = 0; i < ARRAY_ELEMENTS(m_Waiters); ++i) {
  168. m_Waiters[i].InsertTail(&m_FreeList);
  169. }
  170. InsertHead(pList);
  171. }
  172. VOID SetHandle(HANDLE hThread) {
  173. m_hThread = hThread;
  174. }
  175. HANDLE GetHandle(VOID) const {
  176. return m_hThread;
  177. }
  178. DWORD GetObjectCount(VOID) const {
  179. return m_dwObjectCount;
  180. }
  181. BOOL IsAvailableEntry(VOID) const {
  182. return m_dwObjectCount < ARRAY_ELEMENTS(m_Objects);
  183. }
  184. BOOL IsInvalidHandle(DWORD dwIndex) {
  185. ASSERT(dwIndex < m_dwObjectCount);
  186. //
  187. // GetHandleInformation() doesn't exist on Win95
  188. //
  189. //
  190. //DWORD dwHandleFlags;
  191. //
  192. //return !GetHandleInformation(m_Objects[dwIndex], &dwHandleFlags);
  193. DWORD status = WaitForSingleObject(m_Objects[dwIndex], 0);
  194. if ((status == WAIT_FAILED) && (GetLastError() == ERROR_INVALID_HANDLE)) {
  195. //#if DBG
  196. //char buf[128];
  197. //wsprintf(buf, "IsInvalidHandle(%d): handle %#x is invalid\n", dwIndex, m_Objects[dwIndex]);
  198. //OutputDebugString(buf);
  199. //#endif
  200. return TRUE;
  201. }
  202. return FALSE;
  203. }
  204. VOID Compress(DWORD dwIndex, DWORD dwCount = 1)
  205. {
  206. ASSERT(dwCount != 0);
  207. ASSERT((int)m_dwObjectCount > 0);
  208. ASSERT(m_dwObjectCount < MAXIMUM_WAIT_OBJECTS);
  209. if (((dwIndex + dwCount) < m_dwObjectCount) && (m_dwObjectCount < MAXIMUM_WAIT_OBJECTS))
  210. {
  211. RtlMoveMemory(&m_Objects[dwIndex],
  212. &m_Objects[dwIndex + dwCount],
  213. sizeof(m_Objects[0]) * (m_dwObjectCount - (dwIndex + dwCount))
  214. );
  215. RtlMoveMemory(&m_pWaiters[dwIndex],
  216. &m_pWaiters[dwIndex + dwCount],
  217. sizeof(m_pWaiters[0]) * (m_dwObjectCount - (dwIndex + dwCount))
  218. );
  219. }
  220. m_dwObjectCount -= dwCount;
  221. }
  222. VOID Expand(DWORD dwIndex)
  223. {
  224. ASSERT((int)m_dwObjectCount > 0);
  225. // The off by one is because we copying from dwIndex + 1 and our size to copy is
  226. // m_dwObjectCount - dwIndex
  227. if (m_dwObjectCount < MAXIMUM_WAIT_OBJECTS - 1)
  228. {
  229. RtlMoveMemory(&m_Objects[dwIndex],
  230. &m_Objects[dwIndex + 1],
  231. sizeof(m_Objects[0]) * (m_dwObjectCount - dwIndex)
  232. );
  233. RtlMoveMemory(&m_pWaiters[dwIndex],
  234. &m_pWaiters[dwIndex + 1],
  235. sizeof(m_pWaiters[0]) * (m_dwObjectCount - dwIndex)
  236. );
  237. ++m_dwObjectCount;
  238. }
  239. ASSERT(m_dwObjectCount <= ARRAY_ELEMENTS(m_Objects));
  240. }
  241. //DWORD BuildList(VOID) {
  242. //
  243. // //
  244. // // PERF: only rebuild from changed index
  245. // //
  246. //
  247. // m_dwObjectCount = 0;
  248. // for (CWait * pWait = (CWait *)m_WaitList.Next();
  249. // pWait = pWait->Next();
  250. // !m_WaitList.IsHead(pWait)) {
  251. // m_pWaiters[m_dwObjectCount] = pWait;
  252. // m_Objects[m_dwObjectCount] = pWait->GetHandle();
  253. // ++m_dwObjectCount;
  254. // }
  255. // return GetWaitTime();
  256. //}
  257. DWORD Wait(DWORD dwTimeout = INFINITE) {
  258. //
  259. // if no objects in list, sleep alertably for the timeout period
  260. //
  261. if (m_dwObjectCount == 0) {
  262. SleepEx(dwTimeout, TRUE);
  263. return WAIT_IO_COMPLETION;
  264. }
  265. //
  266. // else wait alertably for the timeout period
  267. //
  268. ASSERT(m_dwObjectCount <= ARRAY_ELEMENTS(m_Objects));
  269. return WaitForMultipleObjectsEx(m_dwObjectCount,
  270. m_Objects,
  271. FALSE, // fWaitAll
  272. dwTimeout,
  273. TRUE // fAlertable
  274. );
  275. }
  276. DWORD GetWaitTime(VOID) {
  277. ASSERT(m_dwObjectCount <= ARRAY_ELEMENTS(m_Objects));
  278. if (m_dwObjectCount != 0) {
  279. CWait * pWaiter = m_pWaiters[0];
  280. DWORD dwWaitTime = pWaiter->GetWaitTime();
  281. if (dwWaitTime != INFINITE) {
  282. DWORD dwTimeNow = GetTickCount();
  283. DWORD dwTimeStamp = pWaiter->GetTimeStamp();
  284. if (dwTimeNow > dwTimeStamp + dwWaitTime) {
  285. //
  286. // first object expired already
  287. //
  288. return 0;
  289. }
  290. //
  291. // number of milliseconds until next waiter expires
  292. //
  293. return (dwTimeStamp + dwWaitTime) - dwTimeNow;
  294. }
  295. }
  296. //
  297. // nothing in list
  298. //
  299. return INFINITE;
  300. }
  301. CWait * GetFreeWaiter(VOID) {
  302. return (CWait *)m_FreeList.RemoveHead();
  303. }
  304. VOID InsertWaiter(CWait * pWait) {
  305. DWORD dwIndex = 0;
  306. BOOL bAtEnd = TRUE;
  307. CDoubleLinkedListEntry * pHead = m_WaitList.Head();
  308. ASSERT(m_dwObjectCount <= ARRAY_ELEMENTS(m_Objects));
  309. if ((m_dwObjectCount != 0) && !pWait->IsInfiniteTimeout()) {
  310. //
  311. // not infinite timeout. Find place in list to insert this object
  312. //
  313. //
  314. // PERF: typically, new wait will be longer than most currently in
  315. // list, so should start from end of non-infinite timeouts
  316. // and work backwards
  317. //
  318. for (; dwIndex < m_dwObjectCount; ++dwIndex) {
  319. if (pWait->ExpiryTime() < m_pWaiters[dwIndex]->ExpiryTime()) {
  320. pHead = m_pWaiters[dwIndex]->Head();
  321. bAtEnd = (dwIndex == (m_dwObjectCount - 1));
  322. break;
  323. }
  324. }
  325. }
  326. //
  327. // insert the new wait object at the correct location
  328. //
  329. pWait->InsertTail(pHead);
  330. if (!bAtEnd && (m_dwObjectCount != 0)) {
  331. Expand(dwIndex);
  332. } else {
  333. dwIndex = m_dwObjectCount;
  334. ++m_dwObjectCount;
  335. }
  336. //
  337. // update object list and pointer list
  338. //
  339. m_Objects[dwIndex] = pWait->GetHandle();
  340. m_pWaiters[dwIndex] = pWait;
  341. }
  342. VOID RemoveWaiter(CWait * pWait, DWORD dwIndex) {
  343. //
  344. // remove the waiter from the wait list and add it back to the
  345. // free list
  346. //
  347. pWait->Remove();
  348. pWait->InsertTail(&m_FreeList);
  349. //
  350. // if the object was not at the end of the list then compress
  351. // the list
  352. //
  353. if (dwIndex != (m_dwObjectCount - 1)) {
  354. Compress(dwIndex, 1);
  355. } else {
  356. --m_dwObjectCount;
  357. }
  358. }
  359. VOID RemoveWaiter(DWORD dwIndex) {
  360. ASSERT(m_dwObjectCount <= ARRAY_ELEMENTS(m_Objects));
  361. RemoveWaiter(m_pWaiters[dwIndex], dwIndex);
  362. }
  363. BOOL RemoveWaiter(CWait * pWait) {
  364. ASSERT(m_dwObjectCount <= ARRAY_ELEMENTS(m_Objects));
  365. for (DWORD dwIndex = 0; dwIndex < m_dwObjectCount; ++dwIndex) {
  366. if (m_pWaiters[dwIndex] == pWait) {
  367. RemoveWaiter(pWait, dwIndex);
  368. return TRUE;
  369. }
  370. }
  371. return FALSE;
  372. }
  373. VOID ProcessTimeouts(VOID) {
  374. DWORD dwTimeNow = GetTickCount();
  375. DWORD dwCount = 0;
  376. ASSERT(m_dwObjectCount <= ARRAY_ELEMENTS(m_Objects));
  377. while (dwCount < m_dwObjectCount) {
  378. CWait * pWait = m_pWaiters[dwCount];
  379. //
  380. // if waiter has expired, invoke its callback then remove it from
  381. // the wait list and add back to the free list
  382. //
  383. if (pWait->IsTimedOut(dwTimeNow)) {
  384. pWait->Execute(TRUE);
  385. pWait->Remove();
  386. pWait->InsertTail(&m_FreeList);
  387. ++dwCount;
  388. } else {
  389. //
  390. // quit loop at first non-timed-out entry
  391. //
  392. break;
  393. }
  394. }
  395. ASSERT(dwCount != 0);
  396. if (dwCount != 0) {
  397. Compress(0, dwCount);
  398. }
  399. }
  400. VOID PurgeInvalidHandles(VOID) {
  401. DWORD dwCount = 0;
  402. DWORD dwIndex = 0;
  403. DWORD dwIndexStart = 0;
  404. ASSERT(m_dwObjectCount <= ARRAY_ELEMENTS(m_Objects));
  405. while (dwIndex < m_dwObjectCount) {
  406. CWait * pWait = m_pWaiters[dwIndex];
  407. //
  408. // if handle has become invalid, invoke the callback then remove it
  409. // from the wait list and add back to the free list
  410. //
  411. if (IsInvalidHandle(dwIndex)) {
  412. pWait->Execute(FALSE);
  413. pWait->Remove();
  414. pWait->InsertTail(&m_FreeList);
  415. if (dwIndexStart == 0) {
  416. dwIndexStart = dwIndex;
  417. }
  418. ++dwCount;
  419. } else if (dwCount != 0) {
  420. Compress(dwIndexStart, dwCount);
  421. dwIndex = dwIndexStart - 1;
  422. dwIndexStart = 0;
  423. dwCount = 0;
  424. }
  425. ++dwIndex;
  426. }
  427. if (dwCount != 0) {
  428. Compress(dwIndexStart, dwCount);
  429. }
  430. }
  431. VOID ProcessCompletion(DWORD dwIndex) {
  432. CWait * pWait = m_pWaiters[dwIndex];
  433. pWait->Execute(FALSE);
  434. if (!pWait->IsNoRemoveItem()) {
  435. RemoveWaiter(dwIndex);
  436. }
  437. }
  438. };