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.

431 lines
13 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File: msgguid.cpp
  5. //
  6. // Description: Implementation of AQMsgGuidList and CAQMsgGuidListEntry
  7. // classes which provide the functionality to supersede outdated
  8. // msg ID's.
  9. //
  10. // Author: Mike Swafford (MikeSwa)
  11. //
  12. // History:
  13. // 10/10/98 - MikeSwa Created
  14. //
  15. // Copyright (C) 1998 Microsoft Corporation
  16. //
  17. //-----------------------------------------------------------------------------
  18. #include "aqprecmp.h"
  19. #include "msgguid.h"
  20. CPool CAQMsgGuidListEntry::s_MsgGuidListEntryPool(MSGGUIDLIST_ENTRY_SIG);
  21. //
  22. // A brief note about locks for thess classes.
  23. //
  24. // The CAMsgGuidList* classes are protected by a single per-virtual server
  25. // ShareLock (m_slPrivateData of course). These locks are non-reentrant, so
  26. // it is critical that we do not hold these locks while doing something that
  27. // may cause a locking call back into us (like releasing a CMsgReference).
  28. //
  29. //---[ CAQMsgGuidListEntry::CAQMsgGuidListEntry ]------------------------------
  30. //
  31. //
  32. // Description:
  33. // Constructor for CAQMsgGuidListEntry
  34. // Parameters:
  35. // pmsgref Ptr to CMsgRef for this ID
  36. // pguid GUID ID of this message
  37. // pliHead Head of list to add to
  38. // pmgl List this entry belongs to
  39. // Returns:
  40. // -
  41. // History:
  42. // 10/10/98 - MikeSwa Created
  43. //
  44. //-----------------------------------------------------------------------------
  45. CAQMsgGuidListEntry::CAQMsgGuidListEntry(CMsgRef *pmsgref, GUID *pguid,
  46. PLIST_ENTRY pliHead, CAQMsgGuidList *pmgl)
  47. {
  48. _ASSERT(pmsgref);
  49. _ASSERT(pguid);
  50. _ASSERT(pmgl);
  51. _ASSERT(pliHead);
  52. m_dwSignature = MSGGUIDLIST_ENTRY_SIG;
  53. m_pmsgref = pmsgref;
  54. m_pmsgref->AddRef();
  55. m_pmgl = pmgl;
  56. memcpy(&m_guidMsgID, pguid, sizeof(GUID));
  57. InsertHeadList(pliHead, &m_liMsgGuidList);
  58. }
  59. //---[ CAQMsgGuidListEntry::~CAQMsgGuidListEntry ]-----------------------------
  60. //
  61. //
  62. // Description:
  63. // Destructor for CAQMsgGuidListEntry
  64. // Parameters:
  65. // -
  66. // Returns:
  67. // -
  68. // History:
  69. // 10/10/98 - MikeSwa Created
  70. //
  71. //-----------------------------------------------------------------------------
  72. CAQMsgGuidListEntry::~CAQMsgGuidListEntry()
  73. {
  74. //we should not still be in a list
  75. _ASSERT(!m_liMsgGuidList.Flink);
  76. _ASSERT(!m_liMsgGuidList.Blink);
  77. m_dwSignature = MSGGUIDLIST_ENTRY_SIG_INVALID;
  78. //It is safe to release the message ref here, since there is no way it
  79. //can call back into use (unless there is a ref-counting bug).
  80. if (m_pmsgref)
  81. m_pmsgref->Release();
  82. m_pmgl = NULL;
  83. }
  84. //---[ CAQMsgGuidListEntry::pmgleGetEntry ]------------------------------------
  85. //
  86. //
  87. // Description:
  88. // Static function to get entry from LIST_ENTRY
  89. //
  90. // NOTE: inline function for use by CAQMsgGuidList only
  91. // Parameters:
  92. // pli LIST ENTRY
  93. // Returns:
  94. // pointer to associated CAQMsgGuidListEntry
  95. // History:
  96. // 10/10/98 - MikeSwa Created
  97. //
  98. //-----------------------------------------------------------------------------
  99. CAQMsgGuidListEntry *CAQMsgGuidListEntry::pmgleGetEntry(PLIST_ENTRY pli)
  100. {
  101. _ASSERT(pli);
  102. CAQMsgGuidListEntry *pmgle = CONTAINING_RECORD(pli,
  103. CAQMsgGuidListEntry, m_liMsgGuidList);
  104. ASSERT(pmgle->m_dwSignature == MSGGUIDLIST_ENTRY_SIG);
  105. return pmgle;
  106. }
  107. //---[ CAQMsgGuidListEntry::fCompareGuid ]-------------------------------------
  108. //
  109. //
  110. // Description:
  111. // Function used by CAQMsgGuidList to determine if this has a the GUID
  112. // matching the superseded ID.
  113. //
  114. // NOTE: inline function for use by CAQMsgGuidList only
  115. // Parameters:
  116. // pguid GUID to check against
  117. // Returns:
  118. // TRUE if they match
  119. // FALSE otherwise
  120. // History:
  121. // 10/10/98 - MikeSwa Created
  122. //
  123. //-----------------------------------------------------------------------------
  124. BOOL CAQMsgGuidListEntry::fCompareGuid(GUID *pguid)
  125. {
  126. _ASSERT(pguid);
  127. return (0 == memcmp(pguid, &m_guidMsgID, sizeof(GUID)));
  128. }
  129. //---[ CAQMsgGuidListEntry::RemoveFromList ]-----------------------------------
  130. //
  131. //
  132. // Description:
  133. // Used by CMsgRef to remove an entry from the list once delivery is
  134. // complete.
  135. // Parameters:
  136. // -
  137. // Returns:
  138. // -
  139. // History:
  140. // 10/10/98 - MikeSwa Created
  141. //
  142. //-----------------------------------------------------------------------------
  143. void CAQMsgGuidListEntry::RemoveFromList()
  144. {
  145. _ASSERT(m_pmgl);
  146. m_pmgl->RemoveFromList(&m_liMsgGuidList);
  147. }
  148. //---[ CAQMsgGuidListEntry::pmsgrefGetAndClearMsgRef ]-------------------------
  149. //
  150. //
  151. // Description:
  152. // First phase shutdown/deletion of object. Will set to NULL and return
  153. // orginal msgref pointer. When caller releases lock, they should release
  154. // the returned msgref.
  155. //
  156. // NOTE: Releasing the msgref while holding onto m_slPrivateData can
  157. // lead to a deadlock. m_slPrivateData should be held while this
  158. // Parameters:
  159. // -
  160. // Returns:
  161. // -
  162. // History:
  163. // 10/10/98 - MikeSwa Created
  164. //
  165. //-----------------------------------------------------------------------------
  166. CMsgRef *CAQMsgGuidListEntry::pmsgrefGetAndClearMsgRef()
  167. {
  168. CMsgRef *pmsgref = m_pmsgref;
  169. m_pmsgref = NULL;
  170. return pmsgref;
  171. }
  172. //---[ CAQMsgGuidListEntry::SupersedeMsg ]-------------------------------------
  173. //
  174. //
  175. // Description:
  176. // Function to supersede msg associated with this object. Will flag the
  177. // associated CMsgRef as "non-deliverable"
  178. //
  179. // NOTE: Should have MsgGuidList Write lock when calling
  180. // Parameters:
  181. // -
  182. // Returns:
  183. // -
  184. // History:
  185. // 10/10/98 - MikeSwa Created
  186. //
  187. //-----------------------------------------------------------------------------
  188. void CAQMsgGuidListEntry::SupersedeMsg()
  189. {
  190. m_pmsgref->SupersedeMsg();
  191. m_pmsgref->Release();
  192. m_pmsgref = NULL;
  193. }
  194. //---[ CAQMsgGuidList::CAQMsgGuidList ]-----------------------------------------
  195. //
  196. //
  197. // Description:
  198. // Constructor for CAQMsgGuidList.
  199. // Parameters:
  200. // pcSupersededMsgs Ptr to DWORD to InterlockedIncrement for
  201. // a count of superseded messages.
  202. // (can be NULL if no counters are wanted)
  203. // Returns:
  204. // -
  205. // History:
  206. // 10/11/98 - MikeSwa Created
  207. //
  208. //-----------------------------------------------------------------------------
  209. CAQMsgGuidList::CAQMsgGuidList(DWORD *pcSupersededMsgs)
  210. {
  211. m_dwSignature = MSGGUIDLIST_SIG;
  212. m_pcSupersededMsgs = pcSupersededMsgs;
  213. InitializeListHead(&m_liMsgGuidListHead);
  214. }
  215. //---[ CAQMsgGuidList::~CAQMsgGuidList ]---------------------------------------
  216. //
  217. //
  218. // Description:
  219. // Desctructor for CAQMsgGuidList
  220. // Parameters:
  221. // -
  222. // Returns:
  223. // -
  224. // History:
  225. // 10/11/98 - MikeSwa Created
  226. //
  227. //-----------------------------------------------------------------------------
  228. CAQMsgGuidList::~CAQMsgGuidList()
  229. {
  230. Deinitialize(NULL);
  231. _ASSERT(IsListEmpty(&m_liMsgGuidListHead));
  232. }
  233. //---[ CAQMsgGuidList::pmgleAddMsgGuid ]---------------------------------------
  234. //
  235. //
  236. // Description:
  237. // Adds a message ID/Msg to the list of msg GUIDs. Will also search for
  238. // the superseded msg GUID ID from the tail of the list.
  239. //
  240. // This is meant as a server-side optimization. There is *no* attempt
  241. // to recover from out of memory situations.
  242. // Parameters:
  243. // pmsgref MsgRef associated with this ID
  244. // pguidID GUID ID of this message
  245. // pguidSuperseded GUID ID of message superseded by this message
  246. //
  247. // Returns:
  248. // Pointer to list entry for this msg (caller *must* Release)
  249. // NULL if no entry allocated
  250. // History:
  251. // 10/11/98 - MikeSwa Created
  252. // 05/08/99 - MikeSwa Fixed AV
  253. //
  254. //-----------------------------------------------------------------------------
  255. CAQMsgGuidListEntry *CAQMsgGuidList::pmgleAddMsgGuid(CMsgRef *pmsgref,
  256. GUID *pguidID,
  257. GUID *pguidSuperseded)
  258. {
  259. _ASSERT(pmsgref);
  260. _ASSERT(pguidID);
  261. CAQMsgGuidListEntry *pmgle = NULL;
  262. PLIST_ENTRY pliCurrent = NULL;
  263. CMsgRef *pmsgrefSuperseded = NULL;
  264. //First search list for matching GUID
  265. m_slPrivateData.ShareLock();
  266. pliCurrent = m_liMsgGuidListHead.Blink;
  267. while (pliCurrent && (pliCurrent != &m_liMsgGuidListHead))
  268. {
  269. pmgle = CAQMsgGuidListEntry::pmgleGetEntry(pliCurrent);
  270. if (pguidSuperseded && pmgle->fCompareGuid(pguidSuperseded))
  271. {
  272. //we found a match... addref it and stop looking
  273. pmgle->AddRef();
  274. break;
  275. }
  276. //NOTE: We may want to consider adding functionality that
  277. //would allow us to supersede messages that are added to the
  278. //system later... if some layer of abstaction (like the pickup dir)
  279. //causes out of order submission, this would allow us to handle
  280. //that case. It could require:
  281. // - Additional check of current ID against all superseded ID's (2x cost)
  282. // - Additional storage of original superseded ID's.
  283. pmgle = NULL;
  284. pliCurrent = pliCurrent->Blink;
  285. }
  286. m_slPrivateData.ShareUnlock();
  287. m_slPrivateData.ExclusiveLock();
  288. if (pmgle)
  289. {
  290. //make sure someone else hasn't removed it from the list
  291. if (pliCurrent->Blink && pliCurrent->Flink)
  292. {
  293. //If we found a match supersede
  294. if (m_pcSupersededMsgs)
  295. InterlockedIncrement((PLONG) m_pcSupersededMsgs);
  296. pmgle->SupersedeMsg();
  297. RemoveEntryList(pliCurrent);
  298. pliCurrent->Flink = NULL;
  299. pliCurrent->Blink = NULL;
  300. pmsgrefSuperseded = pmgle->pmsgrefGetAndClearMsgRef();
  301. //Release once for entry in list, and once for AddRef above
  302. _VERIFY(pmgle->Release());
  303. pmgle->Release();
  304. }
  305. }
  306. pmgle = new CAQMsgGuidListEntry(pmsgref, pguidID, &m_liMsgGuidListHead, this);
  307. if (pmgle)
  308. pmgle->AddRef();
  309. m_slPrivateData.ExclusiveUnlock();
  310. if (pmsgrefSuperseded)
  311. pmsgrefSuperseded->Release();
  312. return pmgle;
  313. }
  314. //---[ CAQMsgGuidList::Deinitialize ]------------------------------------------
  315. //
  316. //
  317. // Description:
  318. // Walks list and released all msg id objects. Calls server stop hint
  319. // function if provided.
  320. // Parameters:
  321. // painst Ptr to virtual server object to call stop hint function
  322. // Returns:
  323. // -
  324. // History:
  325. // 10/11/98 - MikeSwa Created
  326. //
  327. //-----------------------------------------------------------------------------
  328. void CAQMsgGuidList::Deinitialize(CAQSvrInst *paqinst)
  329. {
  330. PLIST_ENTRY pliCurrent = NULL;
  331. CAQMsgGuidListEntry *pmgle = NULL;
  332. CMsgRef *pmsgref = NULL;
  333. m_slPrivateData.ExclusiveLock();
  334. //Walk entire list and release all objects
  335. while (!IsListEmpty(&m_liMsgGuidListHead))
  336. {
  337. pliCurrent = m_liMsgGuidListHead.Flink;
  338. _ASSERT(pliCurrent);
  339. pmgle = CAQMsgGuidListEntry::pmgleGetEntry(pliCurrent);
  340. _ASSERT(pmgle);
  341. RemoveEntryList(pliCurrent);
  342. pliCurrent->Flink = NULL;
  343. pliCurrent->Blink = NULL;
  344. //we must unlock to Deinitalize and release won't deadlock
  345. m_slPrivateData.ExclusiveUnlock();
  346. //Send shutdown hint
  347. if (paqinst)
  348. paqinst->ServerStopHintFunction();
  349. pmsgref = pmgle->pmsgrefGetAndClearMsgRef();
  350. if (pmsgref)
  351. pmsgref->Release();
  352. pmgle->Release();
  353. //Lock so we can check if list is empty
  354. m_slPrivateData.ExclusiveLock();
  355. }
  356. m_slPrivateData.ExclusiveUnlock();
  357. }
  358. //---[ CAQMsgGuidList::RemoveFromList ]----------------------------------------
  359. //
  360. //
  361. // Description:
  362. // Used by a CAQMsgGuidListEntry to remove itself from the list in a
  363. // thread-safe manner. The CAQMsgGuidListEntry is called by the CMsgRef
  364. // when it is completely handled.
  365. // Parameters:
  366. // pli PLIST_ENTRY to remove from list
  367. // Returns:
  368. // -
  369. // History:
  370. // 10/11/98 - MikeSwa Created
  371. //
  372. //-----------------------------------------------------------------------------
  373. void CAQMsgGuidList::RemoveFromList(PLIST_ENTRY pli)
  374. {
  375. _ASSERT(pli);
  376. CAQMsgGuidListEntry *pmgle = CAQMsgGuidListEntry::pmgleGetEntry(pli);
  377. CMsgRef *pmsgref = NULL;
  378. m_slPrivateData.ExclusiveLock();
  379. if (pli->Flink && pli->Blink)
  380. {
  381. //Only remove from list once
  382. RemoveEntryList(pli);
  383. pli->Flink = NULL;
  384. pli->Blink = NULL;
  385. pmsgref = pmgle->pmsgrefGetAndClearMsgRef();
  386. //Caller must still have reference
  387. _VERIFY(pmgle->Release());
  388. }
  389. m_slPrivateData.ExclusiveUnlock();
  390. //Do not release while holding lock
  391. if (pmsgref)
  392. pmsgref->Release();
  393. }