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.

733 lines
12 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. serialst.cxx
  5. Abstract:
  6. Functions to deal with a serialized list. These are replaced by macros in
  7. the retail version
  8. Contents:
  9. [InitializeSerializedList]
  10. [TerminateSerializedList]
  11. [LockSerializedList]
  12. [UnlockSerializedList]
  13. [InsertAtHeadOfSerializedList]
  14. [InsertAtTailOfSerializedList]
  15. [RemoveFromSerializedList]
  16. [IsSerializedListEmpty]
  17. [HeadOfSerializedList]
  18. [TailOfSerializedList]
  19. [CheckEntryOnSerializedList]
  20. [(CheckEntryOnList)]
  21. SlDequeueHead
  22. SlDequeueTail
  23. IsOnSerializedList
  24. Author:
  25. Richard L Firth (rfirth) 16-Feb-1995
  26. Environment:
  27. Win-32 user level
  28. Revision History:
  29. 16-Feb-1995 rfirth
  30. Created
  31. 05-Jul-1999 adriaanc
  32. nabbed for fusion
  33. --*/
  34. #include "debmacro.h"
  35. #include <windows.h>
  36. #include "serialst.h"
  37. #if DBG
  38. #if !defined(PRIVATE)
  39. #define PRIVATE static
  40. #endif
  41. #if !defined(DEBUG_FUNCTION)
  42. #define DEBUG_FUNCTION
  43. #endif
  44. #if !defined(DEBUG_PRINT)
  45. #define DEBUG_PRINT(foo, bar, baz)
  46. #endif
  47. #if !defined(ENDEXCEPT)
  48. #define ENDEXCEPT
  49. #endif
  50. #if !defined(DEBUG_BREAK)
  51. #define DEBUG_BREAK(foo) DebugBreak()
  52. #endif
  53. //
  54. // manifests
  55. //
  56. #define SERIALIZED_LIST_SIGNATURE 'tslS'
  57. //
  58. // private prototypes
  59. //
  60. PRIVATE
  61. DEBUG_FUNCTION
  62. BOOL
  63. CheckEntryOnList(
  64. IN PLIST_ENTRY List,
  65. IN PLIST_ENTRY Entry,
  66. IN BOOL ExpectedResult
  67. );
  68. //
  69. // data
  70. //
  71. BOOL fCheckEntryOnList = FALSE;
  72. BOOL ReportCheckEntryOnListErrors = FALSE;
  73. //
  74. // functions
  75. //
  76. DEBUG_FUNCTION
  77. VOID
  78. InitializeSerializedList(
  79. IN LPSERIALIZED_LIST SerializedList
  80. )
  81. /*++
  82. Routine Description:
  83. initializes a serialized list
  84. Arguments:
  85. SerializedList - pointer to SERIALIZED_LIST
  86. Return Value:
  87. None.
  88. --*/
  89. {
  90. ASSERT(SerializedList != NULL);
  91. SerializedList->Signature = SERIALIZED_LIST_SIGNATURE;
  92. SerializedList->LockCount = 0;
  93. #if 0
  94. // removed 1/7/2000 by mgrier - bad debug build
  95. INITIALIZE_RESOURCE_INFO(&SerializedList->ResourceInfo);
  96. #endif // 0
  97. InitializeListHead(&SerializedList->List);
  98. SerializedList->ElementCount = 0;
  99. InitializeCriticalSection(&SerializedList->Lock);
  100. }
  101. DEBUG_FUNCTION
  102. VOID
  103. TerminateSerializedList(
  104. IN LPSERIALIZED_LIST SerializedList
  105. )
  106. /*++
  107. Routine Description:
  108. Undoes InitializeSerializeList
  109. Arguments:
  110. SerializedList - pointer to serialized list to terminate
  111. Return Value:
  112. None.
  113. --*/
  114. {
  115. ASSERT(SerializedList != NULL);
  116. ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
  117. ASSERT(SerializedList->ElementCount == 0);
  118. if (SerializedList->ElementCount != 0) {
  119. DEBUG_PRINT(SERIALST,
  120. ERROR,
  121. ("list @ %#x has %d elements, first is %#x\n",
  122. SerializedList,
  123. SerializedList->ElementCount,
  124. SerializedList->List.Flink
  125. ));
  126. } else {
  127. ASSERT(IsListEmpty(&SerializedList->List));
  128. }
  129. DeleteCriticalSection(&SerializedList->Lock);
  130. }
  131. DEBUG_FUNCTION
  132. VOID
  133. LockSerializedList(
  134. IN LPSERIALIZED_LIST SerializedList
  135. )
  136. /*++
  137. Routine Description:
  138. Acquires a serialized list locks
  139. Arguments:
  140. SerializedList - SERIALIZED_LIST to lock
  141. Return Value:
  142. None.
  143. --*/
  144. {
  145. ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
  146. ASSERT(SerializedList->LockCount >= 0);
  147. EnterCriticalSection(&SerializedList->Lock);
  148. if (SerializedList->LockCount != 0) {
  149. ASSERT(SerializedList->ResourceInfo.Tid == GetCurrentThreadId());
  150. }
  151. ++SerializedList->LockCount;
  152. SerializedList->ResourceInfo.Tid = GetCurrentThreadId();
  153. }
  154. DEBUG_FUNCTION
  155. VOID
  156. UnlockSerializedList(
  157. IN LPSERIALIZED_LIST SerializedList
  158. )
  159. /*++
  160. Routine Description:
  161. Releases a serialized list lock
  162. Arguments:
  163. SerializedList - SERIALIZED_LIST to unlock
  164. Return Value:
  165. None.
  166. --*/
  167. {
  168. ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
  169. ASSERT(SerializedList->ResourceInfo.Tid == GetCurrentThreadId());
  170. ASSERT(SerializedList->LockCount > 0);
  171. --SerializedList->LockCount;
  172. LeaveCriticalSection(&SerializedList->Lock);
  173. }
  174. DEBUG_FUNCTION
  175. VOID
  176. InsertAtHeadOfSerializedList(
  177. IN LPSERIALIZED_LIST SerializedList,
  178. IN PLIST_ENTRY Entry
  179. )
  180. /*++
  181. Routine Description:
  182. Adds an item to the head of a serialized list
  183. Arguments:
  184. SerializedList - SERIALIZED_LIST to update
  185. Entry - thing to update it with
  186. Return Value:
  187. None.
  188. --*/
  189. {
  190. ASSERT(Entry != &SerializedList->List);
  191. LockSerializedList(SerializedList);
  192. if (fCheckEntryOnList) {
  193. CheckEntryOnList(&SerializedList->List, Entry, FALSE);
  194. }
  195. InsertHeadList(&SerializedList->List, Entry);
  196. ++SerializedList->ElementCount;
  197. ASSERT(SerializedList->ElementCount > 0);
  198. UnlockSerializedList(SerializedList);
  199. }
  200. DEBUG_FUNCTION
  201. VOID
  202. InsertAtTailOfSerializedList(
  203. IN LPSERIALIZED_LIST SerializedList,
  204. IN PLIST_ENTRY Entry
  205. )
  206. /*++
  207. Routine Description:
  208. Adds an item to the head of a serialized list
  209. Arguments:
  210. SerializedList - SERIALIZED_LIST to update
  211. Entry - thing to update it with
  212. Return Value:
  213. None.
  214. --*/
  215. {
  216. ASSERT(Entry != &SerializedList->List);
  217. LockSerializedList(SerializedList);
  218. if (fCheckEntryOnList) {
  219. CheckEntryOnList(&SerializedList->List, Entry, FALSE);
  220. }
  221. InsertTailList(&SerializedList->List, Entry);
  222. ++SerializedList->ElementCount;
  223. ASSERT(SerializedList->ElementCount > 0);
  224. UnlockSerializedList(SerializedList);
  225. }
  226. VOID
  227. DEBUG_FUNCTION
  228. RemoveFromSerializedList(
  229. IN LPSERIALIZED_LIST SerializedList,
  230. IN PLIST_ENTRY Entry
  231. )
  232. /*++
  233. Routine Description:
  234. Removes the entry from a serialized list
  235. Arguments:
  236. SerializedList - SERIALIZED_LIST to remove entry from
  237. Entry - pointer to entry to remove
  238. Return Value:
  239. None.
  240. --*/
  241. {
  242. ASSERT((Entry->Flink != NULL) && (Entry->Blink != NULL));
  243. LockSerializedList(SerializedList);
  244. if (fCheckEntryOnList) {
  245. CheckEntryOnList(&SerializedList->List, Entry, TRUE);
  246. }
  247. ASSERT(SerializedList->ElementCount > 0);
  248. RemoveEntryList(Entry);
  249. --SerializedList->ElementCount;
  250. Entry->Flink = NULL;
  251. Entry->Blink = NULL;
  252. UnlockSerializedList(SerializedList);
  253. }
  254. DEBUG_FUNCTION
  255. BOOL
  256. IsSerializedListEmpty(
  257. IN LPSERIALIZED_LIST SerializedList
  258. )
  259. /*++
  260. Routine Description:
  261. Checks if a serialized list contains any elements
  262. Arguments:
  263. SerializedList - pointer to list to check
  264. Return Value:
  265. BOOL
  266. --*/
  267. {
  268. LockSerializedList(SerializedList);
  269. ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
  270. BOOL empty;
  271. if (IsListEmpty(&SerializedList->List)) {
  272. ASSERT(SerializedList->ElementCount == 0);
  273. empty = TRUE;
  274. } else {
  275. ASSERT(SerializedList->ElementCount != 0);
  276. empty = FALSE;
  277. }
  278. UnlockSerializedList(SerializedList);
  279. return empty;
  280. }
  281. DEBUG_FUNCTION
  282. PLIST_ENTRY
  283. HeadOfSerializedList(
  284. IN LPSERIALIZED_LIST SerializedList
  285. )
  286. /*++
  287. Routine Description:
  288. Returns the element at the tail of the list, without taking the lock
  289. Arguments:
  290. SerializedList - pointer to SERIALIZED_LIST
  291. Return Value:
  292. PLIST_ENTRY
  293. pointer to element at tail of list
  294. --*/
  295. {
  296. ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
  297. return SerializedList->List.Flink;
  298. }
  299. DEBUG_FUNCTION
  300. PLIST_ENTRY
  301. TailOfSerializedList(
  302. IN LPSERIALIZED_LIST SerializedList
  303. )
  304. /*++
  305. Routine Description:
  306. Returns the element at the tail of the list, without taking the lock
  307. Arguments:
  308. SerializedList - pointer to SERIALIZED_LIST
  309. Return Value:
  310. PLIST_ENTRY
  311. pointer to element at tail of list
  312. --*/
  313. {
  314. ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
  315. return SerializedList->List.Blink;
  316. }
  317. DEBUG_FUNCTION
  318. BOOL
  319. CheckEntryOnSerializedList(
  320. IN LPSERIALIZED_LIST SerializedList,
  321. IN PLIST_ENTRY Entry,
  322. IN BOOL ExpectedResult
  323. )
  324. /*++
  325. Routine Description:
  326. Checks an entry exists (or doesn't exist) on a list
  327. Arguments:
  328. SerializedList - pointer to serialized list
  329. Entry - pointer to entry
  330. ExpectedResult - TRUE if expected on list, else FALSE
  331. Return Value:
  332. BOOL
  333. TRUE - expected result
  334. FALSE - unexpected result
  335. --*/
  336. {
  337. ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
  338. LockSerializedList(SerializedList);
  339. BOOL result;
  340. __try {
  341. result = CheckEntryOnList(&SerializedList->List, Entry, ExpectedResult);
  342. } __except(EXCEPTION_EXECUTE_HANDLER) {
  343. DEBUG_PRINT(SERIALST,
  344. FATAL,
  345. ("List @ %#x (%d elements) is bad\n",
  346. SerializedList,
  347. SerializedList->ElementCount
  348. ));
  349. result = FALSE;
  350. }
  351. ENDEXCEPT
  352. UnlockSerializedList(SerializedList);
  353. return result;
  354. }
  355. PRIVATE
  356. DEBUG_FUNCTION
  357. BOOL
  358. CheckEntryOnList(
  359. IN PLIST_ENTRY List,
  360. IN PLIST_ENTRY Entry,
  361. IN BOOL ExpectedResult
  362. )
  363. {
  364. BOOLEAN found = FALSE;
  365. PLIST_ENTRY p;
  366. if (!IsListEmpty(List)) {
  367. for (p = List->Flink; p != List; p = p->Flink) {
  368. if (p == Entry) {
  369. found = TRUE;
  370. break;
  371. }
  372. }
  373. }
  374. if (found != ExpectedResult) {
  375. if (ReportCheckEntryOnListErrors) {
  376. LPSTR description;
  377. description = found
  378. ? "Entry %#x already on list %#x\n"
  379. : "Entry %#x not found on list %#x\n"
  380. ;
  381. DEBUG_PRINT(SERIALST,
  382. ERROR,
  383. (description,
  384. Entry,
  385. List
  386. ));
  387. DEBUG_BREAK(SERIALST);
  388. }
  389. return FALSE;
  390. }
  391. return TRUE;
  392. }
  393. #endif // DBG
  394. //
  395. // functions that are always functions
  396. //
  397. LPVOID
  398. SlDequeueHead(
  399. IN LPSERIALIZED_LIST SerializedList
  400. )
  401. /*++
  402. Routine Description:
  403. Dequeues the element at the head of the queue and returns its address or
  404. NULL if the queue is empty
  405. Arguments:
  406. SerializedList - pointer to SERIALIZED_LIST to dequeue from
  407. Return Value:
  408. LPVOID
  409. --*/
  410. {
  411. LPVOID entry;
  412. if (!IsSerializedListEmpty(SerializedList)) {
  413. LockSerializedList(SerializedList);
  414. if (!IsSerializedListEmpty(SerializedList)) {
  415. entry = (LPVOID)HeadOfSerializedList(SerializedList);
  416. RemoveFromSerializedList(SerializedList, (PLIST_ENTRY)entry);
  417. } else {
  418. entry = NULL;
  419. }
  420. UnlockSerializedList(SerializedList);
  421. } else {
  422. entry = NULL;
  423. }
  424. return entry;
  425. }
  426. LPVOID
  427. SlDequeueTail(
  428. IN LPSERIALIZED_LIST SerializedList
  429. )
  430. /*++
  431. Routine Description:
  432. Dequeues the element at the tail of the queue and returns its address or
  433. NULL if the queue is empty
  434. Arguments:
  435. SerializedList - pointer to SERIALIZED_LIST to dequeue from
  436. Return Value:
  437. LPVOID
  438. --*/
  439. {
  440. LPVOID entry;
  441. if (!IsSerializedListEmpty(SerializedList)) {
  442. LockSerializedList(SerializedList);
  443. if (!IsSerializedListEmpty(SerializedList)) {
  444. entry = (LPVOID)TailOfSerializedList(SerializedList);
  445. RemoveFromSerializedList(SerializedList, (PLIST_ENTRY)entry);
  446. } else {
  447. entry = NULL;
  448. }
  449. UnlockSerializedList(SerializedList);
  450. } else {
  451. entry = NULL;
  452. }
  453. return entry;
  454. }
  455. BOOL
  456. IsOnSerializedList(
  457. IN LPSERIALIZED_LIST SerializedList,
  458. IN PLIST_ENTRY Entry
  459. )
  460. /*++
  461. Routine Description:
  462. Checks if an entry is on a serialized list. Useful to call before
  463. RemoveFromSerializedList() if multiple threads can remove the element
  464. Arguments:
  465. SerializedList - pointer to SERIALIZED_LIST
  466. Entry - pointer to element to check
  467. Return Value:
  468. BOOL
  469. TRUE - Entry is on SerializedList
  470. FALSE - " " not on "
  471. --*/
  472. {
  473. BOOL onList = FALSE;
  474. LPVOID entry;
  475. if (!IsSerializedListEmpty(SerializedList)) {
  476. LockSerializedList(SerializedList);
  477. if (!IsSerializedListEmpty(SerializedList)) {
  478. for (PLIST_ENTRY entry = HeadOfSerializedList(SerializedList);
  479. entry != (PLIST_ENTRY)SlSelf(SerializedList);
  480. entry = entry->Flink) {
  481. if (entry == Entry) {
  482. onList = TRUE;
  483. break;
  484. }
  485. }
  486. }
  487. UnlockSerializedList(SerializedList);
  488. }
  489. return onList;
  490. }