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.

800 lines
15 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, except for functions no longer inlined due to critsec
  8. wrapper
  9. Contents:
  10. [InitializeSerializedList]
  11. [TerminateSerializedList]
  12. [LockSerializedList]
  13. [UnlockSerializedList]
  14. [InsertAtHeadOfSerializedList]
  15. [InsertAtTailOfSerializedList]
  16. [RemoveFromSerializedList]
  17. [IsSerializedListEmpty]
  18. [HeadOfSerializedList]
  19. [TailOfSerializedList]
  20. [CheckEntryOnSerializedList]
  21. [(CheckEntryOnList)]
  22. SlDequeueHead
  23. SlDequeueTail
  24. IsOnSerializedList
  25. Author:
  26. Richard L Firth (rfirth) 16-Feb-1995
  27. Environment:
  28. Win-32 user level
  29. Revision History:
  30. 16-Feb-1995 rfirth
  31. Created
  32. --*/
  33. #include <wininetp.h>
  34. #if INET_DEBUG
  35. //
  36. // manifests
  37. //
  38. #define SERIALIZED_LIST_SIGNATURE 'tslS'
  39. //
  40. // private prototypes
  41. //
  42. PRIVATE
  43. DEBUG_FUNCTION
  44. BOOL
  45. CheckEntryOnList(
  46. IN PLIST_ENTRY List,
  47. IN PLIST_ENTRY Entry,
  48. IN BOOL ExpectedResult
  49. );
  50. //
  51. // data
  52. //
  53. BOOL fCheckEntryOnList = FALSE;
  54. BOOL ReportCheckEntryOnListErrors = FALSE;
  55. //
  56. // functions
  57. //
  58. DEBUG_FUNCTION
  59. BOOL
  60. InitializeSerializedList(
  61. IN LPSERIALIZED_LIST SerializedList
  62. )
  63. /*++
  64. Routine Description:
  65. initializes a serialized list
  66. Arguments:
  67. SerializedList - pointer to SERIALIZED_LIST
  68. Return Value:
  69. None.
  70. --*/
  71. {
  72. INET_ASSERT(SerializedList != NULL);
  73. SerializedList->Signature = SERIALIZED_LIST_SIGNATURE;
  74. SerializedList->LockCount = 0;
  75. INITIALIZE_RESOURCE_INFO(&SerializedList->ResourceInfo);
  76. InitializeListHead(&SerializedList->List);
  77. SerializedList->ElementCount = 0;
  78. return SerializedList->Lock.Init();
  79. }
  80. DEBUG_FUNCTION
  81. VOID
  82. TerminateSerializedList(
  83. IN LPSERIALIZED_LIST SerializedList
  84. )
  85. /*++
  86. Routine Description:
  87. Undoes InitializeSerializeList
  88. Arguments:
  89. SerializedList - pointer to serialized list to terminate
  90. Return Value:
  91. None.
  92. --*/
  93. {
  94. INET_ASSERT(SerializedList != NULL);
  95. INET_ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
  96. INET_ASSERT(SerializedList->ElementCount == 0);
  97. if (SerializedList->ElementCount != 0) {
  98. DEBUG_PRINT(SERIALST,
  99. ERROR,
  100. ("list @ %#x has %d elements, first is %#x\n",
  101. SerializedList,
  102. SerializedList->ElementCount,
  103. SerializedList->List.Flink
  104. ));
  105. } else {
  106. INET_ASSERT(IsListEmpty(&SerializedList->List));
  107. }
  108. SerializedList->Lock.FreeLock();
  109. }
  110. DEBUG_FUNCTION
  111. BOOL
  112. LockSerializedList(
  113. IN LPSERIALIZED_LIST SerializedList
  114. )
  115. /*++
  116. Routine Description:
  117. Acquires a serialized list locks
  118. Arguments:
  119. SerializedList - SERIALIZED_LIST to lock
  120. Return Value:
  121. Success if able to acquire a lock.
  122. --*/
  123. {
  124. INET_ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
  125. INET_ASSERT(SerializedList->LockCount >= 0);
  126. if ((!SerializedList->Lock.IsInitialized() && !SerializedList->Lock.Init()) ||
  127. !SerializedList->Lock.Lock())
  128. {
  129. return FALSE;
  130. }
  131. else
  132. {
  133. if (SerializedList->LockCount != 0)
  134. {
  135. INET_ASSERT(SerializedList->ResourceInfo.Tid == GetCurrentThreadId());
  136. }
  137. }
  138. ++SerializedList->LockCount;
  139. SerializedList->ResourceInfo.Tid = GetCurrentThreadId();
  140. return TRUE;
  141. }
  142. DEBUG_FUNCTION
  143. VOID
  144. UnlockSerializedList(
  145. IN LPSERIALIZED_LIST SerializedList
  146. )
  147. /*++
  148. Routine Description:
  149. Releases a serialized list lock
  150. Arguments:
  151. SerializedList - SERIALIZED_LIST to unlock
  152. Return Value:
  153. None.
  154. --*/
  155. {
  156. INET_ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
  157. INET_ASSERT(SerializedList->ResourceInfo.Tid == GetCurrentThreadId());
  158. INET_ASSERT(SerializedList->LockCount > 0);
  159. --SerializedList->LockCount;
  160. SerializedList->Lock.Unlock();
  161. }
  162. DEBUG_FUNCTION
  163. BOOL
  164. InsertAtHeadOfSerializedList(
  165. IN LPSERIALIZED_LIST SerializedList,
  166. IN PLIST_ENTRY Entry
  167. )
  168. /*++
  169. Routine Description:
  170. Adds an item to the head of a serialized list
  171. Arguments:
  172. SerializedList - SERIALIZED_LIST to update
  173. Entry - thing to update it with
  174. Return Value:
  175. FALSE - only if unable to acquire the lock
  176. --*/
  177. {
  178. INET_ASSERT(Entry != &SerializedList->List);
  179. if (LockSerializedList(SerializedList))
  180. {
  181. if (fCheckEntryOnList)
  182. {
  183. CheckEntryOnList(&SerializedList->List, Entry, FALSE);
  184. }
  185. InsertHeadList(&SerializedList->List, Entry);
  186. ++SerializedList->ElementCount;
  187. INET_ASSERT(SerializedList->ElementCount > 0);
  188. UnlockSerializedList(SerializedList);
  189. return TRUE;
  190. }
  191. else
  192. {
  193. return FALSE;
  194. }
  195. }
  196. DEBUG_FUNCTION
  197. BOOL
  198. InsertAtTailOfSerializedList(
  199. IN LPSERIALIZED_LIST SerializedList,
  200. IN PLIST_ENTRY Entry
  201. )
  202. /*++
  203. Routine Description:
  204. Adds an item to the head of a serialized list
  205. Arguments:
  206. SerializedList - SERIALIZED_LIST to update
  207. Entry - thing to update it with
  208. Return Value:
  209. FALSE - only if not enough memory was available to insert an item.
  210. --*/
  211. {
  212. INET_ASSERT(Entry != &SerializedList->List);
  213. if (LockSerializedList(SerializedList))
  214. {
  215. if (fCheckEntryOnList) {
  216. CheckEntryOnList(&SerializedList->List, Entry, FALSE);
  217. }
  218. InsertTailList(&SerializedList->List, Entry);
  219. ++SerializedList->ElementCount;
  220. INET_ASSERT(SerializedList->ElementCount > 0);
  221. UnlockSerializedList(SerializedList);
  222. return TRUE;
  223. }
  224. return FALSE;
  225. }
  226. BOOL
  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. FALSE if unable sycnhronize access to the list due to low-memory.
  240. --*/
  241. {
  242. INET_ASSERT((Entry->Flink != NULL) && (Entry->Blink != NULL));
  243. if (LockSerializedList(SerializedList))
  244. {
  245. if (fCheckEntryOnList)
  246. {
  247. CheckEntryOnList(&SerializedList->List, Entry, TRUE);
  248. }
  249. INET_ASSERT(SerializedList->ElementCount > 0);
  250. RemoveEntryList(Entry);
  251. --SerializedList->ElementCount;
  252. Entry->Flink = NULL;
  253. Entry->Blink = NULL;
  254. UnlockSerializedList(SerializedList);
  255. return TRUE;
  256. }
  257. else
  258. {
  259. return FALSE;
  260. }
  261. }
  262. DEBUG_FUNCTION
  263. BOOL
  264. IsSerializedListEmpty(
  265. IN LPSERIALIZED_LIST SerializedList
  266. )
  267. /*++
  268. Routine Description:
  269. Checks if a serialized list contains any elements
  270. Arguments:
  271. SerializedList - pointer to list to check
  272. Return Value:
  273. BOOL
  274. --*/
  275. {
  276. // For simplicity, don't worry about returning additional status.
  277. // Due to this always being tied to additional manipulation,
  278. // the lock has already been acquired in all current cases.
  279. if (!LockSerializedList(SerializedList))
  280. return TRUE;
  281. INET_ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
  282. BOOL empty;
  283. if (IsListEmpty(&SerializedList->List)) {
  284. INET_ASSERT(SerializedList->ElementCount == 0);
  285. empty = TRUE;
  286. } else {
  287. INET_ASSERT(SerializedList->ElementCount != 0);
  288. empty = FALSE;
  289. }
  290. UnlockSerializedList(SerializedList);
  291. return empty;
  292. }
  293. DEBUG_FUNCTION
  294. PLIST_ENTRY
  295. HeadOfSerializedList(
  296. IN LPSERIALIZED_LIST SerializedList
  297. )
  298. /*++
  299. Routine Description:
  300. Returns the element at the tail of the list, without taking the lock
  301. Arguments:
  302. SerializedList - pointer to SERIALIZED_LIST
  303. Return Value:
  304. PLIST_ENTRY
  305. pointer to element at tail of list
  306. --*/
  307. {
  308. INET_ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
  309. return SerializedList->List.Flink;
  310. }
  311. DEBUG_FUNCTION
  312. PLIST_ENTRY
  313. TailOfSerializedList(
  314. IN LPSERIALIZED_LIST SerializedList
  315. )
  316. /*++
  317. Routine Description:
  318. Returns the element at the tail of the list, without taking the lock
  319. Arguments:
  320. SerializedList - pointer to SERIALIZED_LIST
  321. Return Value:
  322. PLIST_ENTRY
  323. pointer to element at tail of list
  324. --*/
  325. {
  326. INET_ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
  327. return SerializedList->List.Blink;
  328. }
  329. DEBUG_FUNCTION
  330. BOOL
  331. CheckEntryOnSerializedList(
  332. IN LPSERIALIZED_LIST SerializedList,
  333. IN PLIST_ENTRY Entry,
  334. IN BOOL ExpectedResult
  335. )
  336. /*++
  337. Routine Description:
  338. Checks an entry exists (or doesn't exist) on a list
  339. Arguments:
  340. SerializedList - pointer to serialized list
  341. Entry - pointer to entry
  342. ExpectedResult - TRUE if expected on list, else FALSE
  343. Return Value:
  344. BOOL
  345. TRUE - expected result
  346. FALSE - unexpected result
  347. --*/
  348. {
  349. INET_ASSERT(SerializedList->Signature == SERIALIZED_LIST_SIGNATURE);
  350. if (!LockSerializedList(SerializedList))
  351. return FALSE;
  352. BOOL result;
  353. __try {
  354. result = CheckEntryOnList(&SerializedList->List, Entry, ExpectedResult);
  355. } __except(EXCEPTION_EXECUTE_HANDLER) {
  356. DEBUG_PRINT(SERIALST,
  357. FATAL,
  358. ("List @ %#x (%d elements) is bad\n",
  359. SerializedList,
  360. SerializedList->ElementCount
  361. ));
  362. result = FALSE;
  363. }
  364. ENDEXCEPT
  365. UnlockSerializedList(SerializedList);
  366. return result;
  367. }
  368. PRIVATE
  369. DEBUG_FUNCTION
  370. BOOL
  371. CheckEntryOnList(
  372. IN PLIST_ENTRY List,
  373. IN PLIST_ENTRY Entry,
  374. IN BOOL ExpectedResult
  375. )
  376. {
  377. BOOLEAN found = FALSE;
  378. PLIST_ENTRY p;
  379. if (!IsListEmpty(List)) {
  380. for (p = List->Flink; p != List; p = p->Flink) {
  381. if (p == Entry) {
  382. found = TRUE;
  383. break;
  384. }
  385. }
  386. }
  387. if (found != ExpectedResult) {
  388. if (ReportCheckEntryOnListErrors) {
  389. LPSTR description;
  390. description = found
  391. ? "Entry %#x already on list %#x\n"
  392. : "Entry %#x not found on list %#x\n"
  393. ;
  394. DEBUG_PRINT(SERIALST,
  395. ERROR,
  396. (description,
  397. Entry,
  398. List
  399. ));
  400. DEBUG_BREAK(SERIALST);
  401. }
  402. return FALSE;
  403. }
  404. return TRUE;
  405. }
  406. #else // else !INET_DEBUG
  407. BOOL
  408. InitializeSerializedList(LPSERIALIZED_LIST pList)
  409. {
  410. InitializeListHead(&(pList)->List);
  411. (pList)->ElementCount = 0;
  412. return (pList->Lock).Init();
  413. }
  414. BOOL
  415. InsertAtHeadOfSerializedList(LPSERIALIZED_LIST list, PLIST_ENTRY entry)
  416. {
  417. if (LockSerializedList(list))
  418. {
  419. InsertHeadList(&(list)->List, entry);
  420. ++(list)->ElementCount;
  421. UnlockSerializedList(list);
  422. return TRUE;
  423. }
  424. else
  425. {
  426. return FALSE;
  427. }
  428. }
  429. BOOL
  430. InsertAtTailOfSerializedList(LPSERIALIZED_LIST list, PLIST_ENTRY entry)
  431. {
  432. if (LockSerializedList(list))
  433. {
  434. InsertTailList(&(list)->List, entry);
  435. ++(list)->ElementCount;
  436. UnlockSerializedList(list);
  437. return TRUE;
  438. }
  439. else
  440. {
  441. return FALSE;
  442. }
  443. }
  444. BOOL
  445. RemoveFromSerializedList(LPSERIALIZED_LIST list, PLIST_ENTRY entry)
  446. {
  447. if (LockSerializedList(list))
  448. {
  449. RemoveEntryList(entry);
  450. --(list)->ElementCount;
  451. UnlockSerializedList(list);
  452. return TRUE;
  453. }
  454. else
  455. {
  456. return FALSE;
  457. }
  458. }
  459. #endif // INET_DEBUG
  460. //
  461. // functions that are always functions
  462. //
  463. LPVOID
  464. SlDequeueHead(
  465. IN LPSERIALIZED_LIST SerializedList
  466. )
  467. /*++
  468. Routine Description:
  469. Dequeues the element at the head of the queue and returns its address or
  470. NULL if the queue is empty
  471. Arguments:
  472. SerializedList - pointer to SERIALIZED_LIST to dequeue from
  473. Return Value:
  474. LPVOID
  475. --*/
  476. {
  477. LPVOID entry = NULL;
  478. if (!IsSerializedListEmpty(SerializedList)) {
  479. if (LockSerializedList(SerializedList)) {
  480. if (!IsSerializedListEmpty(SerializedList)) {
  481. entry = (LPVOID)HeadOfSerializedList(SerializedList);
  482. if (!RemoveFromSerializedList(SerializedList, (PLIST_ENTRY)entry))
  483. entry = NULL;
  484. }
  485. UnlockSerializedList(SerializedList);
  486. }
  487. }
  488. return entry;
  489. }
  490. LPVOID
  491. SlDequeueTail(
  492. IN LPSERIALIZED_LIST SerializedList
  493. )
  494. /*++
  495. Routine Description:
  496. Dequeues the element at the tail of the queue and returns its address or
  497. NULL if the queue is empty
  498. Arguments:
  499. SerializedList - pointer to SERIALIZED_LIST to dequeue from
  500. Return Value:
  501. LPVOID
  502. --*/
  503. {
  504. LPVOID entry = NULL;
  505. if (!IsSerializedListEmpty(SerializedList)) {
  506. if (LockSerializedList(SerializedList)) {
  507. if (!IsSerializedListEmpty(SerializedList)) {
  508. entry = (LPVOID)TailOfSerializedList(SerializedList);
  509. if (!RemoveFromSerializedList(SerializedList, (PLIST_ENTRY)entry))
  510. entry = NULL;
  511. }
  512. UnlockSerializedList(SerializedList);
  513. }
  514. } else {
  515. entry = NULL;
  516. }
  517. return entry;
  518. }
  519. BOOL
  520. IsOnSerializedList(
  521. IN LPSERIALIZED_LIST SerializedList,
  522. IN PLIST_ENTRY Entry
  523. )
  524. /*++
  525. Routine Description:
  526. Checks if an entry is on a serialized list. Useful to call before
  527. RemoveFromSerializedList() if multiple threads can remove the element
  528. Arguments:
  529. SerializedList - pointer to SERIALIZED_LIST
  530. Entry - pointer to element to check
  531. Return Value:
  532. BOOL
  533. TRUE - Entry is on SerializedList
  534. FALSE - " " not on "
  535. --*/
  536. {
  537. BOOL onList = FALSE;
  538. LPVOID entry;
  539. if (!IsSerializedListEmpty(SerializedList)) {
  540. if (LockSerializedList(SerializedList)) {
  541. if (!IsSerializedListEmpty(SerializedList)) {
  542. for (PLIST_ENTRY entry = HeadOfSerializedList(SerializedList);
  543. entry != (PLIST_ENTRY)SlSelf(SerializedList);
  544. entry = entry->Flink) {
  545. if (entry == Entry) {
  546. onList = TRUE;
  547. break;
  548. }
  549. }
  550. }
  551. UnlockSerializedList(SerializedList);
  552. }
  553. }
  554. return onList;
  555. }