934 lines
22 KiB
C++
934 lines
22 KiB
C++
|
/*****************************************************************************\
|
||
|
* MODULE: cachemgr.cxx
|
||
|
*
|
||
|
* The module contains routines to implement the caching algorithm for
|
||
|
* the printers provider
|
||
|
*
|
||
|
* Purpose:
|
||
|
*
|
||
|
* Description:
|
||
|
*
|
||
|
* The Caching algorithm operates based on a state machine. There are five
|
||
|
* states in the cache:
|
||
|
*
|
||
|
* CACHE_STATE_INIT
|
||
|
* CACHE_STATE_ACCESSED_VALID,
|
||
|
* CACHE_STATE_DATA_VALID,
|
||
|
* CACHE_STATE_ACCESSED_VALID_AGAIN,
|
||
|
* CACHE_STATE_NOT_ACCESSED_VALID_AGAIN
|
||
|
*
|
||
|
* CACHE_STATE_INIT is the initial state. Once the first cache hit
|
||
|
* comes in, the cahce manager calles FetchData to fetch the data
|
||
|
* and goes into CACHE_STATE_ACCESSED_VALID state.
|
||
|
*
|
||
|
* In CACHE_STATE_ACCESSED_VALID state, the cache manager waits
|
||
|
* for the minimum cache timeout and go to CACHE_STATE_DATA_VALID
|
||
|
*
|
||
|
* In CACHE_STATE_DATA_VALID state, the cache manager waits for
|
||
|
* another cache hit withing half of the last fetch time.
|
||
|
*
|
||
|
* If there is a hit during this waiting, the cache manager will go
|
||
|
* for another fetch and go to CACHE_STATE_ACCESSED_VALID state.
|
||
|
*
|
||
|
* If there is no hit during the waiting period, the cache manager
|
||
|
* waits for another timeout or another cache hit.
|
||
|
*
|
||
|
* If there is no access during the waiting, the cache manager
|
||
|
* invalidates the cache. Otherwise, the cache manager go out and
|
||
|
* do anther data fetch and then go to CACHE_STATE_ACCESSED_VALID.
|
||
|
*
|
||
|
*
|
||
|
*
|
||
|
* Copyright (C) 1998-1999 Microsoft Corporation
|
||
|
*
|
||
|
* History:
|
||
|
* 10/16/98 weihaic Created
|
||
|
*
|
||
|
\*****************************************************************************/
|
||
|
#include "precomp.h"
|
||
|
#include "priv.h"
|
||
|
|
||
|
|
||
|
extern BOOL _ppinfo_net_get_info(
|
||
|
IN PCINETMONPORT pIniPort,
|
||
|
OUT PPRINTER_INFO_2 *ppInfo,
|
||
|
OUT LPDWORD lpBufAllocated,
|
||
|
IN ALLOCATORFN pAllocator);
|
||
|
|
||
|
extern BOOL ppjob_EnumForCache(
|
||
|
IN PCINETMONPORT pIniPort,
|
||
|
OUT LPPPJOB_ENUM *ppje);
|
||
|
|
||
|
|
||
|
|
||
|
// cdwMaxCacheValidTime is the maximum expire time for the current cache
|
||
|
// Idealy, we should put a large number to increase the effiency of the cache
|
||
|
// so we choose 30 seconds (30*1000) as the final number. For testing purpose,
|
||
|
// we put 15 seconds to increase the hit of the fetch data code
|
||
|
//
|
||
|
// weihaic 10/23/98
|
||
|
//
|
||
|
const DWORD cdwMaxCacheValidTime = 30*1000; // The cache content will expire after 30 seconds.
|
||
|
const DWORD cdwMinCacheValidTime = 2*1000; // The cache content will be valid for at least 2 seconds
|
||
|
|
||
|
|
||
|
CacheMgr::CacheMgr ():
|
||
|
m_dwState (CACHE_STATE_INIT),
|
||
|
m_pIniPort (NULL),
|
||
|
m_pData (NULL),
|
||
|
m_hDataReadyEvent (NULL),
|
||
|
m_hHitEvent (NULL),
|
||
|
m_hInvalidateCacheEvent (NULL),
|
||
|
m_hThread (NULL),
|
||
|
m_bCacheStopped (FALSE),
|
||
|
m_bAccessed (FALSE),
|
||
|
m_bInvalidateFlag (FALSE),
|
||
|
m_bValid (FALSE)
|
||
|
{
|
||
|
if ((m_hDataReadyEvent = CreateEvent (NULL, TRUE, FALSE, NULL)) &&
|
||
|
(m_hHitEvent = CreateEvent (NULL, FALSE, FALSE, NULL)) &&
|
||
|
(m_hInvalidateCacheEvent = CreateEvent (NULL, FALSE, FALSE, NULL)) )
|
||
|
|
||
|
m_bValid = TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
CacheMgr::~CacheMgr ()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CacheMgr::Shutdown ()
|
||
|
{
|
||
|
CacheRead.Lock ();
|
||
|
// No more read is possible
|
||
|
|
||
|
m_bCacheStopped = TRUE;
|
||
|
if (m_hThread) {
|
||
|
|
||
|
SetEvent (m_hInvalidateCacheEvent);
|
||
|
|
||
|
// Wait for another thread to exit
|
||
|
WaitForSingleObject (m_hThread, INFINITE);
|
||
|
}
|
||
|
|
||
|
if (m_hDataReadyEvent) {
|
||
|
CloseHandle (m_hDataReadyEvent);
|
||
|
}
|
||
|
|
||
|
if (m_hHitEvent) {
|
||
|
CloseHandle (m_hHitEvent);
|
||
|
}
|
||
|
|
||
|
if (m_hInvalidateCacheEvent) {
|
||
|
CloseHandle (m_hInvalidateCacheEvent);
|
||
|
}
|
||
|
|
||
|
m_bValid = FALSE;
|
||
|
|
||
|
CacheRead.Unlock ();
|
||
|
|
||
|
delete this;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
CacheMgr::SetupAsyncFetch (
|
||
|
PCINETMONPORT pIniPort)
|
||
|
{
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
PTHREADCONTEXT pThreadData = new THREADCONTEXT;
|
||
|
|
||
|
if (pThreadData) {
|
||
|
pThreadData->pIniPort = pIniPort;
|
||
|
pThreadData->pCache = this;
|
||
|
|
||
|
#ifdef WINNT32
|
||
|
pThreadData->pSidToken = new CSid;
|
||
|
|
||
|
if (pThreadData->pSidToken && pThreadData->pSidToken->bValid()) {
|
||
|
|
||
|
if (m_hThread = CreateThread (NULL, COMMITTED_STACK_SIZE, (LPTHREAD_START_ROUTINE)CacheMgr::WorkingThread,
|
||
|
(PVOID) pThreadData, 0, NULL)) {
|
||
|
bRet = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
// This parameter can not be deleted since CreateThread() in Win9X requires
|
||
|
// a non-NULL pointer to a DWORD as the last parameter.
|
||
|
|
||
|
DWORD dwThreadId;
|
||
|
|
||
|
if (m_hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)CacheMgr::WorkingThread,
|
||
|
(PVOID) pThreadData, 0, &dwThreadId)) {
|
||
|
bRet = TRUE;
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
if (!bRet) {
|
||
|
#ifdef WINNT32
|
||
|
if (pThreadData->pSidToken) {
|
||
|
delete pThreadData->pSidToken;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
delete (pThreadData);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CacheMgr::TransitState (
|
||
|
PCINETMONPORT pIniPort)
|
||
|
{
|
||
|
PVOID pData = NULL;
|
||
|
DWORD dwFetchTime = 0;
|
||
|
CACHESTATE dwState, dwOldState;
|
||
|
BOOL bNewData;
|
||
|
HANDLE hHandles[2];
|
||
|
|
||
|
hHandles [0] = m_hHitEvent;
|
||
|
hHandles [1] = m_hInvalidateCacheEvent;
|
||
|
|
||
|
|
||
|
dwState = m_dwState;
|
||
|
|
||
|
do {
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE, ( TEXT ("TransitState: current state %d"), m_dwState));
|
||
|
|
||
|
dwState = m_dwState;
|
||
|
bNewData = FALSE;
|
||
|
m_bAccessed = FALSE;
|
||
|
|
||
|
switch (dwState) {
|
||
|
case CACHE_STATE_INIT:
|
||
|
|
||
|
// Clean the data ready event
|
||
|
ResetEvent (m_hDataReadyEvent);
|
||
|
|
||
|
if (GetFetchTime (pIniPort, &dwFetchTime, &pData)) {
|
||
|
bNewData = TRUE;
|
||
|
dwState = CACHE_STATE_ACCESSED_VALID;
|
||
|
}
|
||
|
else {
|
||
|
//Invalid Cache Content
|
||
|
DBGMSGT (DBG_CACHE_ERROR, ( TEXT ("TransitState: FatalError %d"), GetLastError));
|
||
|
|
||
|
// Invalidate the cache content, so that when the next get comes, it will
|
||
|
// get the NULL pointer.
|
||
|
pData = NULL;
|
||
|
bNewData = TRUE;
|
||
|
dwState = CACHE_STATE_ACCESSED_VALID;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case CACHE_STATE_ACCESSED_VALID:
|
||
|
|
||
|
WaitForSingleObject (m_hInvalidateCacheEvent, cdwMinCacheValidTime);
|
||
|
dwState = CACHE_STATE_DATA_VALID;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case CACHE_STATE_DATA_VALID:
|
||
|
|
||
|
|
||
|
WaitForSingleObject (m_hInvalidateCacheEvent, dwFetchTime / 2);
|
||
|
|
||
|
if (m_bAccessed) {
|
||
|
// The cache has been accessed during the waiting time
|
||
|
dwState = CACHE_STATE_ACCESSED_VALID_AGAIN;
|
||
|
}
|
||
|
else {
|
||
|
// The cache has not been accessed during the waiting time
|
||
|
dwState = CACHE_STATE_NOT_ACCESSED_VALID_AGAIN;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case CACHE_STATE_ACCESSED_VALID_AGAIN:
|
||
|
if (GetFetchTime (pIniPort, &dwFetchTime, &pData)) {
|
||
|
bNewData = TRUE;
|
||
|
dwState = CACHE_STATE_ACCESSED_VALID;
|
||
|
}
|
||
|
else {
|
||
|
//Invalid Cache Content
|
||
|
DBGMSGT (DBG_CACHE_ERROR, ( TEXT ("TransitState: FatalError %d"), GetLastError));
|
||
|
|
||
|
// Invalidate the cache content, so that when the next access to cache comes,
|
||
|
// it will get a NULL pointer.
|
||
|
pData = NULL;
|
||
|
bNewData = TRUE;
|
||
|
dwState = CACHE_STATE_ACCESSED_VALID;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case CACHE_STATE_NOT_ACCESSED_VALID_AGAIN:
|
||
|
|
||
|
// This has to be a long wait so that the cache will be valid for an access long after
|
||
|
// the last fetch happeen
|
||
|
|
||
|
|
||
|
ResetEvent (m_hHitEvent);
|
||
|
|
||
|
switch (WaitForMultipleObjects (2, hHandles, FALSE, cdwMaxCacheValidTime ))
|
||
|
{
|
||
|
case WAIT_TIMEOUT:
|
||
|
dwState = CACHE_STATE_INIT;
|
||
|
break;
|
||
|
case WAIT_OBJECT_0:
|
||
|
//Accessed
|
||
|
|
||
|
if (GetFetchTime (pIniPort, &dwFetchTime, &pData)) {
|
||
|
bNewData = TRUE;
|
||
|
dwState = CACHE_STATE_ACCESSED_VALID;
|
||
|
}
|
||
|
else {
|
||
|
//Invalid Cache Content
|
||
|
DBGMSGT (DBG_CACHE_ERROR, ( TEXT ("TransitState: FatalError %d"), GetLastError));
|
||
|
|
||
|
// Invalidate the cache content, so that when the next access to cache comes,
|
||
|
// it will get a NULL pointer.
|
||
|
pData = NULL;
|
||
|
bNewData = TRUE;
|
||
|
dwState = CACHE_STATE_ACCESSED_VALID;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WAIT_OBJECT_0 + 1:
|
||
|
|
||
|
dwState = CACHE_STATE_INIT;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
// ERROR
|
||
|
DBGMSGT (DBG_CACHE_ERROR, ( TEXT ("TransitState: WaitForSingleObject FatalError %d"), GetLastError));
|
||
|
|
||
|
// Invalidate the cache
|
||
|
dwState = CACHE_STATE_INIT;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
DBGMSGT (DBG_CACHE_ERROR, (TEXT ("AsyncFech: wrong state %d"), m_dwState));
|
||
|
// Invalidate the cache
|
||
|
dwState = CACHE_STATE_INIT;
|
||
|
}
|
||
|
|
||
|
if (m_bCacheStopped) {
|
||
|
// Cache is being stopped. Cleanup everything this thread generates
|
||
|
if (bNewData) {
|
||
|
FreeBuffer (pIniPort, pData);
|
||
|
}
|
||
|
// Since the caching thread is going to abort, so we need to raise
|
||
|
// this flag so that the waiting thread can go on.
|
||
|
SetEvent (m_hDataReadyEvent);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
dwOldState = m_dwState;
|
||
|
SetState (pIniPort, dwState, bNewData, pData);
|
||
|
|
||
|
if (dwOldState == CACHE_STATE_INIT) {
|
||
|
SetEvent (m_hDataReadyEvent);
|
||
|
}
|
||
|
|
||
|
if (m_bInvalidateFlag) {
|
||
|
// Another thread called invalidate thread and hope get rid of the thread
|
||
|
m_dwState = CACHE_STATE_INIT;
|
||
|
}
|
||
|
|
||
|
} while ( m_dwState != CACHE_STATE_INIT );
|
||
|
|
||
|
|
||
|
// Terminate the async fetch thread
|
||
|
|
||
|
HANDLE hThread = m_hThread;
|
||
|
m_hThread = NULL;
|
||
|
CloseHandle (hThread);
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE, (TEXT ("CacheMgr::TransitState: Async thread quit")));
|
||
|
|
||
|
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CacheMgr::SetState (
|
||
|
PCINETMONPORT pIniPort,
|
||
|
CACHESTATE dwState,
|
||
|
BOOL bNewData,
|
||
|
PVOID pNewData)
|
||
|
{
|
||
|
PVOID pOldData = NULL;
|
||
|
|
||
|
m_bAccessed = 0;
|
||
|
if (bNewData) {
|
||
|
CacheData.Lock ();
|
||
|
pOldData = m_pData;
|
||
|
m_pData = pNewData;
|
||
|
|
||
|
CacheData.Unlock ();
|
||
|
}
|
||
|
|
||
|
// This line must be here, since otherwise, the state is updated to the new one
|
||
|
// but the data are not
|
||
|
//
|
||
|
m_dwState = dwState;
|
||
|
|
||
|
if (pOldData) {
|
||
|
FreeBuffer (pIniPort, pOldData);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CacheMgr::WorkingThread (
|
||
|
PTHREADCONTEXT pThreadData)
|
||
|
{
|
||
|
CacheMgr *pThis = pThreadData->pCache;
|
||
|
PCINETMONPORT pIniPort = pThreadData->pIniPort;
|
||
|
|
||
|
#ifdef WINNT32
|
||
|
|
||
|
pThreadData->pSidToken->SetCurrentSid ();
|
||
|
delete pThreadData->pSidToken;
|
||
|
pThreadData->pSidToken = NULL;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
delete pThreadData;
|
||
|
|
||
|
pThis->TransitState (pIniPort);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
CacheMgr::GetFetchTime (
|
||
|
PCINETMONPORT pIniPort,
|
||
|
LPDWORD pdwTime,
|
||
|
PVOID *ppData)
|
||
|
{
|
||
|
BOOL bRet = FALSE;
|
||
|
DWORD dwT0, dwT1;
|
||
|
|
||
|
|
||
|
|
||
|
dwT0 = GetTickCount();
|
||
|
if (FetchData (pIniPort, ppData)) {
|
||
|
bRet = TRUE;
|
||
|
}
|
||
|
dwT1 = GetTickCount();
|
||
|
*pdwTime = GetTimeDiff (dwT0, dwT1);
|
||
|
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE,
|
||
|
(TEXT ("GetFetchTime: returns %d, timediff=%d ms"),
|
||
|
bRet, GetTimeDiff (dwT0, dwT1)));
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
PVOID
|
||
|
CacheMgr::BeginReadCache (
|
||
|
PCINETMONPORT pIniPort)
|
||
|
{
|
||
|
|
||
|
if (m_bValid) {
|
||
|
CacheRead.Lock ();
|
||
|
|
||
|
|
||
|
#ifdef WINNT32
|
||
|
CUserData CurUser;
|
||
|
|
||
|
while (TRUE) {
|
||
|
if (m_dwState == CACHE_STATE_INIT) {
|
||
|
|
||
|
m_CurUser = CurUser;
|
||
|
|
||
|
if (!m_hThread) {
|
||
|
// If there is no thread running, we need to reset the dataready event
|
||
|
|
||
|
ResetEvent (m_hDataReadyEvent);
|
||
|
}
|
||
|
|
||
|
if (m_hThread // There is already a thread running
|
||
|
|| SetupAsyncFetch (pIniPort)) {
|
||
|
|
||
|
// We must leave the critical section since it might take forever to
|
||
|
// get the information at the first time
|
||
|
CacheRead.Unlock ();
|
||
|
|
||
|
WaitForSingleObject (m_hDataReadyEvent, INFINITE);
|
||
|
|
||
|
CacheRead.Lock ();
|
||
|
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
if (m_CurUser == CurUser) {
|
||
|
if (m_dwState == CACHE_STATE_NOT_ACCESSED_VALID_AGAIN) {
|
||
|
SetEvent (m_hHitEvent);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
else {
|
||
|
// We must call the internal version of InvalidateCache since
|
||
|
// we have to leave the critical section when waiting for the termination
|
||
|
// of the working thread.
|
||
|
//
|
||
|
|
||
|
_InvalidateCache ();
|
||
|
// Now, the state becomes CACHE_STATE_INIT
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
// Win9X case, no security check
|
||
|
|
||
|
while (TRUE) {
|
||
|
if (m_dwState == CACHE_STATE_INIT) {
|
||
|
|
||
|
if (!m_hThread) {
|
||
|
// If there is no thread running, we need to reset the dataready event
|
||
|
|
||
|
ResetEvent (m_hDataReadyEvent);
|
||
|
}
|
||
|
|
||
|
if (m_hThread // There is already a thread running
|
||
|
|| SetupAsyncFetch (pIniPort)) {
|
||
|
|
||
|
// We must leave the critical section since it might take forever to
|
||
|
// get the information at the first time
|
||
|
CacheRead.Unlock ();
|
||
|
|
||
|
WaitForSingleObject (m_hDataReadyEvent, INFINITE);
|
||
|
|
||
|
CacheRead.Lock ();
|
||
|
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
if (m_dwState == CACHE_STATE_NOT_ACCESSED_VALID_AGAIN) {
|
||
|
SetEvent (m_hHitEvent);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
m_bAccessed = TRUE;
|
||
|
|
||
|
BOOL bRet = CacheData.Lock ();
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE, (TEXT ("CacheData.Lock() = %d"), bRet));
|
||
|
|
||
|
|
||
|
return m_pData;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CacheMgr::EndReadCache (VOID)
|
||
|
{
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE,
|
||
|
(TEXT ("CacheMgr::EndReadCache: Entered")));
|
||
|
|
||
|
|
||
|
if (m_bValid) {
|
||
|
|
||
|
BOOL bRet = CacheData.Unlock ();
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE, (TEXT ("CacheData.Unlock() = %d"), bRet));
|
||
|
|
||
|
CacheRead.Unlock ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CacheMgr::_InvalidateCache ()
|
||
|
{
|
||
|
|
||
|
if (!m_bInvalidateFlag) {
|
||
|
|
||
|
m_bInvalidateFlag = TRUE;
|
||
|
|
||
|
SetEvent (m_hInvalidateCacheEvent);
|
||
|
}
|
||
|
|
||
|
if (m_hThread) {
|
||
|
|
||
|
CacheRead.Unlock ();
|
||
|
// We must leave the critical section since we don't know how long it will take for thread to exit
|
||
|
|
||
|
// Wait for another thread to exit
|
||
|
WaitForSingleObject (m_hThread, INFINITE);
|
||
|
|
||
|
CacheRead.Lock ();
|
||
|
|
||
|
}
|
||
|
|
||
|
// Clean up the event
|
||
|
ResetEvent (m_hInvalidateCacheEvent);
|
||
|
m_bInvalidateFlag = FALSE;
|
||
|
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE, ( TEXT ("CacheMgr::InvalidateCache dwState=%d"), m_dwState));
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
CacheMgr::InvalidateCache ()
|
||
|
{
|
||
|
CacheRead.Lock ();
|
||
|
|
||
|
_InvalidateCache ();
|
||
|
|
||
|
CacheRead.Unlock ();
|
||
|
}
|
||
|
|
||
|
#if (defined(WINNT32))
|
||
|
VOID
|
||
|
CacheMgr::InvalidateCacheForUser(
|
||
|
CLogonUserData *pUser )
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
This routine checks to see whether the given user is currently controlling the cache
|
||
|
thread. If they are, the thread is terminated.
|
||
|
|
||
|
Arguments:
|
||
|
pUser - A pointer to the user.
|
||
|
|
||
|
Return Value:
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
|
||
|
CacheRead.Lock();
|
||
|
|
||
|
if (m_CurUser == *(CUserData *)pUser) // Comparison is valid after caste
|
||
|
_InvalidateCache ();
|
||
|
|
||
|
CacheRead.Unlock();
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif
|
||
|
|
||
|
inline DWORD
|
||
|
CacheMgr::GetTimeDiff (
|
||
|
DWORD t0,
|
||
|
DWORD t1)
|
||
|
{
|
||
|
if (t1 > t0) {
|
||
|
return t1 - t0;
|
||
|
}
|
||
|
else {
|
||
|
return DWORD(-1) - t0 + t1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LPVOID CacheMgr::Allocator(
|
||
|
DWORD cb)
|
||
|
{
|
||
|
return new CHAR[cb];
|
||
|
}
|
||
|
|
||
|
|
||
|
GetPrinterCache::GetPrinterCache(
|
||
|
PCINETMONPORT pIniPort):
|
||
|
m_pIniPort (pIniPort)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
GetPrinterCache::~GetPrinterCache (
|
||
|
VOID)
|
||
|
{
|
||
|
if (m_pData) {
|
||
|
FreeBuffer (m_pIniPort, m_pData);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
GetPrinterCache::FetchData (
|
||
|
PCINETMONPORT pIniPort,
|
||
|
PVOID *ppData)
|
||
|
{
|
||
|
BOOL bRet = FALSE;
|
||
|
PGETPRINTER_CACHEDATA pCacheData = NULL;
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE, (TEXT ("GetPrinterCache::FetchData begins")));
|
||
|
#ifdef DEBUG
|
||
|
if (0) {
|
||
|
// Simulate the hanging of the current thread
|
||
|
// For debugging purpose.
|
||
|
MessageBox (NULL, TEXT ("GetPrinterCache::FetchData called. Press OK to continue."), TEXT ("ALERT"), MB_OK);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
if (pCacheData = new GETPRINTER_CACHEDATA) {
|
||
|
|
||
|
semEnterCrit ();
|
||
|
|
||
|
pCacheData->bRet = _ppinfo_net_get_info(pIniPort,
|
||
|
& (pCacheData->pInfo) ,
|
||
|
& (pCacheData->cbSize),
|
||
|
Allocator);
|
||
|
semLeaveCrit ();
|
||
|
|
||
|
pCacheData->dwLastError = GetLastError ();
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE, (TEXT ("GetPrinterCache::FetchData bRet=%d, err=%d\n"),
|
||
|
pCacheData->bRet, pCacheData->dwLastError ));
|
||
|
|
||
|
|
||
|
//
|
||
|
// We must return TRUE, otherwise PPGetPrinter won't get the correct last error
|
||
|
//
|
||
|
|
||
|
bRet = TRUE; //pCacheData->cbSize != 0;
|
||
|
}
|
||
|
|
||
|
if (!bRet) {
|
||
|
DBGMSGT (DBG_CACHE_TRACE,
|
||
|
(TEXT ("GetPrinterCache::FetchData failed, call FreeBuffer (%x, %x)"), pIniPort, pCacheData));
|
||
|
FreeBuffer (pIniPort, pCacheData);
|
||
|
}
|
||
|
else {
|
||
|
*ppData = pCacheData;
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
GetPrinterCache::FreeBuffer (
|
||
|
PCINETMONPORT pIniPort,
|
||
|
PVOID pData)
|
||
|
{
|
||
|
PGETPRINTER_CACHEDATA pCacheData = (PGETPRINTER_CACHEDATA) pData;
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE,
|
||
|
(TEXT ("FreeBuffer(%x, %x) called"), pIniPort, pCacheData));
|
||
|
|
||
|
if (pCacheData) {
|
||
|
if (pCacheData->pInfo) {
|
||
|
delete [] (PCHAR)(pCacheData->pInfo);
|
||
|
}
|
||
|
delete pCacheData;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
GetPrinterCache::BeginReadCache (
|
||
|
PPRINTER_INFO_2 *ppInfo)
|
||
|
{
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
if (m_bValid) {
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE,
|
||
|
(TEXT ("GetPrinterCache::BeginReadCache: Entered")));
|
||
|
|
||
|
PGETPRINTER_CACHEDATA pData = (PGETPRINTER_CACHEDATA) CacheMgr::BeginReadCache (m_pIniPort);
|
||
|
|
||
|
if (pData) {
|
||
|
if (pData->bRet) {
|
||
|
*ppInfo = pData->pInfo;
|
||
|
bRet = TRUE;
|
||
|
}
|
||
|
else {
|
||
|
SetLastError (pData->dwLastError);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if (!bRet && GetLastError () == ERROR_SUCCESS) {
|
||
|
|
||
|
SetLastError (ERROR_CAN_NOT_COMPLETE);
|
||
|
|
||
|
}
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE,
|
||
|
(TEXT ("GetPrinterCache::BeginReadCache: pData = %x, return = %d, lasterror = %d"),
|
||
|
pData, bRet, GetLastError ()));
|
||
|
}
|
||
|
else {
|
||
|
SetLastError (ERROR_CAN_NOT_COMPLETE);
|
||
|
}
|
||
|
|
||
|
|
||
|
return bRet;
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
EnumJobsCache::EnumJobsCache(
|
||
|
PCINETMONPORT pIniPort):
|
||
|
m_pIniPort (pIniPort)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
EnumJobsCache::~EnumJobsCache (
|
||
|
VOID)
|
||
|
{
|
||
|
if (m_pData) {
|
||
|
FreeBuffer (m_pIniPort, m_pData);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
EnumJobsCache::FetchData (
|
||
|
PCINETMONPORT pIniPort,
|
||
|
PVOID *ppData)
|
||
|
{
|
||
|
BOOL bRet = FALSE;
|
||
|
HANDLE hPort = (HANDLE)pIniPort;
|
||
|
PENUMJOBS_CACHEDATA pCacheData = NULL;
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE, (TEXT ("EnumJobsCache::FetchData begins")));
|
||
|
|
||
|
if (pCacheData = new ENUMJOBS_CACHEDATA) {
|
||
|
|
||
|
pCacheData->pje = NULL;
|
||
|
|
||
|
semEnterCrit ();
|
||
|
pCacheData->bRet = ppjob_EnumForCache(pIniPort, & (pCacheData->pje));
|
||
|
pCacheData->dwLastError = GetLastError ();
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE, (TEXT ("EnumJobsCache::FetchData bRet=%d, err=%d\n"),
|
||
|
pCacheData->bRet, pCacheData->dwLastError ));
|
||
|
|
||
|
if (pCacheData->bRet) {
|
||
|
|
||
|
if (pCacheData->pje) {
|
||
|
pCacheData->cbSize = pCacheData->pje->cbSize;
|
||
|
}
|
||
|
else {
|
||
|
pCacheData->cbSize = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
semLeaveCrit ();
|
||
|
|
||
|
bRet = TRUE;
|
||
|
}
|
||
|
|
||
|
if (bRet) {
|
||
|
*ppData = pCacheData;
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
EnumJobsCache::FreeBuffer (
|
||
|
PCINETMONPORT pIniPort,
|
||
|
PVOID pData)
|
||
|
{
|
||
|
PENUMJOBS_CACHEDATA pCacheData = (PENUMJOBS_CACHEDATA) pData;
|
||
|
|
||
|
if (pCacheData) {
|
||
|
if (pCacheData->pje) {
|
||
|
|
||
|
// memFree has access to the global link list, so it is neccesary
|
||
|
// to run it under critical secion.
|
||
|
//
|
||
|
|
||
|
semEnterCrit ();
|
||
|
memFree(pCacheData->pje, memGetSize(pCacheData->pje));
|
||
|
semLeaveCrit ();
|
||
|
}
|
||
|
delete pCacheData;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
EnumJobsCache::BeginReadCache (
|
||
|
LPPPJOB_ENUM *ppje)
|
||
|
{
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
if (m_bValid) {
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE,
|
||
|
(TEXT ("EnumJobsCache::BeginReadCache: Entered")));
|
||
|
|
||
|
PENUMJOBS_CACHEDATA pData = (PENUMJOBS_CACHEDATA) CacheMgr::BeginReadCache (m_pIniPort);
|
||
|
|
||
|
|
||
|
if (pData) {
|
||
|
if (pData->bRet) {
|
||
|
*ppje = pData->pje;
|
||
|
bRet = TRUE;
|
||
|
}
|
||
|
else {
|
||
|
SetLastError (pData->dwLastError);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!bRet && GetLastError () == ERROR_SUCCESS) {
|
||
|
|
||
|
SetLastError (ERROR_CAN_NOT_COMPLETE);
|
||
|
|
||
|
}
|
||
|
|
||
|
DBGMSGT (DBG_CACHE_TRACE,
|
||
|
(TEXT ("EnumJobsCache::BeginReadCache: pData = %x, return = %d, lasterror = %d"),
|
||
|
pData, bRet, GetLastError ()));
|
||
|
}
|
||
|
else {
|
||
|
SetLastError (ERROR_CAN_NOT_COMPLETE);
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
EnumJobsCache::EndReadCache (
|
||
|
VOID)
|
||
|
{
|
||
|
DBGMSGT (DBG_CACHE_TRACE,
|
||
|
(TEXT ("EnumJobsCache::EndReadCache: Entered")));
|
||
|
|
||
|
CacheMgr::EndReadCache ();
|
||
|
}
|
||
|
|
||
|
/*********************************************************************************
|
||
|
** End of File (cachemgr.cxx)
|
||
|
*********************************************************************************/
|