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.

933 lines
22 KiB

  1. /*****************************************************************************\
  2. * MODULE: cachemgr.cxx
  3. *
  4. * The module contains routines to implement the caching algorithm for
  5. * the printers provider
  6. *
  7. * Purpose:
  8. *
  9. * Description:
  10. *
  11. * The Caching algorithm operates based on a state machine. There are five
  12. * states in the cache:
  13. *
  14. * CACHE_STATE_INIT
  15. * CACHE_STATE_ACCESSED_VALID,
  16. * CACHE_STATE_DATA_VALID,
  17. * CACHE_STATE_ACCESSED_VALID_AGAIN,
  18. * CACHE_STATE_NOT_ACCESSED_VALID_AGAIN
  19. *
  20. * CACHE_STATE_INIT is the initial state. Once the first cache hit
  21. * comes in, the cahce manager calles FetchData to fetch the data
  22. * and goes into CACHE_STATE_ACCESSED_VALID state.
  23. *
  24. * In CACHE_STATE_ACCESSED_VALID state, the cache manager waits
  25. * for the minimum cache timeout and go to CACHE_STATE_DATA_VALID
  26. *
  27. * In CACHE_STATE_DATA_VALID state, the cache manager waits for
  28. * another cache hit withing half of the last fetch time.
  29. *
  30. * If there is a hit during this waiting, the cache manager will go
  31. * for another fetch and go to CACHE_STATE_ACCESSED_VALID state.
  32. *
  33. * If there is no hit during the waiting period, the cache manager
  34. * waits for another timeout or another cache hit.
  35. *
  36. * If there is no access during the waiting, the cache manager
  37. * invalidates the cache. Otherwise, the cache manager go out and
  38. * do anther data fetch and then go to CACHE_STATE_ACCESSED_VALID.
  39. *
  40. *
  41. *
  42. * Copyright (C) 1998-1999 Microsoft Corporation
  43. *
  44. * History:
  45. * 10/16/98 weihaic Created
  46. *
  47. \*****************************************************************************/
  48. #include "precomp.h"
  49. #include "priv.h"
  50. extern BOOL _ppinfo_net_get_info(
  51. IN PCINETMONPORT pIniPort,
  52. OUT PPRINTER_INFO_2 *ppInfo,
  53. OUT LPDWORD lpBufAllocated,
  54. IN ALLOCATORFN pAllocator);
  55. extern BOOL ppjob_EnumForCache(
  56. IN PCINETMONPORT pIniPort,
  57. OUT LPPPJOB_ENUM *ppje);
  58. // cdwMaxCacheValidTime is the maximum expire time for the current cache
  59. // Idealy, we should put a large number to increase the effiency of the cache
  60. // so we choose 30 seconds (30*1000) as the final number. For testing purpose,
  61. // we put 15 seconds to increase the hit of the fetch data code
  62. //
  63. // weihaic 10/23/98
  64. //
  65. const DWORD cdwMaxCacheValidTime = 30*1000; // The cache content will expire after 30 seconds.
  66. const DWORD cdwMinCacheValidTime = 2*1000; // The cache content will be valid for at least 2 seconds
  67. CacheMgr::CacheMgr ():
  68. m_dwState (CACHE_STATE_INIT),
  69. m_pIniPort (NULL),
  70. m_pData (NULL),
  71. m_hDataReadyEvent (NULL),
  72. m_hHitEvent (NULL),
  73. m_hInvalidateCacheEvent (NULL),
  74. m_hThread (NULL),
  75. m_bCacheStopped (FALSE),
  76. m_bAccessed (FALSE),
  77. m_bInvalidateFlag (FALSE),
  78. m_bValid (FALSE)
  79. {
  80. if ((m_hDataReadyEvent = CreateEvent (NULL, TRUE, FALSE, NULL)) &&
  81. (m_hHitEvent = CreateEvent (NULL, FALSE, FALSE, NULL)) &&
  82. (m_hInvalidateCacheEvent = CreateEvent (NULL, FALSE, FALSE, NULL)) )
  83. m_bValid = TRUE;
  84. }
  85. CacheMgr::~CacheMgr ()
  86. {
  87. }
  88. VOID
  89. CacheMgr::Shutdown ()
  90. {
  91. CacheRead.Lock ();
  92. // No more read is possible
  93. m_bCacheStopped = TRUE;
  94. if (m_hThread) {
  95. SetEvent (m_hInvalidateCacheEvent);
  96. // Wait for another thread to exit
  97. WaitForSingleObject (m_hThread, INFINITE);
  98. }
  99. if (m_hDataReadyEvent) {
  100. CloseHandle (m_hDataReadyEvent);
  101. }
  102. if (m_hHitEvent) {
  103. CloseHandle (m_hHitEvent);
  104. }
  105. if (m_hInvalidateCacheEvent) {
  106. CloseHandle (m_hInvalidateCacheEvent);
  107. }
  108. m_bValid = FALSE;
  109. CacheRead.Unlock ();
  110. delete this;
  111. }
  112. BOOL
  113. CacheMgr::SetupAsyncFetch (
  114. PCINETMONPORT pIniPort)
  115. {
  116. BOOL bRet = FALSE;
  117. PTHREADCONTEXT pThreadData = new THREADCONTEXT;
  118. if (pThreadData) {
  119. pThreadData->pIniPort = pIniPort;
  120. pThreadData->pCache = this;
  121. #ifdef WINNT32
  122. pThreadData->pSidToken = new CSid;
  123. if (pThreadData->pSidToken && pThreadData->pSidToken->bValid()) {
  124. if (m_hThread = CreateThread (NULL, COMMITTED_STACK_SIZE, (LPTHREAD_START_ROUTINE)CacheMgr::WorkingThread,
  125. (PVOID) pThreadData, 0, NULL)) {
  126. bRet = TRUE;
  127. }
  128. }
  129. #else
  130. // This parameter can not be deleted since CreateThread() in Win9X requires
  131. // a non-NULL pointer to a DWORD as the last parameter.
  132. DWORD dwThreadId;
  133. if (m_hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)CacheMgr::WorkingThread,
  134. (PVOID) pThreadData, 0, &dwThreadId)) {
  135. bRet = TRUE;
  136. }
  137. #endif
  138. if (!bRet) {
  139. #ifdef WINNT32
  140. if (pThreadData->pSidToken) {
  141. delete pThreadData->pSidToken;
  142. }
  143. #endif
  144. delete (pThreadData);
  145. }
  146. }
  147. return bRet;
  148. }
  149. VOID
  150. CacheMgr::TransitState (
  151. PCINETMONPORT pIniPort)
  152. {
  153. PVOID pData = NULL;
  154. DWORD dwFetchTime = 0;
  155. CACHESTATE dwState, dwOldState;
  156. BOOL bNewData;
  157. HANDLE hHandles[2];
  158. hHandles [0] = m_hHitEvent;
  159. hHandles [1] = m_hInvalidateCacheEvent;
  160. dwState = m_dwState;
  161. do {
  162. DBGMSGT (DBG_CACHE_TRACE, ( TEXT ("TransitState: current state %d"), m_dwState));
  163. dwState = m_dwState;
  164. bNewData = FALSE;
  165. m_bAccessed = FALSE;
  166. switch (dwState) {
  167. case CACHE_STATE_INIT:
  168. // Clean the data ready event
  169. ResetEvent (m_hDataReadyEvent);
  170. if (GetFetchTime (pIniPort, &dwFetchTime, &pData)) {
  171. bNewData = TRUE;
  172. dwState = CACHE_STATE_ACCESSED_VALID;
  173. }
  174. else {
  175. //Invalid Cache Content
  176. DBGMSGT (DBG_CACHE_ERROR, ( TEXT ("TransitState: FatalError %d"), GetLastError));
  177. // Invalidate the cache content, so that when the next get comes, it will
  178. // get the NULL pointer.
  179. pData = NULL;
  180. bNewData = TRUE;
  181. dwState = CACHE_STATE_ACCESSED_VALID;
  182. }
  183. break;
  184. case CACHE_STATE_ACCESSED_VALID:
  185. WaitForSingleObject (m_hInvalidateCacheEvent, cdwMinCacheValidTime);
  186. dwState = CACHE_STATE_DATA_VALID;
  187. break;
  188. case CACHE_STATE_DATA_VALID:
  189. WaitForSingleObject (m_hInvalidateCacheEvent, dwFetchTime / 2);
  190. if (m_bAccessed) {
  191. // The cache has been accessed during the waiting time
  192. dwState = CACHE_STATE_ACCESSED_VALID_AGAIN;
  193. }
  194. else {
  195. // The cache has not been accessed during the waiting time
  196. dwState = CACHE_STATE_NOT_ACCESSED_VALID_AGAIN;
  197. }
  198. break;
  199. case CACHE_STATE_ACCESSED_VALID_AGAIN:
  200. if (GetFetchTime (pIniPort, &dwFetchTime, &pData)) {
  201. bNewData = TRUE;
  202. dwState = CACHE_STATE_ACCESSED_VALID;
  203. }
  204. else {
  205. //Invalid Cache Content
  206. DBGMSGT (DBG_CACHE_ERROR, ( TEXT ("TransitState: FatalError %d"), GetLastError));
  207. // Invalidate the cache content, so that when the next access to cache comes,
  208. // it will get a NULL pointer.
  209. pData = NULL;
  210. bNewData = TRUE;
  211. dwState = CACHE_STATE_ACCESSED_VALID;
  212. }
  213. break;
  214. case CACHE_STATE_NOT_ACCESSED_VALID_AGAIN:
  215. // This has to be a long wait so that the cache will be valid for an access long after
  216. // the last fetch happeen
  217. ResetEvent (m_hHitEvent);
  218. switch (WaitForMultipleObjects (2, hHandles, FALSE, cdwMaxCacheValidTime ))
  219. {
  220. case WAIT_TIMEOUT:
  221. dwState = CACHE_STATE_INIT;
  222. break;
  223. case WAIT_OBJECT_0:
  224. //Accessed
  225. if (GetFetchTime (pIniPort, &dwFetchTime, &pData)) {
  226. bNewData = TRUE;
  227. dwState = CACHE_STATE_ACCESSED_VALID;
  228. }
  229. else {
  230. //Invalid Cache Content
  231. DBGMSGT (DBG_CACHE_ERROR, ( TEXT ("TransitState: FatalError %d"), GetLastError));
  232. // Invalidate the cache content, so that when the next access to cache comes,
  233. // it will get a NULL pointer.
  234. pData = NULL;
  235. bNewData = TRUE;
  236. dwState = CACHE_STATE_ACCESSED_VALID;
  237. }
  238. break;
  239. case WAIT_OBJECT_0 + 1:
  240. dwState = CACHE_STATE_INIT;
  241. break;
  242. default:
  243. // ERROR
  244. DBGMSGT (DBG_CACHE_ERROR, ( TEXT ("TransitState: WaitForSingleObject FatalError %d"), GetLastError));
  245. // Invalidate the cache
  246. dwState = CACHE_STATE_INIT;
  247. break;
  248. }
  249. break;
  250. default:
  251. DBGMSGT (DBG_CACHE_ERROR, (TEXT ("AsyncFech: wrong state %d"), m_dwState));
  252. // Invalidate the cache
  253. dwState = CACHE_STATE_INIT;
  254. }
  255. if (m_bCacheStopped) {
  256. // Cache is being stopped. Cleanup everything this thread generates
  257. if (bNewData) {
  258. FreeBuffer (pIniPort, pData);
  259. }
  260. // Since the caching thread is going to abort, so we need to raise
  261. // this flag so that the waiting thread can go on.
  262. SetEvent (m_hDataReadyEvent);
  263. break;
  264. }
  265. dwOldState = m_dwState;
  266. SetState (pIniPort, dwState, bNewData, pData);
  267. if (dwOldState == CACHE_STATE_INIT) {
  268. SetEvent (m_hDataReadyEvent);
  269. }
  270. if (m_bInvalidateFlag) {
  271. // Another thread called invalidate thread and hope get rid of the thread
  272. m_dwState = CACHE_STATE_INIT;
  273. }
  274. } while ( m_dwState != CACHE_STATE_INIT );
  275. // Terminate the async fetch thread
  276. HANDLE hThread = m_hThread;
  277. m_hThread = NULL;
  278. CloseHandle (hThread);
  279. DBGMSGT (DBG_CACHE_TRACE, (TEXT ("CacheMgr::TransitState: Async thread quit")));
  280. return;
  281. }
  282. VOID
  283. CacheMgr::SetState (
  284. PCINETMONPORT pIniPort,
  285. CACHESTATE dwState,
  286. BOOL bNewData,
  287. PVOID pNewData)
  288. {
  289. PVOID pOldData = NULL;
  290. m_bAccessed = 0;
  291. if (bNewData) {
  292. CacheData.Lock ();
  293. pOldData = m_pData;
  294. m_pData = pNewData;
  295. CacheData.Unlock ();
  296. }
  297. // This line must be here, since otherwise, the state is updated to the new one
  298. // but the data are not
  299. //
  300. m_dwState = dwState;
  301. if (pOldData) {
  302. FreeBuffer (pIniPort, pOldData);
  303. }
  304. }
  305. VOID
  306. CacheMgr::WorkingThread (
  307. PTHREADCONTEXT pThreadData)
  308. {
  309. CacheMgr *pThis = pThreadData->pCache;
  310. PCINETMONPORT pIniPort = pThreadData->pIniPort;
  311. #ifdef WINNT32
  312. pThreadData->pSidToken->SetCurrentSid ();
  313. delete pThreadData->pSidToken;
  314. pThreadData->pSidToken = NULL;
  315. #endif
  316. delete pThreadData;
  317. pThis->TransitState (pIniPort);
  318. }
  319. BOOL
  320. CacheMgr::GetFetchTime (
  321. PCINETMONPORT pIniPort,
  322. LPDWORD pdwTime,
  323. PVOID *ppData)
  324. {
  325. BOOL bRet = FALSE;
  326. DWORD dwT0, dwT1;
  327. dwT0 = GetTickCount();
  328. if (FetchData (pIniPort, ppData)) {
  329. bRet = TRUE;
  330. }
  331. dwT1 = GetTickCount();
  332. *pdwTime = GetTimeDiff (dwT0, dwT1);
  333. DBGMSGT (DBG_CACHE_TRACE,
  334. (TEXT ("GetFetchTime: returns %d, timediff=%d ms"),
  335. bRet, GetTimeDiff (dwT0, dwT1)));
  336. return bRet;
  337. }
  338. PVOID
  339. CacheMgr::BeginReadCache (
  340. PCINETMONPORT pIniPort)
  341. {
  342. if (m_bValid) {
  343. CacheRead.Lock ();
  344. #ifdef WINNT32
  345. CUserData CurUser;
  346. while (TRUE) {
  347. if (m_dwState == CACHE_STATE_INIT) {
  348. m_CurUser = CurUser;
  349. if (!m_hThread) {
  350. // If there is no thread running, we need to reset the dataready event
  351. ResetEvent (m_hDataReadyEvent);
  352. }
  353. if (m_hThread // There is already a thread running
  354. || SetupAsyncFetch (pIniPort)) {
  355. // We must leave the critical section since it might take forever to
  356. // get the information at the first time
  357. CacheRead.Unlock ();
  358. WaitForSingleObject (m_hDataReadyEvent, INFINITE);
  359. CacheRead.Lock ();
  360. }
  361. break;
  362. }
  363. else {
  364. if (m_CurUser == CurUser) {
  365. if (m_dwState == CACHE_STATE_NOT_ACCESSED_VALID_AGAIN) {
  366. SetEvent (m_hHitEvent);
  367. }
  368. break;
  369. }
  370. else {
  371. // We must call the internal version of InvalidateCache since
  372. // we have to leave the critical section when waiting for the termination
  373. // of the working thread.
  374. //
  375. _InvalidateCache ();
  376. // Now, the state becomes CACHE_STATE_INIT
  377. }
  378. }
  379. }
  380. #else
  381. // Win9X case, no security check
  382. while (TRUE) {
  383. if (m_dwState == CACHE_STATE_INIT) {
  384. if (!m_hThread) {
  385. // If there is no thread running, we need to reset the dataready event
  386. ResetEvent (m_hDataReadyEvent);
  387. }
  388. if (m_hThread // There is already a thread running
  389. || SetupAsyncFetch (pIniPort)) {
  390. // We must leave the critical section since it might take forever to
  391. // get the information at the first time
  392. CacheRead.Unlock ();
  393. WaitForSingleObject (m_hDataReadyEvent, INFINITE);
  394. CacheRead.Lock ();
  395. }
  396. break;
  397. }
  398. else {
  399. if (m_dwState == CACHE_STATE_NOT_ACCESSED_VALID_AGAIN) {
  400. SetEvent (m_hHitEvent);
  401. }
  402. break;
  403. }
  404. }
  405. #endif
  406. m_bAccessed = TRUE;
  407. BOOL bRet = CacheData.Lock ();
  408. DBGMSGT (DBG_CACHE_TRACE, (TEXT ("CacheData.Lock() = %d"), bRet));
  409. return m_pData;
  410. }
  411. else
  412. return NULL;
  413. }
  414. VOID
  415. CacheMgr::EndReadCache (VOID)
  416. {
  417. DBGMSGT (DBG_CACHE_TRACE,
  418. (TEXT ("CacheMgr::EndReadCache: Entered")));
  419. if (m_bValid) {
  420. BOOL bRet = CacheData.Unlock ();
  421. DBGMSGT (DBG_CACHE_TRACE, (TEXT ("CacheData.Unlock() = %d"), bRet));
  422. CacheRead.Unlock ();
  423. }
  424. }
  425. VOID
  426. CacheMgr::_InvalidateCache ()
  427. {
  428. if (!m_bInvalidateFlag) {
  429. m_bInvalidateFlag = TRUE;
  430. SetEvent (m_hInvalidateCacheEvent);
  431. }
  432. if (m_hThread) {
  433. CacheRead.Unlock ();
  434. // We must leave the critical section since we don't know how long it will take for thread to exit
  435. // Wait for another thread to exit
  436. WaitForSingleObject (m_hThread, INFINITE);
  437. CacheRead.Lock ();
  438. }
  439. // Clean up the event
  440. ResetEvent (m_hInvalidateCacheEvent);
  441. m_bInvalidateFlag = FALSE;
  442. DBGMSGT (DBG_CACHE_TRACE, ( TEXT ("CacheMgr::InvalidateCache dwState=%d"), m_dwState));
  443. }
  444. VOID
  445. CacheMgr::InvalidateCache ()
  446. {
  447. CacheRead.Lock ();
  448. _InvalidateCache ();
  449. CacheRead.Unlock ();
  450. }
  451. #if (defined(WINNT32))
  452. VOID
  453. CacheMgr::InvalidateCacheForUser(
  454. CLogonUserData *pUser )
  455. /*++
  456. Routine Description:
  457. This routine checks to see whether the given user is currently controlling the cache
  458. thread. If they are, the thread is terminated.
  459. Arguments:
  460. pUser - A pointer to the user.
  461. Return Value:
  462. None.
  463. --*/
  464. {
  465. CacheRead.Lock();
  466. if (m_CurUser == *(CUserData *)pUser) // Comparison is valid after caste
  467. _InvalidateCache ();
  468. CacheRead.Unlock();
  469. }
  470. #endif
  471. inline DWORD
  472. CacheMgr::GetTimeDiff (
  473. DWORD t0,
  474. DWORD t1)
  475. {
  476. if (t1 > t0) {
  477. return t1 - t0;
  478. }
  479. else {
  480. return DWORD(-1) - t0 + t1;
  481. }
  482. }
  483. LPVOID CacheMgr::Allocator(
  484. DWORD cb)
  485. {
  486. return new CHAR[cb];
  487. }
  488. GetPrinterCache::GetPrinterCache(
  489. PCINETMONPORT pIniPort):
  490. m_pIniPort (pIniPort)
  491. {
  492. }
  493. GetPrinterCache::~GetPrinterCache (
  494. VOID)
  495. {
  496. if (m_pData) {
  497. FreeBuffer (m_pIniPort, m_pData);
  498. }
  499. }
  500. BOOL
  501. GetPrinterCache::FetchData (
  502. PCINETMONPORT pIniPort,
  503. PVOID *ppData)
  504. {
  505. BOOL bRet = FALSE;
  506. PGETPRINTER_CACHEDATA pCacheData = NULL;
  507. DBGMSGT (DBG_CACHE_TRACE, (TEXT ("GetPrinterCache::FetchData begins")));
  508. #ifdef DEBUG
  509. if (0) {
  510. // Simulate the hanging of the current thread
  511. // For debugging purpose.
  512. MessageBox (NULL, TEXT ("GetPrinterCache::FetchData called. Press OK to continue."), TEXT ("ALERT"), MB_OK);
  513. }
  514. #endif
  515. if (pCacheData = new GETPRINTER_CACHEDATA) {
  516. semEnterCrit ();
  517. pCacheData->bRet = _ppinfo_net_get_info(pIniPort,
  518. & (pCacheData->pInfo) ,
  519. & (pCacheData->cbSize),
  520. Allocator);
  521. semLeaveCrit ();
  522. pCacheData->dwLastError = GetLastError ();
  523. DBGMSGT (DBG_CACHE_TRACE, (TEXT ("GetPrinterCache::FetchData bRet=%d, err=%d\n"),
  524. pCacheData->bRet, pCacheData->dwLastError ));
  525. //
  526. // We must return TRUE, otherwise PPGetPrinter won't get the correct last error
  527. //
  528. bRet = TRUE; //pCacheData->cbSize != 0;
  529. }
  530. if (!bRet) {
  531. DBGMSGT (DBG_CACHE_TRACE,
  532. (TEXT ("GetPrinterCache::FetchData failed, call FreeBuffer (%x, %x)"), pIniPort, pCacheData));
  533. FreeBuffer (pIniPort, pCacheData);
  534. }
  535. else {
  536. *ppData = pCacheData;
  537. }
  538. return bRet;
  539. }
  540. BOOL
  541. GetPrinterCache::FreeBuffer (
  542. PCINETMONPORT pIniPort,
  543. PVOID pData)
  544. {
  545. PGETPRINTER_CACHEDATA pCacheData = (PGETPRINTER_CACHEDATA) pData;
  546. DBGMSGT (DBG_CACHE_TRACE,
  547. (TEXT ("FreeBuffer(%x, %x) called"), pIniPort, pCacheData));
  548. if (pCacheData) {
  549. if (pCacheData->pInfo) {
  550. delete [] (PCHAR)(pCacheData->pInfo);
  551. }
  552. delete pCacheData;
  553. }
  554. return TRUE;
  555. }
  556. BOOL
  557. GetPrinterCache::BeginReadCache (
  558. PPRINTER_INFO_2 *ppInfo)
  559. {
  560. BOOL bRet = FALSE;
  561. if (m_bValid) {
  562. DBGMSGT (DBG_CACHE_TRACE,
  563. (TEXT ("GetPrinterCache::BeginReadCache: Entered")));
  564. PGETPRINTER_CACHEDATA pData = (PGETPRINTER_CACHEDATA) CacheMgr::BeginReadCache (m_pIniPort);
  565. if (pData) {
  566. if (pData->bRet) {
  567. *ppInfo = pData->pInfo;
  568. bRet = TRUE;
  569. }
  570. else {
  571. SetLastError (pData->dwLastError);
  572. }
  573. }
  574. if (!bRet && GetLastError () == ERROR_SUCCESS) {
  575. SetLastError (ERROR_CAN_NOT_COMPLETE);
  576. }
  577. DBGMSGT (DBG_CACHE_TRACE,
  578. (TEXT ("GetPrinterCache::BeginReadCache: pData = %x, return = %d, lasterror = %d"),
  579. pData, bRet, GetLastError ()));
  580. }
  581. else {
  582. SetLastError (ERROR_CAN_NOT_COMPLETE);
  583. }
  584. return bRet;
  585. }
  586. EnumJobsCache::EnumJobsCache(
  587. PCINETMONPORT pIniPort):
  588. m_pIniPort (pIniPort)
  589. {
  590. }
  591. EnumJobsCache::~EnumJobsCache (
  592. VOID)
  593. {
  594. if (m_pData) {
  595. FreeBuffer (m_pIniPort, m_pData);
  596. }
  597. }
  598. BOOL
  599. EnumJobsCache::FetchData (
  600. PCINETMONPORT pIniPort,
  601. PVOID *ppData)
  602. {
  603. BOOL bRet = FALSE;
  604. HANDLE hPort = (HANDLE)pIniPort;
  605. PENUMJOBS_CACHEDATA pCacheData = NULL;
  606. DBGMSGT (DBG_CACHE_TRACE, (TEXT ("EnumJobsCache::FetchData begins")));
  607. if (pCacheData = new ENUMJOBS_CACHEDATA) {
  608. pCacheData->pje = NULL;
  609. semEnterCrit ();
  610. pCacheData->bRet = ppjob_EnumForCache(pIniPort, & (pCacheData->pje));
  611. pCacheData->dwLastError = GetLastError ();
  612. DBGMSGT (DBG_CACHE_TRACE, (TEXT ("EnumJobsCache::FetchData bRet=%d, err=%d\n"),
  613. pCacheData->bRet, pCacheData->dwLastError ));
  614. if (pCacheData->bRet) {
  615. if (pCacheData->pje) {
  616. pCacheData->cbSize = pCacheData->pje->cbSize;
  617. }
  618. else {
  619. pCacheData->cbSize = 0;
  620. }
  621. }
  622. semLeaveCrit ();
  623. bRet = TRUE;
  624. }
  625. if (bRet) {
  626. *ppData = pCacheData;
  627. }
  628. return bRet;
  629. }
  630. BOOL
  631. EnumJobsCache::FreeBuffer (
  632. PCINETMONPORT pIniPort,
  633. PVOID pData)
  634. {
  635. PENUMJOBS_CACHEDATA pCacheData = (PENUMJOBS_CACHEDATA) pData;
  636. if (pCacheData) {
  637. if (pCacheData->pje) {
  638. // memFree has access to the global link list, so it is neccesary
  639. // to run it under critical secion.
  640. //
  641. semEnterCrit ();
  642. memFree(pCacheData->pje, memGetSize(pCacheData->pje));
  643. semLeaveCrit ();
  644. }
  645. delete pCacheData;
  646. }
  647. return TRUE;
  648. }
  649. BOOL
  650. EnumJobsCache::BeginReadCache (
  651. LPPPJOB_ENUM *ppje)
  652. {
  653. BOOL bRet = FALSE;
  654. if (m_bValid) {
  655. DBGMSGT (DBG_CACHE_TRACE,
  656. (TEXT ("EnumJobsCache::BeginReadCache: Entered")));
  657. PENUMJOBS_CACHEDATA pData = (PENUMJOBS_CACHEDATA) CacheMgr::BeginReadCache (m_pIniPort);
  658. if (pData) {
  659. if (pData->bRet) {
  660. *ppje = pData->pje;
  661. bRet = TRUE;
  662. }
  663. else {
  664. SetLastError (pData->dwLastError);
  665. }
  666. }
  667. if (!bRet && GetLastError () == ERROR_SUCCESS) {
  668. SetLastError (ERROR_CAN_NOT_COMPLETE);
  669. }
  670. DBGMSGT (DBG_CACHE_TRACE,
  671. (TEXT ("EnumJobsCache::BeginReadCache: pData = %x, return = %d, lasterror = %d"),
  672. pData, bRet, GetLastError ()));
  673. }
  674. else {
  675. SetLastError (ERROR_CAN_NOT_COMPLETE);
  676. }
  677. return bRet;
  678. }
  679. VOID
  680. EnumJobsCache::EndReadCache (
  681. VOID)
  682. {
  683. DBGMSGT (DBG_CACHE_TRACE,
  684. (TEXT ("EnumJobsCache::EndReadCache: Entered")));
  685. CacheMgr::EndReadCache ();
  686. }
  687. /*********************************************************************************
  688. ** End of File (cachemgr.cxx)
  689. *********************************************************************************/