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.

1116 lines
32 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2000-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dnnbqueue.cpp
  6. * Content: DirectPlay implementations of OS NBQueue functions
  7. *
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 04/24/2000 davec Created nbqueue.c
  12. * 10/31/2001 vanceo Converted for use in DPlay source
  13. *
  14. ***************************************************************************/
  15. #include "dncmni.h"
  16. // Until this gets ported, we won't use the NBQueue functions if WINCE is
  17. // defined.
  18. // Also, for DPNBUILD_ONLYONETHREAD builds we want to use the fallback code
  19. // because the critical sections get compiled away and we're left with a simple
  20. // queue.
  21. //=============================================================================
  22. #if ((defined(WINCE)) || (defined(DPNBUILD_ONLYONETHREAD)))
  23. //=============================================================================
  24. //
  25. // For now, the Windows CE NBQueue is just a critical section protected list.
  26. // On DPNBUILD_ONLYONETHREAD builds, we use the same structure because
  27. // the critical section will be compiled away.
  28. //
  29. typedef struct _DNNBQUEUE_HEADER
  30. {
  31. DNSLIST_HEADER * pSlistHeadFreeNodes; // pointer to Slist containing free nodes, the user must add 1 DNNBQUEUE_BLOCK for every item to be in the queue + 1 extra
  32. DNNBQUEUE_BLOCK * pHead;
  33. DNNBQUEUE_BLOCK * pTail;
  34. #ifndef DPNBUILD_ONLYONETHREAD
  35. DNCRITICAL_SECTION csLock;
  36. #endif // !DPNBUILD_ONLYONETHREAD
  37. } DNNBQUEUE_HEADER, *PDNNBQUEUE_HEADER;
  38. #undef DPF_MODNAME
  39. #define DPF_MODNAME "DNInitializeNBQueueHead"
  40. //=============================================================================
  41. // DNInitializeNBQueueHead
  42. //-----------------------------------------------------------------------------
  43. //
  44. // Description: This function creates and initializes a non-blocking queue
  45. // header. The specified SList must contain at least one pre-
  46. // allocated DNNBQUEUE_BLOCK.
  47. //
  48. // Arguments:
  49. // DNSLIST_HEADER * pSlistHeadFreeNodes - Pointer to list with free nodes.
  50. //
  51. // Returns: Pointer to queue header memory if successful, NULL if failed.
  52. //=============================================================================
  53. PVOID WINAPI DNInitializeNBQueueHead(DNSLIST_HEADER * const pSlistHeadFreeNodes)
  54. {
  55. DNNBQUEUE_HEADER * pQueueHeader;
  56. DNASSERT(pSlistHeadFreeNodes != NULL);
  57. pQueueHeader = (DNNBQUEUE_HEADER*) DNMalloc(sizeof(DNNBQUEUE_HEADER));
  58. if (pQueueHeader != NULL)
  59. {
  60. pQueueHeader->pSlistHeadFreeNodes = pSlistHeadFreeNodes;
  61. pQueueHeader->pHead = NULL;
  62. pQueueHeader->pTail = NULL;
  63. if (! DNInitializeCriticalSection(&pQueueHeader->csLock))
  64. {
  65. DNFree(pQueueHeader);
  66. pQueueHeader = NULL;
  67. }
  68. else
  69. {
  70. DebugSetCriticalSectionRecursionCount(&pQueueHeader->csLock, 0);
  71. }
  72. }
  73. return pQueueHeader;
  74. } // DNInitializeNBQueueHead
  75. #undef DPF_MODNAME
  76. #define DPF_MODNAME "DNDeinitializeNBQueueHead"
  77. //=============================================================================
  78. // DNDeinitializeNBQueueHead
  79. //-----------------------------------------------------------------------------
  80. //
  81. // Description: This function cleans up a previously initialized non-
  82. // blocking queue header.
  83. //
  84. // Arguments:
  85. // PVOID pvQueueHeader - Pointer to queue header.
  86. //
  87. // Returns: None.
  88. //=============================================================================
  89. void WINAPI DNDeinitializeNBQueueHead(PVOID const pvQueueHeader)
  90. {
  91. DNNBQUEUE_HEADER * pQueueHeader;
  92. DNASSERT(pvQueueHeader != NULL);
  93. pQueueHeader = (DNNBQUEUE_HEADER*) pvQueueHeader;
  94. DNASSERT(pQueueHeader->pHead == NULL);
  95. DNASSERT(pQueueHeader->pTail == NULL);
  96. DNDeleteCriticalSection(&pQueueHeader->csLock);
  97. DNFree(pQueueHeader);
  98. pQueueHeader = NULL;
  99. } // DNDeinitializeNBQueueHead
  100. #undef DPF_MODNAME
  101. #define DPF_MODNAME "DNInsertTailNBQueue"
  102. //=============================================================================
  103. // DNInsertTailNBQueue
  104. //-----------------------------------------------------------------------------
  105. //
  106. // Description: This function inserts the specified value at the tail of the
  107. // specified non-blocking queue.
  108. //
  109. // Arguments:
  110. // PVOID pvQueueHeader - Pointer to queue header.
  111. // ULONG64 Value - Value to insert.
  112. //
  113. // Returns: None.
  114. //=============================================================================
  115. void WINAPI DNInsertTailNBQueue(PVOID const pvQueueHeader, const ULONG64 Value)
  116. {
  117. DNNBQUEUE_HEADER * pQueueHeader;
  118. DNNBQUEUE_BLOCK * pQueueNode;
  119. DNASSERT(pvQueueHeader != NULL);
  120. pQueueHeader = (DNNBQUEUE_HEADER*) pvQueueHeader;
  121. DNASSERT(Value != 0);
  122. //
  123. // Retrieve a queue node from the SLIST owned by the specified non-blocking
  124. // queue. If this fails, we will assert or crash.
  125. //
  126. DBG_CASSERT(sizeof(DNNBQUEUE_BLOCK) >= sizeof(DNSLIST_ENTRY));
  127. pQueueNode = (DNNBQUEUE_BLOCK*) DNInterlockedPopEntrySList(pQueueHeader->pSlistHeadFreeNodes);
  128. DNASSERT(pQueueNode != NULL);
  129. pQueueNode->Next = NULL;
  130. pQueueNode->Data = Value;
  131. DNEnterCriticalSection(&pQueueHeader->csLock);
  132. if (pQueueHeader->pTail == NULL)
  133. {
  134. DNASSERT(pQueueHeader->pHead == NULL);
  135. pQueueHeader->pHead = pQueueNode;
  136. }
  137. else
  138. {
  139. DNASSERT(pQueueHeader->pTail->Next == NULL);
  140. pQueueHeader->pTail->Next = (ULONG64) pQueueNode;
  141. }
  142. pQueueHeader->pTail = pQueueNode;
  143. DNLeaveCriticalSection(&pQueueHeader->csLock);
  144. } // DNInsertTailNBQueue
  145. #undef DPF_MODNAME
  146. #define DPF_MODNAME "DNRemoveHeadNBQueue"
  147. //=============================================================================
  148. // DNRemoveHeadNBQueue
  149. //-----------------------------------------------------------------------------
  150. //
  151. // Description: This function removes a queue entry from the head of the
  152. // specified non-blocking queue and returns its value.
  153. //
  154. // Arguments:
  155. // PVOID pvQueueHeader - Pointer to queue header.
  156. //
  157. // Returns: First value retrieved, or 0 if none.
  158. //=============================================================================
  159. ULONG64 WINAPI DNRemoveHeadNBQueue(PVOID const pvQueueHeader)
  160. {
  161. DNNBQUEUE_HEADER * pQueueHeader;
  162. ULONG64 ReturnValue;
  163. DNNBQUEUE_BLOCK * pNode;
  164. DNASSERT(pvQueueHeader != NULL);
  165. pQueueHeader = (DNNBQUEUE_HEADER*) pvQueueHeader;
  166. DNEnterCriticalSection(&pQueueHeader->csLock);
  167. pNode = pQueueHeader->pHead;
  168. if (pNode != NULL)
  169. {
  170. DNASSERT(pQueueHeader->pTail != NULL);
  171. pQueueHeader->pHead = (DNNBQUEUE_BLOCK*) pNode->Next;
  172. if (pQueueHeader->pHead == NULL)
  173. {
  174. DNASSERT(pQueueHeader->pTail == pNode);
  175. pQueueHeader->pTail = NULL;
  176. }
  177. DNLeaveCriticalSection(&pQueueHeader->csLock);
  178. ReturnValue = pNode->Data;
  179. //
  180. // Return the node that was removed for the list by inserting the node in
  181. // the associated SLIST.
  182. //
  183. DNInterlockedPushEntrySList(pQueueHeader->pSlistHeadFreeNodes,
  184. (DNSLIST_ENTRY*) pNode);
  185. }
  186. else
  187. {
  188. DNASSERT(pQueueHeader->pTail == NULL);
  189. DNLeaveCriticalSection(&pQueueHeader->csLock);
  190. ReturnValue = 0;
  191. }
  192. return ReturnValue;
  193. } // DNRemoveHeadNBQueue
  194. #undef DPF_MODNAME
  195. #define DPF_MODNAME "DNIsNBQueueEmpty"
  196. //=============================================================================
  197. // DNIsNBQueueEmpty
  198. //-----------------------------------------------------------------------------
  199. //
  200. // Description: This function returns TRUE if the queue contains no items at
  201. // this instant, FALSE if there are items.
  202. //
  203. // Arguments:
  204. // PVOID pvQueueHeader - Pointer to queue header.
  205. //
  206. // Returns: TRUE if queue is empty, FALSE otherwise.
  207. //=============================================================================
  208. BOOL WINAPI DNIsNBQueueEmpty(PVOID const pvQueueHeader)
  209. {
  210. DNNBQUEUE_HEADER * pQueueHeader;
  211. BOOL fReturn;
  212. DNASSERT(pvQueueHeader != NULL);
  213. pQueueHeader = (DNNBQUEUE_HEADER*) pvQueueHeader;
  214. DNEnterCriticalSection(&pQueueHeader->csLock);
  215. fReturn = (pQueueHeader->pHead == NULL) ? TRUE : FALSE;
  216. DNLeaveCriticalSection(&pQueueHeader->csLock);
  217. return fReturn;
  218. } // DNIsNBQueueEmpty
  219. #undef DPF_MODNAME
  220. #define DPF_MODNAME "DNAppendListNBQueue"
  221. //=============================================================================
  222. // DNAppendListNBQueue
  223. //-----------------------------------------------------------------------------
  224. //
  225. // Description: This function appends a queue of items to the tail of the
  226. // specified non-blocking queue. The queue of items to be added
  227. // must be linked in the form of an SLIST, where the actual
  228. // ULONG64 value to be queued is the DNSLIST_ENTRY pointer minus
  229. // iValueOffset.
  230. //
  231. // Arguments:
  232. // PVOID pvQueueHeader - Pointer to queue header.
  233. // DNSLIST_ENTRY * pSlistEntryAppend - Pointer to first item to append.
  234. // INT_PTR iValueOffset - How far DNSLIST_ENTRY field is offset
  235. //
  236. // Returns: None.
  237. //=============================================================================
  238. void WINAPI DNAppendListNBQueue(PVOID const pvQueueHeader,
  239. DNSLIST_ENTRY * const pSlistEntryAppend,
  240. INT_PTR iValueOffset)
  241. {
  242. DNNBQUEUE_HEADER * pQueueHeader;
  243. DNSLIST_ENTRY * pCurrent;
  244. DNNBQUEUE_BLOCK * pFirstQueueNode;
  245. DNNBQUEUE_BLOCK * pLastQueueNode;
  246. DNNBQUEUE_BLOCK * pCurrentQueueNode;
  247. DNASSERT(pvQueueHeader != NULL);
  248. pQueueHeader = (DNNBQUEUE_HEADER*) pvQueueHeader;
  249. DNASSERT(pSlistEntryAppend != NULL);
  250. //
  251. // Retrieve queue nodes for each value to add from the SLIST owned by the
  252. // specified non-blocking queue. If this fails, we will assert or crash.
  253. //
  254. pFirstQueueNode = NULL;
  255. pCurrent = pSlistEntryAppend;
  256. do
  257. {
  258. DBG_CASSERT(sizeof(DNNBQUEUE_BLOCK) >= sizeof(DNSLIST_ENTRY));
  259. pCurrentQueueNode = (DNNBQUEUE_BLOCK*) DNInterlockedPopEntrySList(pQueueHeader->pSlistHeadFreeNodes);
  260. DNASSERT(pCurrentQueueNode != NULL);
  261. //
  262. // Initialize the queue node next pointer and value.
  263. //
  264. pCurrentQueueNode->Next = NULL;
  265. pCurrentQueueNode->Data = (ULONG64) (pCurrent - iValueOffset);
  266. //
  267. // Link the item as appropriate.
  268. //
  269. if (pFirstQueueNode == NULL)
  270. {
  271. pFirstQueueNode = pCurrentQueueNode;
  272. pLastQueueNode = pCurrentQueueNode;
  273. }
  274. else
  275. {
  276. pLastQueueNode->Next = (ULONG64) pCurrentQueueNode;
  277. pLastQueueNode = pCurrentQueueNode;
  278. }
  279. pCurrent = pCurrent->Next;
  280. }
  281. while (pCurrent != NULL);
  282. //
  283. // Lock the queue and append the list.
  284. //
  285. DNEnterCriticalSection(&pQueueHeader->csLock);
  286. if (pQueueHeader->pTail == NULL)
  287. {
  288. DNASSERT(pQueueHeader->pHead == NULL);
  289. pQueueHeader->pHead = pFirstQueueNode;
  290. }
  291. else
  292. {
  293. DNASSERT(pQueueHeader->pTail->Next == NULL);
  294. pQueueHeader->pTail->Next = (ULONG64) pFirstQueueNode;
  295. }
  296. pQueueHeader->pTail = pLastQueueNode;
  297. DNLeaveCriticalSection(&pQueueHeader->csLock);
  298. } // DNAppendListNBQueue
  299. //=============================================================================
  300. #else // ! WINCE and ! DPNBUILD_ONLYONETHREAD
  301. //=============================================================================
  302. // Forward declare the generic node structure.
  303. typedef struct _DNNBQUEUE_NODE DNNBQUEUE_NODE, *PDNNBQUEUE_NODE;
  304. //
  305. // Define inline functions to pack and unpack pointers in the platform
  306. // specific non-blocking queue pointer structure, as well as
  307. // InterlockedCompareExchange64.
  308. //
  309. //-----------------------------------------------------------------------------
  310. #if defined(_AMD64_)
  311. //-----------------------------------------------------------------------------
  312. typedef union _DNNBQUEUE_POINTER
  313. {
  314. struct
  315. {
  316. LONG64 Node : 48;
  317. LONG64 Count : 16;
  318. };
  319. LONG64 Data;
  320. } DNNBQUEUE_POINTER, * PDNNBQUEUE_POINTER;
  321. __inline VOID PackNBQPointer(IN PDNNBQUEUE_POINTER Entry, IN PDNNBQUEUE_NODE Node)
  322. {
  323. Entry->Node = (LONG64)Node;
  324. return;
  325. }
  326. __inline PDNNBQUEUE_NODE UnpackNBQPointer(IN PDNNBQUEUE_POINTER Entry)
  327. {
  328. return (PDNNBQUEUE_NODE)((LONG64)(Entry->Node));
  329. }
  330. //
  331. // For whatever reason we need to redirect through an inline, the compiler doesn't
  332. // like the casting when calling it directly through a macro.
  333. //
  334. inline LONG64 _DNInterlockedCompareExchange64(volatile PVOID * Destination, PVOID Exchange, PVOID Comperand)
  335. { return reinterpret_cast<LONG64>(InterlockedCompareExchangePointer(Destination, Exchange, Comperand)); }
  336. #define DNInterlockedCompareExchange64(Destination, Exchange, Comperand) \
  337. _DNInterlockedCompareExchange64((volatile PVOID*) (Destination), reinterpret_cast<void*>(Exchange), reinterpret_cast<void*>(Comperand))
  338. //-----------------------------------------------------------------------------
  339. #elif defined(_IA64_)
  340. //-----------------------------------------------------------------------------
  341. typedef union _DNNBQUEUE_POINTER
  342. {
  343. struct
  344. {
  345. LONG64 Node : 45;
  346. LONG64 Region : 3;
  347. LONG64 Count : 16;
  348. };
  349. LONG64 Data;
  350. } DNNBQUEUE_POINTER, *PDNNBQUEUE_POINTER;
  351. __inline VOID PackNBQPointer(IN PDNNBQUEUE_POINTER Entry, IN PDNNBQUEUE_NODE Node)
  352. {
  353. Entry->Node = (LONG64)Node;
  354. Entry->Region = (LONG64)Node >> 61;
  355. return;
  356. }
  357. __inline PDNNBQUEUE_NODE UnpackNBQPointer(IN PDNNBQUEUE_POINTER Entry)
  358. {
  359. LONG64 Value;
  360. Value = Entry->Node & 0x1fffffffffffffff;
  361. Value |= Entry->Region << 61;
  362. return (PDNNBQUEUE_NODE)(Value);
  363. }
  364. //
  365. // For whatever reason we need to redirect through an inline, the compiler doesn't
  366. // like the casting when calling it directly through a macro.
  367. //
  368. inline LONG64 _DNInterlockedCompareExchange64(volatile PVOID * Destination, PVOID Exchange, PVOID Comperand)
  369. { return reinterpret_cast<LONG64>(InterlockedCompareExchangePointer(Destination, Exchange, Comperand)); }
  370. #define DNInterlockedCompareExchange64(Destination, Exchange, Comperand) \
  371. _DNInterlockedCompareExchange64((volatile PVOID*) (Destination), reinterpret_cast<void*>(Exchange), reinterpret_cast<void*>(Comperand))
  372. //-----------------------------------------------------------------------------
  373. #elif defined(_X86_)
  374. //-----------------------------------------------------------------------------
  375. typedef union _DNNBQUEUE_POINTER
  376. {
  377. struct
  378. {
  379. LONG Count;
  380. LONG Node;
  381. };
  382. LONG64 Data;
  383. } DNNBQUEUE_POINTER, *PDNNBQUEUE_POINTER;
  384. __inline VOID PackNBQPointer(IN PDNNBQUEUE_POINTER Entry, IN PDNNBQUEUE_NODE Node)
  385. {
  386. Entry->Node = (LONG)Node;
  387. return;
  388. }
  389. __inline PDNNBQUEUE_NODE UnpackNBQPointer(IN PDNNBQUEUE_POINTER Entry)
  390. {
  391. return (PDNNBQUEUE_NODE)(Entry->Node);
  392. }
  393. #define DNInterlockedCompareExchange64(Destination, Exchange, Comperand) \
  394. xInterlockedCompareExchange64(Destination, &(Exchange), &(Comperand))
  395. __declspec(naked)
  396. LONG64 __fastcall xInterlockedCompareExchange64(IN OUT LONG64 volatile * Destination, IN PLONG64 Exchange, IN PLONG64 Comperand)
  397. {
  398. __asm
  399. {
  400. // Save nonvolatile registers and read the exchange and comperand values.
  401. push ebx ; save nonvolatile registers
  402. push ebp ;
  403. mov ebp, ecx ; set destination address
  404. mov ebx, [edx] ; get exchange value
  405. mov ecx, [edx] + 4 ;
  406. mov edx, [esp] + 12 ; get comperand address
  407. mov eax, [edx] ; get comperand value
  408. mov edx, [edx] + 4 ;
  409. lock cmpxchg8b qword ptr [ebp] ; compare and exchange
  410. // Restore nonvolatile registers and return result in edx:eax.
  411. pop ebp ; restore nonvolatile registers
  412. pop ebx ;
  413. ret 4
  414. }
  415. }
  416. //-----------------------------------------------------------------------------
  417. #else
  418. //-----------------------------------------------------------------------------
  419. #error "no target architecture"
  420. //-----------------------------------------------------------------------------
  421. #endif
  422. //-----------------------------------------------------------------------------
  423. struct _DNNBQUEUE_NODE
  424. {
  425. DNNBQUEUE_POINTER Next;
  426. ULONG64 Value;
  427. };
  428. typedef struct _DNNBQUEUE_HEADER
  429. {
  430. DNSLIST_HEADER * pSlistHeadFreeNodes; // pointer to Slist containing free nodes, the user must add 1 DNNBQUEUE_BLOCK for every item to be in the queue + 1 extra
  431. DNNBQUEUE_POINTER Head;
  432. DNNBQUEUE_POINTER Tail;
  433. } DNNBQUEUE_HEADER, *PDNNBQUEUE_HEADER;
  434. /*
  435. //=============================================================================
  436. // Globals
  437. //=============================================================================
  438. #if ((defined(DBG)) && (defined(_X86_)))
  439. DNCRITICAL_SECTION g_csValidation;
  440. DWORD g_dwEntries;
  441. #endif // DBG and _X86_
  442. */
  443. #undef DPF_MODNAME
  444. #define DPF_MODNAME "DNInitializeNBQueueHead"
  445. //=============================================================================
  446. // DNInitializeNBQueueHead
  447. //-----------------------------------------------------------------------------
  448. //
  449. // Description: This function creates and initializes a non-blocking queue
  450. // header. The specified SList must contain at least one pre-
  451. // allocated DNNBQUEUE_BLOCK.
  452. //
  453. // Arguments:
  454. // DNSLIST_HEADER * pSlistHeadFreeNodes - Pointer to list with free nodes.
  455. //
  456. // Returns: Pointer to queue header memory if successful, NULL if failed.
  457. //=============================================================================
  458. PVOID WINAPI DNInitializeNBQueueHead(DNSLIST_HEADER * const pSlistHeadFreeNodes)
  459. {
  460. DNNBQUEUE_HEADER * pQueueHeader;
  461. DNNBQUEUE_NODE * pQueueNode;
  462. DNASSERT(pSlistHeadFreeNodes != NULL);
  463. pQueueHeader = (DNNBQUEUE_HEADER*) DNMalloc(sizeof(DNNBQUEUE_HEADER));
  464. if (pQueueHeader != NULL)
  465. {
  466. pQueueHeader->pSlistHeadFreeNodes = pSlistHeadFreeNodes;
  467. pQueueNode = (DNNBQUEUE_NODE*) DNInterlockedPopEntrySList(pQueueHeader->pSlistHeadFreeNodes);
  468. DNASSERT(pQueueNode != NULL);
  469. //
  470. // Initialize the initial root node's next pointer and value.
  471. //
  472. pQueueNode->Next.Data = 0;
  473. pQueueNode->Value = 0;
  474. //
  475. // Initialize the head and tail pointers in the queue header.
  476. //
  477. PackNBQPointer(&pQueueHeader->Head, pQueueNode);
  478. pQueueHeader->Head.Count = 0;
  479. PackNBQPointer(&pQueueHeader->Tail, pQueueNode);
  480. pQueueHeader->Tail.Count = 0;
  481. /*
  482. #if ((defined(DBG)) && (defined(_X86_)))
  483. DNInitializeCriticalSection(&g_csValidation);
  484. g_dwEntries = 1;
  485. #endif // DBG and _X86_
  486. */
  487. }
  488. return pQueueHeader;
  489. } // DNInitializeNBQueueHead
  490. #undef DPF_MODNAME
  491. #define DPF_MODNAME "DNDeinitializeNBQueueHead"
  492. //=============================================================================
  493. // DNDeinitializeNBQueueHead
  494. //-----------------------------------------------------------------------------
  495. //
  496. // Description: This function cleans up a previously initialized non-
  497. // blocking queue header.
  498. //
  499. // Arguments:
  500. // PVOID pvQueueHeader - Pointer to queue header.
  501. //
  502. // Returns: None.
  503. //=============================================================================
  504. void WINAPI DNDeinitializeNBQueueHead(PVOID const pvQueueHeader)
  505. {
  506. DNNBQUEUE_HEADER * pQueueHeader;
  507. DNNBQUEUE_NODE * pQueueNode;
  508. #ifdef DBG
  509. DNNBQUEUE_NODE * pQueueNodeCompare;
  510. #endif // DBG
  511. DNASSERT(pvQueueHeader != NULL);
  512. pQueueHeader = (DNNBQUEUE_HEADER*) pvQueueHeader;
  513. //
  514. // There should be just the root node left.
  515. //
  516. pQueueNode = UnpackNBQPointer(&pQueueHeader->Head);
  517. #ifdef DBG
  518. DNASSERT(pQueueNode != NULL);
  519. pQueueNodeCompare = UnpackNBQPointer(&pQueueHeader->Tail);
  520. DNASSERT(pQueueNode == pQueueNodeCompare);
  521. #endif // DBG
  522. //
  523. // Return the node that was removed for the list by
  524. // inserting the node in the associated SLIST.
  525. //
  526. DNInterlockedPushEntrySList(pQueueHeader->pSlistHeadFreeNodes,
  527. (DNSLIST_ENTRY*) pQueueNode);
  528. DNFree(pQueueHeader);
  529. pQueueHeader = NULL;
  530. } // DNDeinitializeNBQueueHead
  531. #undef DPF_MODNAME
  532. #define DPF_MODNAME "DNInsertTailNBQueue"
  533. //=============================================================================
  534. // DNInsertTailNBQueue
  535. //-----------------------------------------------------------------------------
  536. //
  537. // Description: This function inserts the specified value at the tail of the
  538. // specified non-blocking queue.
  539. //
  540. // Arguments:
  541. // PVOID pvQueueHeader - Pointer to queue header.
  542. // ULONG64 Value - Value to insert.
  543. //
  544. // Returns: None.
  545. //=============================================================================
  546. void WINAPI DNInsertTailNBQueue(PVOID const pvQueueHeader, const ULONG64 Value)
  547. {
  548. DNNBQUEUE_HEADER * pQueueHeader;
  549. DNNBQUEUE_POINTER Insert;
  550. DNNBQUEUE_POINTER Next;
  551. DNNBQUEUE_NODE * pNextNode;
  552. DNNBQUEUE_NODE * pQueueNode;
  553. DNNBQUEUE_POINTER Tail;
  554. DNNBQUEUE_NODE * pTailNode;
  555. DNASSERT(pvQueueHeader != NULL);
  556. pQueueHeader = (DNNBQUEUE_HEADER*) pvQueueHeader;
  557. DNASSERT(Value != 0);
  558. //
  559. // Retrieve a queue node from the SLIST owned by the specified non-blocking
  560. // queue. If this fails, we will assert or crash.
  561. //
  562. DBG_CASSERT(sizeof(DNNBQUEUE_NODE) >= sizeof(DNSLIST_ENTRY));
  563. pQueueNode = (DNNBQUEUE_NODE*) DNInterlockedPopEntrySList(pQueueHeader->pSlistHeadFreeNodes);
  564. DNASSERT(pQueueNode != NULL);
  565. //
  566. // Initialize the queue node next pointer and value.
  567. //
  568. pQueueNode->Next.Data = 0;
  569. pQueueNode->Value = Value;
  570. //
  571. // The following loop is executed until the specified entry can be safely
  572. // inserted at the tail of the specified non-blocking queue.
  573. //
  574. do
  575. {
  576. //
  577. // Read the tail queue pointer and the next queue pointer of the tail
  578. // queue pointer making sure the two pointers are coherent.
  579. //
  580. Tail.Data = *((volatile LONG64 *)(&pQueueHeader->Tail.Data));
  581. pTailNode = UnpackNBQPointer(&Tail);
  582. Next.Data = *((volatile LONG64 *)(&pTailNode->Next.Data));
  583. pQueueNode->Next.Count = Tail.Count + 1;
  584. if (Tail.Data == *((volatile LONG64 *)(&pQueueHeader->Tail.Data)))
  585. {
  586. //
  587. // If the tail is pointing to the last node in the list, then
  588. // attempt to insert the new node at the end of the list.
  589. // Otherwise, the tail is not pointing to the last node in the list
  590. // and an attempt is made to move the tail pointer to the next
  591. // node.
  592. //
  593. pNextNode = UnpackNBQPointer(&Next);
  594. if (pNextNode == NULL)
  595. {
  596. PackNBQPointer(&Insert, pQueueNode);
  597. Insert.Count = Next.Count + 1;
  598. if (DNInterlockedCompareExchange64(&pTailNode->Next.Data,
  599. Insert.Data,
  600. Next.Data) == Next.Data)
  601. {
  602. break;
  603. }
  604. }
  605. else
  606. {
  607. PackNBQPointer(&Insert, pNextNode);
  608. Insert.Count = Tail.Count + 1;
  609. DNInterlockedCompareExchange64(&pQueueHeader->Tail.Data,
  610. Insert.Data,
  611. Tail.Data);
  612. }
  613. }
  614. }
  615. while (TRUE);
  616. //
  617. // Attempt to move the tail to the new tail node.
  618. //
  619. PackNBQPointer(&Insert, pQueueNode);
  620. Insert.Count = Tail.Count + 1;
  621. DNInterlockedCompareExchange64(&pQueueHeader->Tail.Data,
  622. Insert.Data,
  623. Tail.Data);
  624. } // DNInsertTailNBQueue
  625. #undef DPF_MODNAME
  626. #define DPF_MODNAME "DNRemoveHeadNBQueue"
  627. //=============================================================================
  628. // DNRemoveHeadNBQueue
  629. //-----------------------------------------------------------------------------
  630. //
  631. // Description: This function removes a queue entry from the head of the
  632. // specified non-blocking queue and returns its value.
  633. //
  634. // Arguments:
  635. // PVOID pvQueueHeader - Pointer to queue header.
  636. //
  637. // Returns: First value retrieved, or 0 if none.
  638. //=============================================================================
  639. ULONG64 WINAPI DNRemoveHeadNBQueue(PVOID const pvQueueHeader)
  640. {
  641. DNNBQUEUE_HEADER * pQueueHeader;
  642. ULONG64 ReturnValue;
  643. DNNBQUEUE_POINTER Head;
  644. PDNNBQUEUE_NODE pHeadNode;
  645. DNNBQUEUE_POINTER Insert;
  646. DNNBQUEUE_POINTER Next;
  647. PDNNBQUEUE_NODE pNextNode;
  648. DNNBQUEUE_POINTER Tail;
  649. PDNNBQUEUE_NODE pTailNode;
  650. DNASSERT(pvQueueHeader != NULL);
  651. pQueueHeader = (DNNBQUEUE_HEADER*) pvQueueHeader;
  652. //
  653. // The following loop is executed until an entry can be removed from
  654. // the specified non-blocking queue or until it can be determined that
  655. // the queue is empty.
  656. //
  657. do
  658. {
  659. //
  660. // Read the head queue pointer, the tail queue pointer, and the
  661. // next queue pointer of the head queue pointer making sure the
  662. // three pointers are coherent.
  663. //
  664. Head.Data = *((volatile LONG64 *)(&pQueueHeader->Head.Data));
  665. Tail.Data = *((volatile LONG64 *)(&pQueueHeader->Tail.Data));
  666. pHeadNode = UnpackNBQPointer(&Head);
  667. Next.Data = *((volatile LONG64 *)(&pHeadNode->Next.Data));
  668. if (Head.Data == *((volatile LONG64 *)(&pQueueHeader->Head.Data)))
  669. {
  670. //
  671. // If the queue header node is equal to the queue tail node,
  672. // then either the queue is empty or the tail pointer is falling
  673. // behind. Otherwise, there is an entry in the queue that can
  674. // be removed.
  675. //
  676. pNextNode = UnpackNBQPointer(&Next);
  677. pTailNode = UnpackNBQPointer(&Tail);
  678. if (pHeadNode == pTailNode)
  679. {
  680. //
  681. // If the next node of head pointer is NULL, then the queue
  682. // is empty. Otherwise, attempt to move the tail forward.
  683. //
  684. if (pNextNode == NULL)
  685. {
  686. ReturnValue = 0;
  687. break;
  688. }
  689. else
  690. {
  691. PackNBQPointer(&Insert, pNextNode);
  692. Insert.Count = Tail.Count + 1;
  693. DNInterlockedCompareExchange64(&pQueueHeader->Tail.Data,
  694. Insert.Data,
  695. Tail.Data);
  696. }
  697. }
  698. else
  699. {
  700. //
  701. // There is an entry in the queue that can be removed.
  702. //
  703. ReturnValue = pNextNode->Value;
  704. PackNBQPointer(&Insert, pNextNode);
  705. Insert.Count = Head.Count + 1;
  706. if (DNInterlockedCompareExchange64(&pQueueHeader->Head.Data,
  707. Insert.Data,
  708. Head.Data) == Head.Data)
  709. {
  710. //
  711. // Return the node that was removed for the list by
  712. // inserting the node in the associated SLIST.
  713. //
  714. DNInterlockedPushEntrySList(pQueueHeader->pSlistHeadFreeNodes,
  715. (DNSLIST_ENTRY*) pHeadNode);
  716. break;
  717. }
  718. }
  719. }
  720. }
  721. while (TRUE);
  722. return ReturnValue;
  723. } // DNRemoveHeadNBQueue
  724. #undef DPF_MODNAME
  725. #define DPF_MODNAME "DNIsNBQueueEmpty"
  726. //=============================================================================
  727. // DNIsNBQueueEmpty
  728. //-----------------------------------------------------------------------------
  729. //
  730. // Description: This function returns TRUE if the queue contains no items at
  731. // this instant, FALSE if there are items.
  732. //
  733. // Arguments:
  734. // PVOID pvQueueHeader - Pointer to queue header.
  735. //
  736. // Returns: TRUE if queue is empty, FALSE otherwise.
  737. //=============================================================================
  738. BOOL WINAPI DNIsNBQueueEmpty(PVOID const pvQueueHeader)
  739. {
  740. DNNBQUEUE_HEADER * pQueueHeader;
  741. BOOL fReturn;
  742. DNNBQUEUE_POINTER Head;
  743. PDNNBQUEUE_NODE pHeadNode;
  744. DNNBQUEUE_POINTER Insert;
  745. DNNBQUEUE_POINTER Next;
  746. PDNNBQUEUE_NODE pNextNode;
  747. DNNBQUEUE_POINTER Tail;
  748. PDNNBQUEUE_NODE pTailNode;
  749. DNASSERT(pvQueueHeader != NULL);
  750. pQueueHeader = (DNNBQUEUE_HEADER*) pvQueueHeader;
  751. //
  752. // The following loop is executed until it can be determined that the queue
  753. // is empty or contains at least one item.
  754. //
  755. do
  756. {
  757. //
  758. // Read the head queue pointer, the tail queue pointer, and the
  759. // next queue pointer of the head queue pointer making sure the
  760. // three pointers are coherent.
  761. //
  762. Head.Data = *((volatile LONG64 *)(&pQueueHeader->Head.Data));
  763. Tail.Data = *((volatile LONG64 *)(&pQueueHeader->Tail.Data));
  764. pHeadNode = UnpackNBQPointer(&Head);
  765. Next.Data = *((volatile LONG64 *)(&pHeadNode->Next.Data));
  766. if (Head.Data == *((volatile LONG64 *)(&pQueueHeader->Head.Data)))
  767. {
  768. //
  769. // If the queue header node is equal to the queue tail node,
  770. // then either the queue is empty or the tail pointer is falling
  771. // behind. Otherwise, there is an entry in the queue that can
  772. // be removed.
  773. //
  774. pNextNode = UnpackNBQPointer(&Next);
  775. pTailNode = UnpackNBQPointer(&Tail);
  776. if (pHeadNode == pTailNode)
  777. {
  778. //
  779. // If the next node of head pointer is NULL, then the queue
  780. // is empty. Otherwise, attempt to move the tail forward.
  781. //
  782. if (pNextNode == NULL)
  783. {
  784. fReturn = TRUE;
  785. break;
  786. }
  787. else
  788. {
  789. PackNBQPointer(&Insert, pNextNode);
  790. Insert.Count = Tail.Count + 1;
  791. DNInterlockedCompareExchange64(&pQueueHeader->Tail.Data,
  792. Insert.Data,
  793. Tail.Data);
  794. }
  795. }
  796. else
  797. {
  798. //
  799. // There is an entry in the queue.
  800. //
  801. fReturn = FALSE;
  802. break;
  803. }
  804. }
  805. }
  806. while (TRUE);
  807. return fReturn;
  808. } // DNIsNBQueueEmpty
  809. #undef DPF_MODNAME
  810. #define DPF_MODNAME "DNAppendListNBQueue"
  811. //=============================================================================
  812. // DNAppendListNBQueue
  813. //-----------------------------------------------------------------------------
  814. //
  815. // Description: This function appends a queue of items to the tail of the
  816. // specified non-blocking queue. The queue of items to be added
  817. // must be linked in the form of an SLIST, where the actual
  818. // ULONG64 value to be queued is the DNSLIST_ENTRY pointer minus
  819. // iValueOffset.
  820. //
  821. // Arguments:
  822. // PVOID pvQueueHeader - Pointer to queue header.
  823. // DNSLIST_ENTRY * pSlistEntryAppend - Pointer to first item to append.
  824. // INT_PTR iValueOffset - How far DNSLIST_ENTRY field is offset
  825. // from start of value.
  826. //
  827. // Returns: None.
  828. //=============================================================================
  829. void WINAPI DNAppendListNBQueue(PVOID const pvQueueHeader,
  830. DNSLIST_ENTRY * const pSlistEntryAppend,
  831. INT_PTR iValueOffset)
  832. {
  833. DNNBQUEUE_HEADER * pQueueHeader;
  834. DNSLIST_ENTRY * pCurrent;
  835. DNNBQUEUE_POINTER Insert;
  836. DNNBQUEUE_POINTER Next;
  837. DNNBQUEUE_NODE * pNextNode;
  838. DNNBQUEUE_NODE * pFirstQueueNode;
  839. DNNBQUEUE_NODE * pLastQueueNode;
  840. DNNBQUEUE_NODE * pCurrentQueueNode;
  841. DNNBQUEUE_POINTER Tail;
  842. DNNBQUEUE_NODE * pTailNode;
  843. DNASSERT(pvQueueHeader != NULL);
  844. pQueueHeader = (DNNBQUEUE_HEADER*) pvQueueHeader;
  845. DNASSERT(pSlistEntryAppend != NULL);
  846. //
  847. // Retrieve queue nodes for each value to add from the SLIST owned by the
  848. // specified non-blocking queue. If this fails, we will assert or crash.
  849. //
  850. pFirstQueueNode = NULL;
  851. pCurrent = pSlistEntryAppend;
  852. do
  853. {
  854. DBG_CASSERT(sizeof(DNNBQUEUE_NODE) >= sizeof(DNSLIST_ENTRY));
  855. pCurrentQueueNode = (DNNBQUEUE_NODE*) DNInterlockedPopEntrySList(pQueueHeader->pSlistHeadFreeNodes);
  856. DNASSERT(pCurrentQueueNode != NULL);
  857. //
  858. // Initialize the queue node next pointer and value.
  859. //
  860. pCurrentQueueNode->Next.Data = 0;
  861. pCurrentQueueNode->Value = (ULONG64) (pCurrent - iValueOffset);
  862. //
  863. // Link the item as appropriate.
  864. //
  865. if (pFirstQueueNode == NULL)
  866. {
  867. pFirstQueueNode = pCurrentQueueNode;
  868. pLastQueueNode = pCurrentQueueNode;
  869. }
  870. else
  871. {
  872. PackNBQPointer(&pLastQueueNode->Next, pCurrentQueueNode);
  873. pLastQueueNode = pCurrentQueueNode;
  874. }
  875. pCurrent = pCurrent->Next;
  876. }
  877. while (pCurrent != NULL);
  878. //
  879. // The following loop is executed until the specified entries can be safely
  880. // inserted at the tail of the specified non-blocking queue.
  881. //
  882. do
  883. {
  884. //
  885. // Read the tail queue pointer and the next queue pointer of the tail
  886. // queue pointer making sure the two pointers are coherent.
  887. //
  888. Tail.Data = *((volatile LONG64 *)(&pQueueHeader->Tail.Data));
  889. pTailNode = UnpackNBQPointer(&Tail);
  890. Next.Data = *((volatile LONG64 *)(&pTailNode->Next.Data));
  891. pFirstQueueNode->Next.Count = Tail.Count + 1;
  892. if (Tail.Data == *((volatile LONG64 *)(&pQueueHeader->Tail.Data)))
  893. {
  894. //
  895. // If the tail is pointing to the last node in the list, then
  896. // attempt to insert the new nodes at the end of the list.
  897. // Otherwise, the tail is not pointing to the last node in the list
  898. // and an attempt is made to move the tail pointer to the next
  899. // node.
  900. //
  901. pNextNode = UnpackNBQPointer(&Next);
  902. if (pNextNode == NULL)
  903. {
  904. PackNBQPointer(&Insert, pFirstQueueNode);
  905. Insert.Count = Next.Count + 1;
  906. if (DNInterlockedCompareExchange64(&pTailNode->Next.Data,
  907. Insert.Data,
  908. Next.Data) == Next.Data)
  909. {
  910. break;
  911. }
  912. }
  913. else
  914. {
  915. PackNBQPointer(&Insert, pNextNode);
  916. Insert.Count = Tail.Count + 1;
  917. DNInterlockedCompareExchange64(&pQueueHeader->Tail.Data,
  918. Insert.Data,
  919. Tail.Data);
  920. }
  921. }
  922. }
  923. while (TRUE);
  924. //
  925. // Attempt to move the tail to the new tail node.
  926. //
  927. PackNBQPointer(&Insert, pLastQueueNode);
  928. Insert.Count = Tail.Count + 1;
  929. DNInterlockedCompareExchange64(&pQueueHeader->Tail.Data,
  930. Insert.Data,
  931. Tail.Data);
  932. } // DNAppendListNBQueue
  933. //=============================================================================
  934. #endif // ! WINCE and ! DPNBUILD_ONLYONETHREAD
  935. //=============================================================================