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.

1238 lines
26 KiB

  1. /****************************************************************************
  2. *
  3. *
  4. * INTEL Corporation Prorietary Information
  5. *
  6. * This listing is supplied under the terms of a license agreement
  7. * with INTEL Corporation and may not be copied nor disclosed except
  8. * in accordance with the terms of that agreement.
  9. *
  10. * Copyright (c) 1996 Intel Corporation.
  11. *
  12. *
  13. * Abstract:
  14. *
  15. * Notes:
  16. *
  17. ***************************************************************************/
  18. #ifndef __TSTABLE_H
  19. #define __TSTABLE_H
  20. #include <windows.h>
  21. typedef struct _LOCK_ENTRY
  22. {
  23. HANDLE hLock;
  24. int iLockCount;
  25. BOOL bCleanup,
  26. bDeleted;
  27. WORD wNextFree,
  28. wUniqueID;
  29. } LOCK_ENTRY, *PLOCK_ENTRY;
  30. // definition of an invalid ID
  31. #define TSTABLE_INVALID_ID (DWORD) 0xFFFFFFFF
  32. // return codes that the callback function used in conjunction with EnumerateEntries can return
  33. const DWORD CALLBACK_CONTINUE = 1;
  34. const DWORD CALLBACK_ABORT = 2;
  35. const DWORD CALLBACK_DELETE_ENTRY = 3;
  36. const DWORD CALLBACK_DELETE_ENTRY_AND_OBJECT = 4;
  37. // used in call to Lock
  38. #define TSTABLE_INVALID_UNIQUE_ID (WORD) 0xFFFF
  39. #define TSTABLE_INVALID_INDEX (WORD) 0xFFFF
  40. // This is a compare function that we aren't using right now. It
  41. // will be useful in the future if there is a reason to search
  42. // the table
  43. typedef INT (*ENTRY_COMPARE) (LPVOID ptr1, LPVOID ptr2);
  44. #if defined(DBG) && defined(ENABLE_DUMP_ENTRIES)
  45. VOID
  46. TSDbgPrint(
  47. LPSTR szFormat,
  48. ...
  49. )
  50. {
  51. #define DEBUG_FORMAT_HEADER "TABLE "
  52. #define DEBUG_FORMAT_TIMESTAMP "[%02u:%02u:%02u.%03u"
  53. #define DEBUG_FORMAT_THREADID ",tid=%x] "
  54. va_list Args;
  55. SYSTEMTIME SystemTime;
  56. char szDebugMessage[512+1];
  57. int nLengthRemaining;
  58. int nLength = 0;
  59. // retrieve local time
  60. GetLocalTime(&SystemTime);
  61. // add component header to the debug message
  62. nLength += sprintf(&szDebugMessage[nLength],
  63. DEBUG_FORMAT_HEADER
  64. );
  65. // add timestamp to the debug message
  66. nLength += sprintf(&szDebugMessage[nLength],
  67. DEBUG_FORMAT_TIMESTAMP,
  68. SystemTime.wHour,
  69. SystemTime.wMinute,
  70. SystemTime.wSecond,
  71. SystemTime.wMilliseconds
  72. );
  73. // add thread id to the debug message
  74. nLength += sprintf(&szDebugMessage[nLength],
  75. DEBUG_FORMAT_THREADID,
  76. GetCurrentThreadId()
  77. );
  78. // point at first argument
  79. va_start(Args, szFormat);
  80. // determine number of bytes left in buffer
  81. nLengthRemaining = sizeof(szDebugMessage) - nLength;
  82. // add user specified debug message
  83. _vsnprintf(&szDebugMessage[nLength],
  84. nLengthRemaining,
  85. szFormat,
  86. Args
  87. );
  88. // release pointer
  89. va_end(Args);
  90. // output message to specified sink
  91. OutputDebugString(szDebugMessage);
  92. }
  93. #endif
  94. template <class EntryData> class TSTable
  95. {
  96. typedef DWORD (*TABLE_CALLBACK) (EntryData* ptr, LPVOID context);
  97. public:
  98. TSTable (WORD _size);
  99. ~TSTable ();
  100. BOOL Resize (WORD wNewSize);
  101. BOOL CreateAndLock (EntryData* pEntryData,
  102. LPDWORD lpdwID);
  103. BOOL Validate (DWORD dwID);
  104. EntryData *Lock (DWORD dwID,
  105. DWORD timeout = INFINITE);
  106. BOOL Unlock (DWORD dwID);
  107. BOOL Delete (DWORD dwID,
  108. BOOL bCleanup = FALSE);
  109. EntryData *EnumerateEntries(TABLE_CALLBACK callBackFunc,
  110. void* context,
  111. BOOL bUnlockTable = FALSE);
  112. BOOL IsInitialized () {return bInitialized;}
  113. WORD GetSize () {return wNumUsed;}
  114. #if defined(DBG) && defined(ENABLE_DUMP_ENTRIES)
  115. VOID DumpEntries ();
  116. #endif
  117. private:
  118. // data
  119. EntryData** pDataTable;
  120. PLOCK_ENTRY pLockTable;
  121. CRITICAL_SECTION csTableLock;
  122. WORD wSize,
  123. wNumUsed,
  124. wFirstFree,
  125. wLastFree,
  126. wUniqueID;
  127. BOOL bInitialized;
  128. // private methods
  129. BOOL LockEntry (WORD wIndex,
  130. DWORD timeout = INFINITE);
  131. BOOL UnLockEntry(WORD wIndex);
  132. void LockTable () { EnterCriticalSection(&csTableLock); };
  133. void UnLockTable() { LeaveCriticalSection(&csTableLock); };
  134. WORD GenerateUniqueID();
  135. DWORD MakeID(WORD wIndex, WORD wUniqueID)
  136. {
  137. DWORD theID = wUniqueID;
  138. theID = (theID << 16) & 0xFFFF0000;
  139. theID |= wIndex;
  140. return(theID);
  141. };
  142. void BreakID(DWORD theID, WORD* pwIndex, WORD* pwUID)
  143. {
  144. *pwIndex = (WORD) (theID & 0x0000FFFF);
  145. *pwUID = (WORD) ((theID >> 16) & 0x0000FFFF);
  146. };
  147. };
  148. /*
  149. ** TSTable::TSTable
  150. *
  151. * FILENAME: c:\msdev\projects\firewalls\inc\tstable.h
  152. *
  153. * PARAMETERS:
  154. *
  155. * DESCRIPTION:
  156. *
  157. * RETURNS:
  158. *
  159. */
  160. template <class EntryData>
  161. TSTable<EntryData>::TSTable(WORD _size) :
  162. wSize(_size),
  163. wNumUsed((WORD) 0),
  164. wFirstFree((WORD) 0),
  165. wLastFree((WORD) (_size - 1)),
  166. wUniqueID((WORD) 0),
  167. bInitialized(TRUE),
  168. pDataTable(NULL),
  169. pLockTable(NULL)
  170. {
  171. WORD wIndex;
  172. // Create the table lock
  173. InitializeCriticalSection(&csTableLock);
  174. // Lock the table
  175. LockTable();
  176. // Create the data table
  177. pDataTable = new EntryData*[wSize];
  178. if(pDataTable == NULL)
  179. {
  180. bInitialized = FALSE;
  181. return;
  182. }
  183. // Init the pointers
  184. for (wIndex = 0; wIndex < wSize; wIndex++)
  185. {
  186. pDataTable[wIndex] = NULL;
  187. }
  188. // Create the lock table
  189. #if defined(DBG) && defined(ENABLE_BOGUS_ENTRY)
  190. pLockTable = new LOCK_ENTRY[wSize+1];
  191. #else
  192. pLockTable = new LOCK_ENTRY[wSize];
  193. #endif
  194. if (pLockTable == NULL)
  195. {
  196. bInitialized = FALSE;
  197. return;
  198. }
  199. // Initialize the lock table entries...each entry begins with
  200. // a NULL mutex handle, a zero lock count and it's next free is
  201. // the next successive entry.
  202. for (wIndex = 0; wIndex < wSize; wIndex++ )
  203. {
  204. pLockTable[wIndex].hLock = NULL;
  205. pLockTable[wIndex].iLockCount = 0;
  206. pLockTable[wIndex].wNextFree = (WORD) (wIndex + 1);
  207. }
  208. #if defined(DBG) && defined(ENABLE_BOGUS_ENTRY)
  209. pLockTable[wSize].hLock = (HANDLE)0xBAADBAAD;
  210. pLockTable[wSize].iLockCount = 0xBAADBAAD;
  211. pLockTable[wSize].bCleanup = 0xBAADBAAD;
  212. pLockTable[wSize].bDeleted = 0xBAADBAAD;
  213. pLockTable[wSize].wNextFree = 0xBAAD;
  214. pLockTable[wSize].wUniqueID = 0xBAAD;
  215. #endif
  216. // note: the wNextFree in the last table entry points to an invalid index, however,
  217. // this is OK since if the table ever fills, it is automatically resized making what
  218. // was an invalid index, the index into the first entry of newly added part of the
  219. // enlargened table. Trust me...
  220. // Unlock the table
  221. UnLockTable();
  222. }
  223. /*
  224. ** TSTable::~TSTable
  225. *
  226. * FILENAME: c:\msdev\projects\firewalls\inc\table.h
  227. *
  228. * PARAMETERS:
  229. *
  230. * DESCRIPTION:
  231. *
  232. * RETURNS:
  233. *
  234. */
  235. template <class EntryData>
  236. TSTable<EntryData>::~TSTable()
  237. {
  238. DWORD wIndex;
  239. // Lock the table
  240. LockTable();
  241. // Delete the data table
  242. if (pDataTable != NULL)
  243. {
  244. delete pDataTable;
  245. }
  246. // Delete the lock table
  247. if (pLockTable != NULL)
  248. {
  249. // Destroy the mutexes
  250. for (wIndex = 0; wIndex < wSize; wIndex++)
  251. {
  252. if (pLockTable[wIndex].hLock != NULL)
  253. {
  254. CloseHandle(pLockTable[wIndex].hLock);
  255. }
  256. }
  257. delete pLockTable;
  258. }
  259. // Unlock the table
  260. UnLockTable();
  261. // Destroy the table lock
  262. DeleteCriticalSection(&csTableLock);
  263. bInitialized = FALSE;
  264. }
  265. /*
  266. ** TSTable::Resize
  267. *
  268. * FILENAME: c:\msdev\projects\firewalls\inc\table.h
  269. *
  270. * PARAMETERS:
  271. *
  272. * DESCRIPTION:
  273. *
  274. * RETURNS:
  275. *
  276. */
  277. template <class EntryData>
  278. BOOL TSTable<EntryData>::Resize(WORD wNewSize)
  279. {
  280. BOOL bRetCode = TRUE;
  281. EntryData** pNewDataTable;
  282. PLOCK_ENTRY pNewLockTable;
  283. WORD wIndex;
  284. // Lock the table
  285. LockTable();
  286. // If the table is shrinking, pretend we did it
  287. if (wNewSize <= wSize)
  288. {
  289. goto EXIT;
  290. }
  291. // Allocate new data and lock tables and make sure that succeeds.
  292. pNewDataTable = new EntryData*[wNewSize];
  293. if(pNewDataTable == NULL)
  294. {
  295. bRetCode = FALSE;
  296. goto EXIT;
  297. }
  298. #if defined(DBG) && defined(ENABLE_BOGUS_ENTRY)
  299. pNewLockTable = new LOCK_ENTRY[wNewSize+1];
  300. #else
  301. pNewLockTable = new LOCK_ENTRY[wNewSize];
  302. #endif
  303. if(pNewLockTable == NULL)
  304. {
  305. bRetCode = FALSE;
  306. goto CLEANUP1;
  307. }
  308. // Initialize the new section of the lock and data tables
  309. for (wIndex = wSize; wIndex < wNewSize; wIndex++)
  310. {
  311. pNewDataTable[wIndex] = NULL;
  312. pNewLockTable[wIndex].hLock = NULL;
  313. pNewLockTable[wIndex].iLockCount = 0;
  314. pNewLockTable[wIndex].wNextFree = (WORD) (wIndex + 1);
  315. }
  316. #if defined(DBG) && defined(ENABLE_BOGUS_ENTRY)
  317. pNewLockTable[wNewSize].hLock = (HANDLE)0xBAADBAAD;
  318. pNewLockTable[wNewSize].iLockCount = 0xBAADBAAD;
  319. pNewLockTable[wNewSize].bCleanup = 0xBAADBAAD;
  320. pNewLockTable[wNewSize].bDeleted = 0xBAADBAAD;
  321. pNewLockTable[wNewSize].wNextFree = 0xBAAD;
  322. pNewLockTable[wNewSize].wUniqueID = 0xBAAD;
  323. #endif // DBG
  324. // Copy the old data table pointers to the new data table
  325. memcpy((PCHAR) pNewDataTable,
  326. (PCHAR) pDataTable,
  327. sizeof(EntryData*) * wSize);
  328. // Delete the old data table and fix the pointer
  329. delete pDataTable;
  330. pDataTable = pNewDataTable;
  331. // Copy the old lock table to the new lock table
  332. memcpy((PCHAR) pNewLockTable,
  333. (PCHAR) pLockTable,
  334. sizeof(LOCK_ENTRY) * wSize);
  335. // Delete the old lock table and fix the pointer
  336. delete pLockTable;
  337. pLockTable = pNewLockTable;
  338. // Fix the size variable
  339. wSize = wNewSize;
  340. // Fix the last free index
  341. wLastFree = wSize - 1;
  342. goto EXIT;
  343. CLEANUP1:
  344. // Delete the new data table
  345. delete pNewDataTable;
  346. EXIT:
  347. // Unlock the table
  348. UnLockTable();
  349. return bRetCode;
  350. }
  351. /*
  352. ** TSTable::CreateAndLock
  353. *
  354. * FILENAME: c:\msdev\projects\firewalls\inc\table.h
  355. *
  356. * PARAMETERS:
  357. *
  358. * DESCRIPTION:
  359. *
  360. * RETURNS:
  361. *
  362. */
  363. template <class EntryData>
  364. BOOL TSTable<EntryData>::CreateAndLock(EntryData* pEntryData,
  365. LPDWORD lpdwID)
  366. {
  367. BOOL bRetCode = FALSE;
  368. WORD wIndex;
  369. // If the pointer passed in is bad, then don't even try to do anything for them
  370. if (pEntryData == NULL || lpdwID == NULL)
  371. {
  372. goto EXIT;
  373. }
  374. // Lock the table
  375. LockTable();
  376. // If the table is full, then resize it.
  377. if (wNumUsed == wSize)
  378. {
  379. if (Resize((WORD) (wSize + 20)) == FALSE)
  380. {
  381. goto EXIT;
  382. }
  383. }
  384. // Get the first free entry
  385. wIndex = wFirstFree;
  386. // Create the mutex for the object
  387. if ((pLockTable[wIndex].hLock = CreateMutexA(NULL, FALSE, NULL)) == NULL)
  388. {
  389. goto EXIT;
  390. }
  391. // Lock the entry (no need checking the return code as the entire
  392. // table is locked) - since this is a new entry, that means that nobody
  393. // could have locked the entry already.
  394. LockEntry(wIndex, 0);
  395. // Copy pointer to the data table
  396. pDataTable[wIndex] = pEntryData;
  397. // Init the corresponding lock table entry
  398. pLockTable[wIndex].bDeleted = FALSE;
  399. pLockTable[wIndex].iLockCount = 1;
  400. pLockTable[wIndex].wUniqueID = GenerateUniqueID();
  401. // Set the id for the caller
  402. *lpdwID = MakeID(wIndex, pLockTable[wIndex].wUniqueID);
  403. // Bump up the count of number used
  404. wNumUsed++;
  405. // Fix the next free index
  406. wFirstFree = pLockTable[wIndex].wNextFree;
  407. // Fix the last free index
  408. if (wIndex == wLastFree)
  409. {
  410. wLastFree = wFirstFree;
  411. }
  412. // Signal success
  413. bRetCode = TRUE;
  414. EXIT:
  415. // Unlock the table
  416. UnLockTable();
  417. return bRetCode;
  418. }
  419. /*
  420. ** TSTable::Lock
  421. *
  422. * FILENAME: c:\msdev\projects\firewalls\inc\table.h
  423. *
  424. * PARAMETERS:
  425. *
  426. * DESCRIPTION:
  427. *
  428. * RETURNS:
  429. *
  430. */
  431. template <class EntryData>
  432. EntryData* TSTable<EntryData>::Lock(DWORD dwID,
  433. DWORD timeout)
  434. {
  435. EntryData* pEntryData = NULL;
  436. WORD wIndex,
  437. wUID;
  438. BreakID(dwID, &wIndex, &wUID);
  439. // Lock the table
  440. LockTable();
  441. // Verify the index is within bounds
  442. if (wIndex >= wSize)
  443. {
  444. goto EXIT;
  445. }
  446. // Verify that the entry is actually valid (ie the lock in non-NULL,
  447. // the object status is valid, and the unique ID matches).
  448. if (pLockTable[wIndex].hLock == NULL ||
  449. pLockTable[wIndex].bDeleted == TRUE ||
  450. pLockTable[wIndex].wUniqueID != wUID)
  451. {
  452. goto EXIT;
  453. }
  454. // If the timeout is INFINITE, then try to lock the entry using a more
  455. // "thread friendly" method. If a timeout is specified, then don't do
  456. // the spin lock since it could be implemented at a higher level.
  457. if(timeout == INFINITE)
  458. {
  459. // simulate infinity with a pseudo "spin lock"
  460. // This is more "thread friendly" in that it unlocks the table allowing some
  461. // other thread that is trying to unlock the same entry to be able to lock the
  462. // table.
  463. while(LockEntry(wIndex, 0) == FALSE)
  464. {
  465. UnLockTable();
  466. // give up the rest of this thread quantum, allowing others to run and potentially
  467. // unlock the entry
  468. Sleep(0);
  469. LockTable();
  470. // If the entry has been replaced, deleted or marked for deletion then
  471. // bag it (give up)
  472. if((pLockTable[wIndex].wUniqueID != wUID) ||
  473. (pLockTable[wIndex].hLock == NULL) ||
  474. (pLockTable[wIndex].bDeleted == TRUE))
  475. {
  476. goto EXIT;
  477. }
  478. }
  479. // we got the lock
  480. pEntryData = pDataTable[wIndex];
  481. }
  482. // Otherwise, do a normal lock
  483. else
  484. {
  485. if (LockEntry(wIndex, timeout) == TRUE)
  486. {
  487. pEntryData = pDataTable[wIndex];
  488. }
  489. }
  490. EXIT:
  491. // Unlock the table
  492. UnLockTable();
  493. return pEntryData;
  494. }
  495. /*
  496. ** TSTable::Unlock
  497. *
  498. * FILENAME: c:\msdev\projects\firewalls\inc\table.h
  499. *
  500. * PARAMETERS:
  501. *
  502. * DESCRIPTION:
  503. *
  504. * RETURNS:
  505. *
  506. */
  507. template <class EntryData>
  508. BOOL TSTable<EntryData>::Unlock(DWORD dwID)
  509. {
  510. BOOL bRetCode = TRUE;
  511. WORD wIndex,
  512. wUID;
  513. BreakID(dwID, &wIndex, &wUID);
  514. // Lock the table
  515. LockTable();
  516. // Verify the id is within bounds
  517. if (wIndex >= wSize)
  518. {
  519. bRetCode = FALSE;
  520. goto EXIT;
  521. }
  522. // verify that the UID matches
  523. if (pLockTable[wIndex].wUniqueID != wUID)
  524. {
  525. bRetCode = FALSE;
  526. goto EXIT;
  527. }
  528. // Verify that the lock is actually valid and that the entry has not been
  529. // deleted
  530. if (pLockTable[wIndex].hLock == NULL)
  531. {
  532. goto EXIT;
  533. }
  534. // Make sure that that thread has the lock on the entry
  535. if ((bRetCode = LockEntry(wIndex, 0)) == TRUE)
  536. {
  537. // if this table entry is marked for delete and the lock count is less than 2
  538. // (since the thread could have called delete after unlocking the entry...although
  539. // this is a no-no) then clean up the table entry
  540. if (pLockTable[wIndex].bDeleted == TRUE &&
  541. pLockTable[wIndex].iLockCount <= 2)
  542. {
  543. // If the caller specifed cleanup on delete, then get rid of memory
  544. if (pLockTable[wIndex].bCleanup == TRUE)
  545. {
  546. delete pDataTable[wIndex];
  547. }
  548. // Set the pointer to NULL
  549. pDataTable[wIndex] = NULL;
  550. // See if table is full
  551. if (wNumUsed == wSize) {
  552. // Fix the entry so that it's next free index points to end of
  553. // table. No need to update last entry since it was virtual.
  554. pLockTable[wIndex].wNextFree = wLastFree;
  555. wFirstFree = wIndex;
  556. wLastFree = wIndex;
  557. } else {
  558. // Fix the entry so that it's next free index is what is currently
  559. // the next free pointed to by the current last free entry.
  560. // Then update the last free entry's next pointer, and finally,
  561. // update the last free index to this entry
  562. pLockTable[wIndex].wNextFree = pLockTable[wLastFree].wNextFree;
  563. pLockTable[wLastFree].wNextFree = wIndex;
  564. wLastFree = wIndex;
  565. }
  566. // Decrement the count of used entries
  567. wNumUsed--;
  568. }
  569. // Do two unlocks on the entry ... one for the original lock and another for
  570. // the lock we obtained during the test
  571. UnLockEntry(wIndex);
  572. UnLockEntry(wIndex);
  573. // Since the entire table is locked, then we can get away with this. If
  574. // the code is ever changed so that the entire table is not locked during
  575. // these operations, then this will cause a race condition.
  576. // If we got rid of the data, then close the handle to the mutex and
  577. // set the handle to NULL
  578. if (pDataTable[wIndex] == NULL)
  579. {
  580. CloseHandle(pLockTable[wIndex].hLock);
  581. pLockTable[wIndex].hLock = NULL;
  582. }
  583. }
  584. EXIT:
  585. // Unlock the table
  586. UnLockTable();
  587. return bRetCode;
  588. }
  589. /*
  590. ** TSTable::Delete
  591. *
  592. * FILENAME: c:\msdev\projects\firewalls\inc\table.h
  593. *
  594. * PARAMETERS:
  595. *
  596. * DESCRIPTION:
  597. *
  598. * RETURNS:
  599. *
  600. */
  601. template <class EntryData>
  602. BOOL TSTable<EntryData>::Delete(DWORD dwID,
  603. BOOL bCleanup)
  604. {
  605. BOOL bRetCode = TRUE;
  606. WORD wIndex,
  607. wUID;
  608. BreakID(dwID, &wIndex, &wUID);
  609. // Lock the table
  610. LockTable();
  611. // Verify that the ID is within bounds
  612. if (wIndex >= wSize)
  613. {
  614. bRetCode = FALSE;
  615. goto EXIT;
  616. }
  617. // verify that the UID matches
  618. if (pLockTable[wIndex].wUniqueID != wUID)
  619. {
  620. bRetCode = FALSE;
  621. goto EXIT;
  622. }
  623. // Verify that the entry is valid
  624. if (pDataTable[wIndex] == NULL)
  625. {
  626. bRetCode = FALSE;
  627. goto EXIT;
  628. }
  629. // Try to lock the entry (ie check to see if we had the entry locked)
  630. if (LockEntry(wIndex, 0) == TRUE)
  631. {
  632. // mark it for deletion, set the cleanp flag and then unlock it
  633. pLockTable[wIndex].bDeleted = TRUE;
  634. pLockTable[wIndex].bCleanup = bCleanup;
  635. UnLockEntry(wIndex);
  636. // Note: this function does not call ::Unlock() on behalf of the user.
  637. // Thus, the entry is only marked as deleted at this point and can no
  638. // longer be locked by any threads (including the one that marked it for delete).
  639. // The thread that marked the entry as deleted must call ::Unlock() to actually
  640. // free up the entry.
  641. }
  642. EXIT:
  643. // Unlock the table
  644. UnLockTable();
  645. return bRetCode;
  646. }
  647. /*
  648. ** TSTable::Lock
  649. *
  650. * FILENAME: c:\msdev\projects\firewalls\inc\table.h
  651. *
  652. * PARAMETERS:
  653. *
  654. * DESCRIPTION: Validates that an object still exists. Can be called
  655. * regardless if caller has entry locked or not.
  656. *
  657. * RETURNS:
  658. *
  659. */
  660. template <class EntryData>
  661. BOOL TSTable<EntryData>::Validate(DWORD dwID)
  662. {
  663. BOOL bRetCode = TRUE;
  664. WORD wIndex,
  665. wUID;
  666. BreakID(dwID, &wIndex, &wUID);
  667. // Lock the table
  668. LockTable();
  669. // Verify the index is within bounds
  670. if (wIndex >= wSize)
  671. {
  672. bRetCode = FALSE;
  673. goto EXIT;
  674. }
  675. // Verify that the entry is actually valid (ie the lock in non-NULL,
  676. // the object status is valid, the unique ID matches, and the data ptr is not null).
  677. if (pLockTable[wIndex].hLock == NULL ||
  678. pLockTable[wIndex].bDeleted == TRUE ||
  679. pLockTable[wIndex].wUniqueID != wUID ||
  680. pDataTable[wIndex] == NULL)
  681. {
  682. bRetCode = FALSE;
  683. goto EXIT;
  684. }
  685. EXIT:
  686. // Unlock the table
  687. UnLockTable();
  688. return bRetCode;
  689. }
  690. /*
  691. ** TSTable::EnumerateEntries
  692. *
  693. * FILENAME: c:\msdev\projects\firewalls\inc\table.h
  694. *
  695. * PARAMETERS:
  696. *
  697. * DESCRIPTION:
  698. *
  699. * RETURNS:
  700. *
  701. */
  702. template <class EntryData>
  703. EntryData* TSTable<EntryData>::EnumerateEntries(TABLE_CALLBACK callbackFunc,
  704. LPVOID context,
  705. BOOL bUnlockTable)
  706. {
  707. DWORD dwAction;
  708. WORD wIndex = wSize;
  709. EntryData* pEntryData = NULL;
  710. DWORD dwEntryID;
  711. // Make sure they passed a good function
  712. if (callbackFunc == NULL)
  713. {
  714. goto EXIT;
  715. }
  716. // Lock the table
  717. LockTable();
  718. // Run through the data table and pass the data to the callback function
  719. for (wIndex = 0; wIndex < wSize; wIndex++)
  720. {
  721. // Verify that there is actually data in the entry and that the entry has not
  722. // been marked for deletion.
  723. if (pDataTable[wIndex] == NULL ||
  724. pLockTable[wIndex].bDeleted == TRUE)
  725. {
  726. continue;
  727. }
  728. // Try to lock the entry...if we cannot, then we don't have the lock and
  729. // we will only report entries that we have locked (or are unlocked)
  730. if (LockEntry(wIndex, 0) == FALSE)
  731. {
  732. continue;
  733. }
  734. // build and remember the "full" entry ID so we can use it to unlock the entry
  735. dwEntryID = MakeID(wIndex, pLockTable[wIndex].wUniqueID);
  736. // Save the pointer to the object.
  737. pEntryData = pDataTable[wIndex];
  738. // note: only unlock the table during the callback if we are explicitly asked to (the
  739. // default is not to unlock the table).
  740. if(bUnlockTable == TRUE)
  741. UnLockTable();
  742. // Call their function
  743. dwAction = callbackFunc(pDataTable[wIndex], context);
  744. if(bUnlockTable == TRUE)
  745. LockTable();
  746. // If the action says to delete the entry, then do so...if we are also to delete
  747. // the object, pass in a TRUE.
  748. if (dwAction == CALLBACK_DELETE_ENTRY ||
  749. dwAction == CALLBACK_DELETE_ENTRY_AND_OBJECT)
  750. {
  751. Delete(dwEntryID, (dwAction == CALLBACK_DELETE_ENTRY ? FALSE : TRUE));
  752. }
  753. // If the action says abort, then break the loop...notice that means that
  754. // the entry is still locked
  755. else if (dwAction == CALLBACK_ABORT)
  756. {
  757. goto EXIT;
  758. }
  759. // Unlock the entry...notice we don't use UnLockEntry. The reason is that
  760. // if the entry has been marked as deleted, then we need to have
  761. // it destroyed and UnLockEntry doesn't do that.
  762. Unlock(dwEntryID);
  763. }
  764. EXIT:
  765. // Unlock the table
  766. UnLockTable();
  767. // Return NULL if we processed the entire table...if we were told to abort,
  768. // return a pointer to the entry we stopped on.
  769. return (wIndex == wSize ? NULL : pEntryData);
  770. }
  771. // helper functions - these assume table is locked and index is good
  772. /*
  773. ** TSTable::LockEntry
  774. *
  775. * FILENAME: c:\msdev\projects\firewalls\inc\table.h
  776. *
  777. * PARAMETERS:
  778. *
  779. * DESCRIPTION:
  780. *
  781. * RETURNS:
  782. *
  783. */
  784. template <class EntryData>
  785. BOOL TSTable<EntryData>::LockEntry(WORD wIndex,
  786. DWORD timeout)
  787. {
  788. BOOL bRetCode = TRUE;
  789. DWORD dwRetCode;
  790. // Try to lock the entry. If it succeeds, we'll bump up the lock count. If
  791. // the wait ended because another thread abandoned the mutex, then set the count
  792. // to one.
  793. dwRetCode = WaitForSingleObject(pLockTable[wIndex].hLock, timeout);
  794. if (dwRetCode == WAIT_OBJECT_0)
  795. {
  796. pLockTable[wIndex].iLockCount++;
  797. }
  798. else if (dwRetCode == WAIT_ABANDONED)
  799. {
  800. pLockTable[wIndex].iLockCount = 1;
  801. }
  802. else
  803. {
  804. bRetCode = FALSE;
  805. }
  806. return bRetCode;
  807. }
  808. /*
  809. ** TSTable::UnLockEntry
  810. *
  811. * FILENAME: c:\msdev\projects\firewalls\inc\table.h
  812. *
  813. * PARAMETERS:
  814. *
  815. * DESCRIPTION:
  816. *
  817. * RETURNS:
  818. *
  819. */
  820. template <class EntryData>
  821. BOOL TSTable<EntryData>::UnLockEntry(WORD wIndex)
  822. {
  823. BOOL bRetCode;
  824. // Release the mutex...if that succeeds, reduce the count
  825. if((bRetCode = ReleaseMutex(pLockTable[wIndex].hLock)) == TRUE)
  826. {
  827. pLockTable[wIndex].iLockCount--;
  828. }
  829. return bRetCode;
  830. }
  831. /*
  832. ** TSTable::GenerateUniqueID
  833. *
  834. * FILENAME: c:\msdev\projects\firewalls\inc\table.h
  835. *
  836. * PARAMETERS:
  837. *
  838. * DESCRIPTION: table should be locked before calling this function.
  839. *
  840. * RETURNS:
  841. *
  842. */
  843. template <class EntryData>
  844. WORD TSTable<EntryData>::GenerateUniqueID()
  845. {
  846. // table must be locked
  847. if(++wUniqueID == TSTABLE_INVALID_UNIQUE_ID)
  848. wUniqueID++;
  849. return(wUniqueID);
  850. }
  851. #if defined(DBG) && defined(ENABLE_DUMP_ENTRIES)
  852. /*
  853. ** TSTable::DumpEntries
  854. *
  855. * FILENAME: c:\msdev\projects\firewalls\inc\table.h
  856. *
  857. * PARAMETERS:
  858. *
  859. * DESCRIPTION:
  860. *
  861. * RETURNS:
  862. *
  863. */
  864. template <class EntryData>
  865. VOID TSTable<EntryData>::DumpEntries()
  866. {
  867. WORD wIndex;
  868. WORD wNumFree;
  869. // Lock the table
  870. LockTable();
  871. #ifdef ENABLE_DUMP_ENTRIES_VERBOSE
  872. for (wIndex = 0; wIndex < wSize; wIndex++)
  873. {
  874. if (pLockTable[wIndex].hLock == NULL) {
  875. TSDbgPrint("[Entry %d] - FREE"
  876. "\n\thLock = %x"
  877. "\n\tiLockCount = %d"
  878. "\n\tbCleanup = %s"
  879. "\n\tbDeleted = %s"
  880. "\n\twNextFree = %d"
  881. "\n\tpEntryData = 0x%08lx\n",
  882. wIndex,
  883. pLockTable[wIndex].hLock,
  884. pLockTable[wIndex].iLockCount,
  885. pLockTable[wIndex].bCleanup ? "TRUE" : "FALSE",
  886. pLockTable[wIndex].bDeleted ? "TRUE" : "FALSE",
  887. pLockTable[wIndex].wNextFree,
  888. pDataTable[wIndex]
  889. );
  890. } else if (LockEntry(wIndex, 0) == TRUE) {
  891. TSDbgPrint("[Entry %d] - USED"
  892. "\n\thLock = %x"
  893. "\n\tiLockCount = %d"
  894. "\n\tbCleanup = %s"
  895. "\n\tbDeleted = %s"
  896. "\n\twNextFree = %d"
  897. "\n\tpEntryData = 0x%08lx\n",
  898. wIndex,
  899. pLockTable[wIndex].hLock,
  900. pLockTable[wIndex].iLockCount,
  901. pLockTable[wIndex].bCleanup ? "TRUE" : "FALSE",
  902. pLockTable[wIndex].bDeleted ? "TRUE" : "FALSE",
  903. pLockTable[wIndex].wNextFree,
  904. pDataTable[wIndex]
  905. );
  906. UnLockEntry(wIndex);
  907. } else {
  908. TSDbgPrint("[Entry %d] - LOCKED\n",wIndex);
  909. }
  910. }
  911. #endif
  912. TSDbgPrint("[Free List] - "
  913. "wFirstFree=%d,"
  914. "wLastFree=%d\n",
  915. wFirstFree,
  916. wLastFree
  917. );
  918. wIndex = wFirstFree;
  919. wNumFree = (wFirstFree < wSize) ? 1 : 0;
  920. while (wIndex != wLastFree) {
  921. TSDbgPrint("\t%d -> %d\n",wIndex,pLockTable[wIndex].wNextFree);
  922. wIndex = pLockTable[wIndex].wNextFree;
  923. wNumFree++;
  924. }
  925. TSDbgPrint("[Summary] - "
  926. "wSize=%d,"
  927. "wNumUsed=%d,"
  928. "wNumFree=%d %s\n\n",
  929. wSize,
  930. wNumUsed,
  931. wNumFree,
  932. ((wSize - wNumUsed) != wNumFree)
  933. ? "ERROR"
  934. : "OKAY"
  935. );
  936. // Unlock the table
  937. UnLockTable();
  938. }
  939. #endif
  940. #endif