Source code of Windows XP (NT5)
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.

434 lines
12 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 2001 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: CAUWait.h
  6. //
  7. // Creator: PeterWi
  8. //
  9. // Purpose: Event waiting management.
  10. //
  11. //=======================================================================
  12. #pragma once
  13. #include "pch.h"
  14. //handle event number should be consecutive and
  15. // range from AU_HANDLE_EVENT_MIN to AU_HANDLE_EVENT_MAX
  16. typedef enum tagAUEVENT {
  17. AU_HANDLE_EVENT_MIN = 0,
  18. AUEVENT_STATE_CHANGED = AU_HANDLE_EVENT_MIN,
  19. AUEVENT_SERVICE_FINISHED,
  20. AUEVENT_NEW_ADMIN_SESSION ,
  21. AUEVENT_WUAUCLT_FINISHED ,
  22. AUEVENT_POLICY_CHANGE,
  23. AUEVENT_SETTINGS_CHANGE,
  24. AUEVENT_CATALOG_VALIDATED,
  25. AU_HANDLE_EVENT_MAX = AUEVENT_CATALOG_VALIDATED,
  26. AUEVENT_DUMMY,
  27. AUEVENT_REMINDER_TIMEOUT ,
  28. AUEVENT_DO_DIRECTIVE, //skip wait once
  29. AUEVENT_RELAUNCH_TIMEOUT ,
  30. AUEVENT_SCHEDULED_INSTALL,
  31. AUEVENT_REBOOTWARNING_TIMEOUT
  32. } AUEVENT;
  33. extern HANDLE ghActiveAdminSession;
  34. extern HANDLE ghPolicyChanged;
  35. extern HANDLE ghSettingsChanged;
  36. //=======================================================================
  37. // CAUState
  38. //=======================================================================
  39. class CAUWait
  40. {
  41. public:
  42. CAUWait() :m_pfSecondaryCltsIsAdmin(NULL), m_phSecondaryClts(NULL){ Reset(); }
  43. ~CAUWait()
  44. {
  45. Reset();
  46. }
  47. void Reset(void)
  48. {
  49. // DEBUGMSG("CAUWait Reset() called");
  50. m_fFirstClientIsAdmin = TRUE;
  51. m_dwSecondaryClts= 0;
  52. m_timeoutID = AUEVENT_DUMMY;
  53. m_fProrateTimeout = TRUE;
  54. m_fSkipWaitOnce = FALSE;
  55. SafeFreeNULL(m_pfSecondaryCltsIsAdmin);
  56. SafeFreeNULL(m_phSecondaryClts);
  57. ZeroMemory(&m_hEventHandles, sizeof(m_hEventHandles));
  58. ZeroMemory(&m_stTimeout, sizeof(m_stTimeout));
  59. m_Add(AUEVENT_STATE_CHANGED);
  60. m_Add(AUEVENT_SERVICE_FINISHED);
  61. m_Add(AUEVENT_POLICY_CHANGE);
  62. m_Add(AUEVENT_SETTINGS_CHANGE);
  63. }
  64. BOOL Add(AUEVENT eventID, HANDLE hEvent = NULL, BOOL fAdmin = FALSE)
  65. {
  66. if (AUEVENT_DO_DIRECTIVE == eventID)
  67. {
  68. m_fSkipWaitOnce = TRUE;
  69. return TRUE;
  70. }
  71. return m_Add(eventID, hEvent, fAdmin);
  72. }
  73. void Timeout(AUEVENT eventID, DWORD dwTimeout, BOOL fProrate = TRUE)
  74. {
  75. m_timeoutID = eventID;
  76. GetSystemTime(&m_stTimeout);
  77. TimeAddSeconds(m_stTimeout, dwTimeout, &m_stTimeout);
  78. m_fProrateTimeout = fProrate;
  79. #if 0
  80. #ifdef DBG
  81. TCHAR szTime[50];
  82. if (SUCCEEDED(SystemTime2String(m_stTimeout, szTime, ARRAYSIZE(szTime))))
  83. {
  84. DEBUGMSG("next time out time is %S", szTime);
  85. }
  86. #endif
  87. #endif
  88. }
  89. AUEVENT GetTimeoutEvent(void)
  90. {
  91. return m_timeoutID;
  92. }
  93. DWORD GetTimeoutValue(void)
  94. {
  95. SYSTEMTIME stCur;
  96. GetSystemTime(&stCur);
  97. return max(TimeDiff(stCur, m_stTimeout), 0);
  98. }
  99. BOOL Wait(HANDLE *pHandle, BOOL *pfAdmin, AUEVENT *pfEventId)
  100. {
  101. DWORD dwTimeout;
  102. BOOL fRet = TRUE;
  103. AUASSERT(pHandle != NULL);
  104. AUASSERT(pfAdmin != NULL);
  105. AUASSERT(NULL != pfEventId);
  106. *pHandle = NULL;
  107. *pfAdmin = FALSE;
  108. *pfEventId = AUEVENT_DUMMY;
  109. if (m_fSkipWaitOnce)
  110. {
  111. m_fSkipWaitOnce = FALSE;
  112. *pfEventId = AUEVENT_DO_DIRECTIVE;
  113. return TRUE;
  114. }
  115. if (AUEVENT_DUMMY == m_timeoutID)
  116. {
  117. dwTimeout = INFINITE;
  118. }
  119. else
  120. {
  121. SYSTEMTIME stCur;
  122. GetSystemTime(&stCur);
  123. dwTimeout = max(TimeDiff(stCur, m_stTimeout), 0);
  124. dwTimeout = m_fProrateTimeout ? dwTimeToWait(dwTimeout): dwTimeout * 1000;
  125. // DEBUGMSG("Wait() timeout value is %d msecs", dwTimeout);
  126. }
  127. HANDLE *phandles = NULL;
  128. DWORD dwCount = 0;
  129. HandleList(FALSE, &phandles, &dwCount); //get handle list
  130. AUASSERT(dwCount > 0);
  131. AUASSERT(NULL != phandles);
  132. AUEVENT eventid = AUEVENT_DUMMY;
  133. DWORD dwRet = WaitForMultipleObjects(dwCount, phandles, FALSE, dwTimeout);
  134. if ( (WAIT_OBJECT_0 + dwCount - 1) >= dwRet )
  135. {
  136. *pHandle = phandles[dwRet - WAIT_OBJECT_0];
  137. eventid = GetEventID(*pHandle);
  138. if (AUEVENT_WUAUCLT_FINISHED == eventid)
  139. {
  140. *pfAdmin = fIsCltAdmin(*pHandle);
  141. DEBUGMSG("%s wuauclt exited", *pfAdmin ? "Admin" : "Nonadmin");
  142. }
  143. RemoveHandle(eventid, *pHandle);
  144. }
  145. else if ( WAIT_TIMEOUT == dwRet )
  146. {
  147. eventid = m_timeoutID;
  148. m_timeoutID = AUEVENT_DUMMY;
  149. }
  150. else
  151. {
  152. fRet = FALSE;
  153. }
  154. HandleList(TRUE, &phandles); //free handle list if allocated
  155. #ifdef DBG
  156. char buf[100];
  157. switch (eventid)
  158. {
  159. case AUEVENT_STATE_CHANGED: StringCchCopyExA(buf, ARRAYSIZE(buf), "state change", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
  160. case AUEVENT_POLICY_CHANGE: StringCchCopyExA(buf, ARRAYSIZE(buf), "policy change", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
  161. case AUEVENT_RELAUNCH_TIMEOUT: StringCchCopyExA(buf, ARRAYSIZE(buf), "relaunch timeout", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
  162. case AUEVENT_REMINDER_TIMEOUT: StringCchCopyExA(buf, ARRAYSIZE(buf), "reminder timeout", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
  163. case AUEVENT_SCHEDULED_INSTALL: StringCchCopyExA(buf, ARRAYSIZE(buf), "schedule install", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
  164. case AUEVENT_WUAUCLT_FINISHED: StringCchCopyExA(buf, ARRAYSIZE(buf), "wuauclt finished", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
  165. case AUEVENT_SERVICE_FINISHED: StringCchCopyExA(buf, ARRAYSIZE(buf), "service finished", NULL, NULL, MISTSAFE_STRING_FLAGS);break;
  166. case AUEVENT_NEW_ADMIN_SESSION: StringCchCopyExA(buf, ARRAYSIZE(buf), "new admin session", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
  167. case AUEVENT_SETTINGS_CHANGE: StringCchCopyExA(buf, ARRAYSIZE(buf), "settings changed", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
  168. case AUEVENT_DO_DIRECTIVE: StringCchCopyExA(buf, ARRAYSIZE(buf), "doing directive, skip wait once", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
  169. case AUEVENT_CATALOG_VALIDATED: StringCchCopyExA(buf, ARRAYSIZE(buf), "catalog validation done", NULL, NULL, MISTSAFE_STRING_FLAGS); break;
  170. case AUEVENT_REBOOTWARNING_TIMEOUT: StringCchCopyExA(buf, ARRAYSIZE(buf), "reboot warning engine timeout", NULL, NULL, MISTSAFE_STRING_FLAGS);break;
  171. default: StringCchCopyExA(buf, ARRAYSIZE(buf), "error", NULL, NULL, MISTSAFE_STRING_FLAGS);
  172. }
  173. DEBUGMSG("Wait object wake up for %s with handle %lx", buf, *pHandle);
  174. #endif
  175. *pfEventId = eventid;
  176. return fRet;
  177. }
  178. private:
  179. //assumption: handle is unique in the list
  180. BOOL m_Add(AUEVENT eventID, HANDLE hEvent = NULL, BOOL fAdmin = FALSE)
  181. {
  182. if (eventID >= ARRAYSIZE(m_hEventHandles))
  183. {
  184. AUASSERT(FALSE); //should never be
  185. return FALSE;
  186. }
  187. if ( NULL != hEvent )
  188. {
  189. if (AUEVENT_WUAUCLT_FINISHED != eventID)
  190. {
  191. m_hEventHandles[eventID] = hEvent;
  192. }
  193. else
  194. {
  195. if (NULL == m_hEventHandles[eventID])
  196. {
  197. m_hEventHandles[eventID] = hEvent;
  198. m_fFirstClientIsAdmin = fAdmin;
  199. }
  200. else
  201. { //more than one client
  202. HANDLE *pTmp = (HANDLE *)malloc((m_dwSecondaryClts+1)*sizeof(*pTmp));
  203. if (NULL == pTmp)
  204. {
  205. return FALSE;
  206. }
  207. BOOL *pTmp2 = (BOOL *) malloc((m_dwSecondaryClts + 1) * sizeof(*pTmp2));
  208. if (NULL == pTmp2)
  209. {
  210. free(pTmp);
  211. return FALSE;
  212. }
  213. for (UINT i = 0; i < m_dwSecondaryClts; i++)
  214. {
  215. pTmp[i] = m_phSecondaryClts[i];
  216. pTmp2[i] = m_pfSecondaryCltsIsAdmin[i];
  217. }
  218. m_dwSecondaryClts++;
  219. pTmp[m_dwSecondaryClts-1] = hEvent;
  220. pTmp2[m_dwSecondaryClts-1] = fAdmin;
  221. SafeFree(m_phSecondaryClts);
  222. SafeFree(m_pfSecondaryCltsIsAdmin);
  223. m_phSecondaryClts = pTmp;
  224. m_pfSecondaryCltsIsAdmin = pTmp2;
  225. }
  226. }
  227. return TRUE;
  228. }
  229. else
  230. {
  231. switch (eventID)
  232. {
  233. case AUEVENT_STATE_CHANGED:
  234. return m_Add(eventID, ghEngineState);
  235. case AUEVENT_SERVICE_FINISHED:
  236. return m_Add(eventID, ghServiceFinished);
  237. case AUEVENT_NEW_ADMIN_SESSION:
  238. return m_Add(eventID, ghActiveAdminSession);
  239. case AUEVENT_POLICY_CHANGE:
  240. return m_Add(eventID, ghPolicyChanged);
  241. case AUEVENT_SETTINGS_CHANGE:
  242. return m_Add(eventID, ghSettingsChanged);
  243. case AUEVENT_CATALOG_VALIDATED:
  244. return m_Add(eventID, ghValidateCatalog);
  245. default:
  246. DEBUGMSG("Unknown event id %d", eventID);
  247. AUASSERT(FALSE); //should never be here
  248. return FALSE;
  249. }
  250. }
  251. }
  252. private:
  253. HANDLE m_hEventHandles[AU_HANDLE_EVENT_MAX - AU_HANDLE_EVENT_MIN + 1];
  254. BOOL m_fFirstClientIsAdmin; // for the first clt
  255. HANDLE *m_phSecondaryClts;
  256. BOOL *m_pfSecondaryCltsIsAdmin;
  257. DWORD m_dwSecondaryClts;
  258. SYSTEMTIME m_stTimeout; //when timeout should happen
  259. AUEVENT m_timeoutID;
  260. BOOL m_fProrateTimeout;//whether to prorate Timeout when do actual wait
  261. BOOL m_fSkipWaitOnce;
  262. BOOL fIsEventInherent(DWORD dwEventId)
  263. {
  264. if (AUEVENT_STATE_CHANGED == dwEventId ||
  265. AUEVENT_SERVICE_FINISHED==dwEventId ||
  266. AUEVENT_POLICY_CHANGE == dwEventId ||
  267. AUEVENT_SETTINGS_CHANGE == dwEventId)
  268. {
  269. return TRUE;
  270. }
  271. else
  272. {
  273. return FALSE;
  274. }
  275. }
  276. //get or free handle list
  277. //IN fFreeList: if TRUE, free *pHandles list got
  278. // if FALSE, get the handle list
  279. void HandleList(BOOL fFreeList, HANDLE **pHandles, DWORD *pdwCount = NULL) const
  280. {
  281. static HANDLE handles[ARRAYSIZE(m_hEventHandles)];
  282. DWORD dwCount = 0;
  283. if (NULL== pHandles )
  284. {
  285. return ;
  286. }
  287. if (fFreeList)
  288. {
  289. if (*pHandles != handles)
  290. {
  291. free(*pHandles);
  292. }
  293. return;
  294. }
  295. if (NULL == pdwCount)
  296. {
  297. return;
  298. }
  299. *pHandles = NULL;
  300. *pdwCount =0;
  301. ZeroMemory(&handles, sizeof(handles));
  302. for (UINT i = 0; i < ARRAYSIZE(m_hEventHandles); i++)
  303. {
  304. if (NULL != m_hEventHandles[i])
  305. {
  306. handles[dwCount++] = m_hEventHandles[i];
  307. }
  308. }
  309. *pHandles = handles;
  310. if (0 != m_dwSecondaryClts)
  311. { //need to wait for more than one client
  312. AUASSERT(m_phSecondaryClts != NULL);
  313. if (NULL != (*pHandles = (HANDLE *) malloc((dwCount + m_dwSecondaryClts) * sizeof(**pHandles))))
  314. {
  315. for (UINT j = 0 ; j < dwCount; j++)
  316. {
  317. (*pHandles)[j] = handles[j];
  318. }
  319. for (j = 0; j< m_dwSecondaryClts; j++)
  320. {
  321. (*pHandles)[dwCount+j] = m_phSecondaryClts[j];
  322. }
  323. dwCount += m_dwSecondaryClts;
  324. }
  325. else
  326. {
  327. *pHandles = handles;
  328. }
  329. }
  330. *pdwCount = dwCount;
  331. }
  332. //return TRUE if handle removed from internal wait list or handle does not need to be removed
  333. //return FALSE if handle not found
  334. BOOL RemoveHandle(IN AUEVENT eventid , IN HANDLE & handle)
  335. {
  336. AUASSERT(NULL != handle);
  337. if (fIsEventInherent(eventid))
  338. {
  339. return TRUE;
  340. }
  341. //remove non inhereant events once signalled
  342. for (UINT i = 0; i < ARRAYSIZE(m_hEventHandles); i++)
  343. {
  344. if (handle == m_hEventHandles[i])
  345. {
  346. m_hEventHandles[i] = NULL;
  347. return TRUE;
  348. }
  349. }
  350. for (i = 0; i < m_dwSecondaryClts; i++)
  351. {
  352. if (handle == m_phSecondaryClts[i])
  353. {
  354. m_phSecondaryClts[i] = m_phSecondaryClts[m_dwSecondaryClts-1];
  355. m_pfSecondaryCltsIsAdmin[i] = m_pfSecondaryCltsIsAdmin[m_dwSecondaryClts - 1];
  356. m_phSecondaryClts[m_dwSecondaryClts-1] = NULL;
  357. m_pfSecondaryCltsIsAdmin[m_dwSecondaryClts - 1] = FALSE;
  358. m_dwSecondaryClts--;
  359. if (0 == m_dwSecondaryClts)
  360. {
  361. SafeFreeNULL(m_phSecondaryClts);
  362. SafeFreeNULL(m_pfSecondaryCltsIsAdmin);
  363. }
  364. return TRUE;
  365. }
  366. }
  367. AUASSERT(FALSE); //should never be here
  368. return FALSE;
  369. }
  370. BOOL fIsCltAdmin(HANDLE & handle) const
  371. {
  372. AUASSERT(NULL != handle);
  373. if (handle == m_hEventHandles[AUEVENT_WUAUCLT_FINISHED])
  374. {
  375. return m_fFirstClientIsAdmin;
  376. }
  377. for (UINT i = 0; i < m_dwSecondaryClts; i++)
  378. {
  379. if (handle == m_phSecondaryClts[i])
  380. {
  381. return m_pfSecondaryCltsIsAdmin[i];
  382. }
  383. }
  384. AUASSERT(FALSE); //should never be here
  385. return FALSE;
  386. }
  387. AUEVENT GetEventID(HANDLE &handle) const
  388. {
  389. AUASSERT(NULL!= handle);
  390. for (UINT i = 0; i < ARRAYSIZE(m_hEventHandles); i++)
  391. {
  392. if (handle == m_hEventHandles[i])
  393. {
  394. return (AUEVENT)i;
  395. }
  396. }
  397. for (i = 0; i< m_dwSecondaryClts; i++)
  398. {
  399. if (handle == m_phSecondaryClts[i])
  400. {
  401. return AUEVENT_WUAUCLT_FINISHED;
  402. }
  403. }
  404. AUASSERT(FALSE); //should never be here
  405. return AUEVENT_DUMMY;
  406. }
  407. };