|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: dmnslave.cxx
//
// Contents: The slave thread that executes executes commands on behalf of
// the DownLevel daemon process.
//
// History: 1-31-96 srikants Created
// 1-06-97 srikants Renamed to dmnslave.cxx from dlslave.cxx
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <cci.hxx>
#include <glbconst.hxx>
#include "dmnslave.hxx"
#include "cimanger.hxx"
const WCHAR * wcsCiDaemonImage = L"%systemroot%\\system32\\cidaemon.exe";
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::GetInheritableHandle
//
// Synopsis: Creates an inheritable handle of this process for
// synchronization purposes only.
//
// Arguments: [hTarget] - The inherited handle.
//
// Returns: STATUS_SUCCESS if successful.
// An error code otherwise.
//
// History: 2-02-96 srikants Created
//
//----------------------------------------------------------------------------
DWORD CDaemonSlave::GetInheritableHandle( HANDLE & hTarget ) { HANDLE hSelf = GetCurrentProcess();
BOOL fSuccess = DuplicateHandle( hSelf, // source process
hSelf, // source handle
hSelf, // destination process
&hTarget, // target handle
SYNCHRONIZE, // desired access
TRUE, // inheritable
0 // dwOptions
);
if (fSuccess) return STATUS_SUCCESS;
return GetLastError(); } //GetInheritableHandle
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::CDaemonSlave ~ctor
//
// Synopsis: Constructor of the class that is manages the slave thread
// in CI. This thread will execute the commands specified by
// the DownLevel Daemon process.
//
// Arguments: [cicat] -
// [pwcsCatRoot] - Catalog path.
// [nameGen] - mutex name
// [pwcsCatName] - 0 or the friendly name
//
// History: 1-31-96 srikants Created
//
//----------------------------------------------------------------------------
CDaemonSlave::CDaemonSlave( CCiManager & ciManager, CCI * pCci, WCHAR const * pwcsCatRoot, CSharedNameGen & nameGen, const GUID & clsidDaemonClientMgr) : _ciManager(ciManager), _pCci(pCci), #pragma warning( disable : 4355 ) // this used in base initialization
_thrSlave(SlaveThread, this, TRUE), #pragma warning( default : 4355 )
_fAbort(FALSE), _smemMutex( nameGen.GetMutexName() ), _sharedMem( nameGen.GetSharedMemName(),MAX_DL_SHARED_MEM), _evtCi( nameGen.GetCiEventName() ), _evtDaemon( nameGen.GetDaemonEventName() ), _pProcess(0), _hParent(INVALID_HANDLE_VALUE), _state(eDeathNotified), _daemonExitStatus(0), _cbStartupData(0), _clsidDaemonClientMgr(clsidDaemonClientMgr) { //
// Initialize both the events to be in an "unsignalled" state.
//
_evtCi.Reset(); _evtDaemon.Reset();
//
// Initialize the shared memory.
//
_pLayout = (CFilterSharedMemLayout *) _sharedMem.Map(); _pLayout->Init();
Win4Assert( 0 != pwcsCatRoot ); ULONG len = wcslen( pwcsCatRoot ); _wszCatRoot.Init( len+1 ); RtlCopyMemory( _wszCatRoot.GetPointer(), pwcsCatRoot, (len+1) * sizeof(WCHAR) );
DWORD dwError = GetInheritableHandle( _hParent ); if ( STATUS_SUCCESS != dwError ) { ciDebugOut(( DEB_ERROR, "Cannot duplicate a handle to self. Error 0x%X\n", dwError )); THROW( CException( HRESULT_FROM_WIN32( dwError) ) ); }
Win4Assert( INVALID_HANDLE_VALUE != _hParent );
SHandle xSafeHandle(_hParent);
//
// First resume the slave thread and then resume the daemon process.
// The slave should run at a lower priority than queries.
//
if ( IDLE_PRIORITY_CLASS == _ciManager._GetFrameworkParams().GetThreadClassFilter() ) { _thrSlave.SetPriority( THREAD_PRIORITY_BELOW_NORMAL ); } else { _thrSlave.SetPriority( THREAD_PRIORITY_NORMAL ); }
_thrSlave.Resume();
xSafeHandle.Acquire(); }
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::StartFiltering
//
// Synopsis: Signal to indicate that it is okay to start the daemon
// process.
//
// History: 12-30-96 srikants Created
//
//----------------------------------------------------------------------------
void CDaemonSlave::StartFiltering( BYTE const * pbStartupData, ULONG cbStartupData ) { // ====================================================
CLock lock(_mutex);
if ( eReadyToStart == _state || eRunning == _state ) return;
if ( eDeathNotified != _state ) { ciDebugOut(( DEB_ERROR, "StartFiltering called in an invalid state (%d)\n", _state ));
THROW( CException( CI_E_INVALID_STATE ) ); }
//
// Make a local copy of the startup data.
//
if ( _xbStartupData.Count() < cbStartupData ) { _xbStartupData.Free(); _xbStartupData.Set( cbStartupData, new BYTE [cbStartupData] ); }
RtlCopyMemory( _xbStartupData.GetPointer(), pbStartupData, cbStartupData ); _cbStartupData = cbStartupData;
_state = eReadyToStart; _evtCi.Set(); // ====================================================
}
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::StartProcess
//
// Synopsis: Creates the DL daemon process if it is not already started.
//
// History: 1-31-96 srikants Created
//
//----------------------------------------------------------------------------
void CDaemonSlave::StartProcess() { if ( 0 == _pProcess ) { WCHAR wszCommandLine[ MAX_PATH + 50 ]; swprintf( wszCommandLine,L"\"%ls\" %ls \"%ls\" %ul %ul", DL_DAEMON_EXE_NAME, DL_DAEMON_ARG1_W, _wszCatRoot.GetPointer(), _sharedMem.SizeLow(), GetCurrentProcessId() );
XInterface<ICiCAdviseStatus> xAdviseStatus;
SCODE sc = _ciManager._xDocStore->QueryInterface( IID_ICiCAdviseStatus, xAdviseStatus.GetQIPointer() ); if ( S_OK != sc ) { Win4Assert( xAdviseStatus.IsNull() );
THROW( CException( sc ) ); }
_pProcess = new CProcess( DL_DAEMON_EXE_NAME, wszCommandLine, TRUE, // suspended
xAdviseStatus.GetPointer() ); } } //StartProcess
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::~CDaemonSlave
//
// Synopsis: Destructor of the CDaemonSlave class. Kills the slave thread
// and then kills the daemon process.
//
// History: 1-31-96 srikants Created
//
//----------------------------------------------------------------------------
CDaemonSlave::~CDaemonSlave() { _fAbort = TRUE;
//
// Kill the thread first. Otherwise, the process will be recreated
// by the thread.
//
KillThread(); KillProcess();
//
// Close the handle to ourselves.
//
CloseHandle(_hParent); }
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::KillProcess
//
// Synopsis: Kills the downlevel daemon process.
//
// History: 1-31-96 srikants Created
//
//----------------------------------------------------------------------------
void CDaemonSlave::KillProcess() { // =====================================================
CLock lock(_mutex);
if ( _pProcess ) { //
// Get the process exit code.
//
SaveDaemonExitCode();
TRY { delete _pProcess; _pProcess = 0;
_state = eDied; _ciManager.ProcessCiDaemonTermination( _daemonExitStatus ); _state = eDeathNotified; } CATCH ( CException, e ) { ciDebugOut(( DEB_ERROR, "Error while killing process. 0x%X\n", e.GetErrorCode() )); } END_CATCH
_evtCi.Reset(); _pProcess = 0; }
//
// The process has either not started at all (_pProcess==0), or it has been notified, or it
// has died.
//
Win4Assert( eReadyToStart == _state || eDeathNotified == _state || eDied == _state ); // =====================================================
}
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::RestartDaemon
//
// Synopsis: Starts the daemon process.
//
// History: 1-31-96 srikants Created
//
//----------------------------------------------------------------------------
void CDaemonSlave::RestartDaemon() { Win4Assert( eReadyToStart == _state ); StartProcess(); _pProcess->Resume(); }
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::KillThread
//
// Synopsis: Kills the slave thread.
//
// History: 1-31-96 srikants Created
//
//----------------------------------------------------------------------------
void CDaemonSlave::KillThread() { _evtCi.Set(); _thrSlave.WaitForDeath(); }
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::InitiateShutdown
//
// Synopsis: Initiates the shutdown of the slave thread.
//
// History: 12-30-96 srikants Added comment header.
//
//----------------------------------------------------------------------------
void CDaemonSlave::InitiateShutdown() { _fAbort = TRUE; _evtCi.Set(); }
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::SlaveThread
//
// Synopsis: The slave thread in CI.
//
// Arguments: [self] -
//
// History: 1-31-96 srikants Created
//
//----------------------------------------------------------------------------
DWORD CDaemonSlave::SlaveThread( void * self ) { ((CDaemonSlave *) self)->DoWork();
return 0; }
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::FilterReady
//
// Synopsis: Executes the FilterReady() call on behalf of the DL Daemon.
//
// Returns: Status of the operation.
//
// History: 1-31-96 srikants Created
//
//----------------------------------------------------------------------------
SCODE CDaemonSlave::FilterReady() { CFilterReadyLayout & data = _pLayout->GetFilterReady(); Win4Assert( data.IsValid() );
SCODE status = S_OK;
Win4Assert( 0 != _pCci ); ULONG cb = 0;
do { cb = data.GetCount(); BYTE * docBuffer = data.GetBuffer(); ULONG cMaxDocs = data.GetMaxDocs();
if ( 0 != _pCci ) { status = _pCci->FilterReady( docBuffer, cb, cMaxDocs ); } else { status = STATUS_NOT_FOUND; }
_ciManager._HandleFilterReadyStatus( status ); } while ( FILTER_S_DISK_FULL == status );
data.SetCount( cb ); return status; }
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::FilterMore
//
// Synopsis: Executes the FilterMore() call.
//
// History: 1-31-96 srikants Created
//
//----------------------------------------------------------------------------
SCODE CDaemonSlave::FilterMore() { CFilterMoreDoneLayout & data = _pLayout->GetFilterMore(); Win4Assert( data.IsValid() );
SCODE status = S_OK;
Win4Assert( 0 != _pCci );
if ( 0 != _pCci ) { STATUS const * pStatus = data.GetStatusArray(); ULONG cStatus = data.GetCount(); status = _pCci->FilterMore( pStatus, cStatus ); } else { status = STATUS_NOT_FOUND; }
return status; }
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::FilterDataReady
//
// History: 1-31-96 srikants Created
//
//----------------------------------------------------------------------------
SCODE CDaemonSlave::FilterDataReady() { CFilterDataLayout & data = _pLayout->GetFilterDataReady(); Win4Assert( data.IsValid() );
SCODE status = S_OK;
Win4Assert( 0 != _pCci );
if ( 0 != _pCci ) { BYTE const * pEntryBuf = data.GetBuffer(); ULONG cb = data.GetSize(); status = _pCci->FilterDataReady( pEntryBuf, cb ); } else { status = STATUS_NOT_FOUND; }
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::FilterDone
//
// History: 1-31-96 srikants Created
//
//----------------------------------------------------------------------------
SCODE CDaemonSlave::FilterDone() { CFilterMoreDoneLayout & data = _pLayout->GetFilterDone(); Win4Assert( data.IsValid() );
SCODE status = S_OK;
Win4Assert( 0 != _pCci );
if ( 0 != _pCci ) { STATUS const * pStatus = data.GetStatusArray(); ULONG cStatus = data.GetCount(); status = _pCci->FilterDone( pStatus, cStatus ); } else { status = STATUS_NOT_FOUND; }
return status; }
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::FilterStoreValue
//
// History: 1-31-96 srikants Created
//
//----------------------------------------------------------------------------
SCODE CDaemonSlave::FilterStoreValue() { CFilterStoreValueLayout & data = _pLayout->GetFilterStoreValueLayout(); Win4Assert( data.IsValid() );
CMemDeSerStream deSer( data.GetBuffer(), data.GetCount() );
CFullPropSpec ps( deSer );
if ( !ps.IsValid() ) THROW( CException( E_OUTOFMEMORY ) );
CStorageVariant var( deSer );
if ( !var.IsValid() ) THROW( CException( E_OUTOFMEMORY ) );
WORKID widFake = data.GetWorkid();
BOOL fSuccess; _pCci->FilterStoreValue( widFake, ps, var, fSuccess ); data.SetStatus( fSuccess );
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::FilterStoreSecurity
//
// History: 06 Feb 96 AlanW Created
//
//----------------------------------------------------------------------------
SCODE CDaemonSlave::FilterStoreSecurity() { CFilterStoreSecurityLayout & data = _pLayout->GetFilterStoreSecurityLayout(); Win4Assert( data.IsValid() );
PSECURITY_DESCRIPTOR pSD = data.GetSD(); ULONG cbSD = data.GetCount();
WORKID widFake = data.GetWorkid();
BOOL fSuccess; _pCci->FilterStoreSecurity( widFake, pSD, cbSD, fSuccess ); data.SetStatus( fSuccess );
return S_OK; } //FilterStoreSecurity
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::FPSToPROPID, public
//
// Synopsis: Converts FULLPROPSPEC to PROPID
//
// Returns: S_OK on success
//
// History: 29-Dec-1997 KyleP Created
//
//----------------------------------------------------------------------------
SCODE CDaemonSlave::FPSToPROPID() { CFPSToPROPIDLayout & data = _pLayout->GetFPSToPROPID(); Win4Assert( data.IsValid() );
CMemDeSerStream deSer( data.GetBuffer(), data.GetCount() );
CFullPropSpec fps( deSer );
if ( !fps.IsValid() ) return E_INVALIDARG;
SCODE status = S_OK;
Win4Assert( 0 != _pCci );
if ( 0 != _pCci ) { status = _pCci->FPSToPROPID( fps, *(PROPID *)data.GetBuffer() );
unsigned cb;
if ( SUCCEEDED(status) ) cb = sizeof(PROPID); else cb = 0;
data.SetCount( cb ); } else { status = STATUS_NOT_FOUND; }
return status; } //FPSToPROPID
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::GetClientStartupData
//
// Synopsis: Retrieves the client startup data.
//
// History: 12-19-96 srikants Created
//
//----------------------------------------------------------------------------
SCODE CDaemonSlave::GetClientStartupData() { CFilterStartupDataLayout & data = _pLayout->GetStartupData(); Win4Assert( data.IsValid() );
SCODE status = S_OK;
Win4Assert( 0 != _pCci );
if ( 0 != _pCci ) { data.SetData( _clsidDaemonClientMgr, _xbStartupData.GetPointer(), _cbStartupData ); } else { status = STATUS_NOT_FOUND; }
return status; } //GetClientStartupData
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::DoSlaveWork
//
// Synopsis: The "de-multiplexor" which figures out what work was signalled
// by the daemon process.
//
// History: 1-31-96 srikants Created
//
//----------------------------------------------------------------------------
void CDaemonSlave::DoSlaveWork() { if ( _fAbort ) return;
CIPLock lock(_smemMutex);
Win4Assert( 0 != _pLayout );
CFilterSharedMemLayout::EFilterWorkType workType = _pLayout->GetWorkType();
SCODE status = S_OK;
TRY { switch ( workType ) { case CFilterSharedMemLayout::eNone: break;
case CFilterSharedMemLayout::eFilterReady: { status = FilterReady(); break; }
case CFilterSharedMemLayout::eFilterDataReady: { status = FilterDataReady(); break; }
case CFilterSharedMemLayout::eFilterMore: { status = FilterMore(); break; }
case CFilterSharedMemLayout::eFilterDone: { status = FilterDone(); break; }
case CFilterSharedMemLayout::eFilterStoreValue: { status = FilterStoreValue(); break; }
case CFilterSharedMemLayout::eFilterStoreSecurity: { status = FilterStoreSecurity(); break; }
case CFilterSharedMemLayout::eFPSToPROPID: { status = FPSToPROPID(); break; }
case CFilterSharedMemLayout::eFilterStartupData: { status = GetClientStartupData(); break; }
default: ciDebugOut(( DEB_ERROR, "Unknown work code from daemon\n", workType )); Win4Assert( !"Unknown work code"); status = STATUS_INVALID_PARAMETER; break; } } CATCH( CException, e ) { status = e.GetErrorCode();
ciDebugOut(( DEB_WARN, "Error (0x%X) caught while doing slave work\n", status ));
if ( IsCiCorruptStatus( e.GetErrorCode() ) ) RETHROW();
} END_CATCH
if ( IsDiskLowError(status) ) { BOOL fLow; _pCci->VerifyIfLowOnDiskSpace(fLow); }
//
// Set the status of the operation and wake up the daemon process.
//
_pLayout->SetStatus( status ); _evtDaemon.Set(); } //DoSlaveWork
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::DoStateMachineWork
//
// Synopsis: Does state machine book keeping work. If necessary, it will
// restart the cidaemon process.
//
// History: 12-30-96 srikants Created
//
//----------------------------------------------------------------------------
void CDaemonSlave::DoStateMachineWork() { // =======================================
CLock lock(_mutex);
Win4Assert( eRunning != _state );
if ( _state == eReadyToStart && !IsProcessLowOnResources() ) { RestartDaemon(); _state = eRunning; } else if ( _state == eDied ) { _ciManager.ProcessCiDaemonTermination( _daemonExitStatus ); _state = eDeathNotified; } // =======================================
} //DoStateMachineWork
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::SaveDaemonExitCode
//
// Synopsis: Saves the exit code of the daemon process.
//
// History: 12-30-96 srikants Created
//
//----------------------------------------------------------------------------
void CDaemonSlave::SaveDaemonExitCode() { Win4Assert( 0 != _pProcess );
HANDLE hProcess = _pProcess->GetHandle(); DWORD dwExitCode;
if ( GetExitCodeProcess( hProcess, &dwExitCode ) ) _daemonExitStatus = dwExitCode; else _daemonExitStatus = E_FAIL; } //SaveDaemonExitCode
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::IsProcessLowOnResources
//
// Synopsis: Tests if the daemon process died because of being low on
// resources.
//
// Returns: Returns TRUE if the daemon process died with low resource
// condition (low on memory or disk). FALSE o/w.
//
// History: 3-11-96 srikants Created
//
//----------------------------------------------------------------------------
BOOL CDaemonSlave::IsProcessLowOnResources() const { Win4Assert( 0 == _pProcess );
return _IsResourceLowError( _daemonExitStatus ); }
static WCHAR const * my_wcsistr( WCHAR const * wcsString, WCHAR const * wcsPattern ) { if ( (wcsPattern == 0) || (*wcsPattern == 0) ) return wcsString;
ULONG cwcPattern = wcslen(wcsPattern);
while ( *wcsString != 0 ) { while ( (*wcsString != 0) && (towupper(*wcsString) != towupper(*wcsPattern)) ) wcsString++;
if ( 0 == *wcsString ) return 0;
if ( _wcsnicmp( wcsString, wcsPattern, cwcPattern) == 0 ) return wcsString;
wcsString++; }
return 0; } //my_wcsistr
//+---------------------------------------------------------------------------
//
// Functions: IsInDebugger
//
// Synopsis: Tests if a process is being debugged
//
// Arguments: [hProcess] -- The process handle to test.
//
// Returns: Returns TRUE if the process is being debugged.
//
// History: 4-23-98 dlee Created
//
//----------------------------------------------------------------------------
BOOL IsInDebugger( HANDLE hProcess ) { //
// Is the child process cdb, ntsd, or windbg? If so, the daemon was started
// via ImageFileExecutionOptions, and we can safely assume it's in a debugger.
//
const ULONG cbBuffer = sizeof(UNICODE_STRING) + ( MAX_PATH * sizeof WCHAR ); XArray<BYTE> xBuf( cbBuffer ); PUNICODE_STRING pBuffer = (PUNICODE_STRING) xBuf.Get();
NTSTATUS s = NtQueryInformationProcess( hProcess, ProcessImageFileName, pBuffer, cbBuffer, 0 );
if ( STATUS_SUCCESS != s ) return FALSE;
// Null-terminate the buffer
pBuffer->Buffer[ pBuffer->Length / sizeof WCHAR ] = 0;
// The buffer now looks something like "\Device\HarddiskVolume2\WINDOWS\system32\ntsd.exe"
if ( ( 0 != my_wcsistr( pBuffer->Buffer, L"ntsd.exe" ) ) || ( 0 != my_wcsistr( pBuffer->Buffer, L"cdb.exe" ) ) || ( 0 != my_wcsistr( pBuffer->Buffer, L"windbg.exe" ) ) ) return TRUE;
//
// So it's not a debugger. Is the child process in a debugger?
// First get the base address of the process.
//
PROCESS_BASIC_INFORMATION bi; s = NtQueryInformationProcess( hProcess, ProcessBasicInformation, (PVOID) &bi, sizeof bi, 0 );
if ( STATUS_SUCCESS != s ) return FALSE;
PEB Peb; if ( ReadProcessMemory( hProcess, bi.PebBaseAddress, &Peb, sizeof PEB, 0 ) ) return Peb.BeingDebugged;
return FALSE; } //IsInDebugger
//+---------------------------------------------------------------------------
//
// Member: CDaemonSlave::DoWork
//
// Synopsis: Main worker thread.
//
// History: 1-31-96 srikants Created
//
//----------------------------------------------------------------------------
void CDaemonSlave::DoWork() { const cHandles = 2; HANDLE aHandles[cHandles];
const iCiWork = 0; // Index of the ci work event.
const iDaemonProcess = 1; // Index of the daemon process.
aHandles[iCiWork] = _evtCi.GetHandle();
BOOL fContinue = TRUE;
while ( fContinue ) { if ( !_fAbort ) { TRY { DWORD nHandles = 1;
if ( 0 != _pProcess ) { aHandles[iDaemonProcess] = _pProcess->GetHandle(); nHandles++; }
DWORD timeout = _ciManager._GetFrameworkParams().GetDaemonResponseTimeout() * 60 * 1000;
DWORD status = WaitForMultipleObjects( nHandles, aHandles, FALSE, timeout );
if ( WAIT_FAILED == status ) { ciDebugOut(( DEB_ERROR, "WaitForMultipleObjects failed with error 0x%X\n", GetLastError() )); //
// Don't restart the daemon process immediately. Wait for
// the timeout period.
//
KillProcess(); } else if ( WAIT_TIMEOUT == status ) { // The process is probably looping. We should kill it and
// restart.
if ( eRunning == _state ) { if ( 0 != _pProcess ) { BOOL fDbg = IsInDebugger( _pProcess->GetHandle() );
ciDebugOut(( DEB_ERROR, "Daemon is looping, killing? %s\n", fDbg ? "no" : "yes" ));
if ( !fDbg ) KillProcess(); } } else { DoStateMachineWork(); } } else { //
// An event was signalled.
//
DWORD iWake = status - WAIT_OBJECT_0;
if ( iCiWork == iWake ) { //
// We have been given some work. Do it.
//
// =========================================
{ CLock lock(_mutex); _evtCi.Reset(); } // =========================================
if ( eRunning == _state ) DoSlaveWork(); else DoStateMachineWork(); } else if ( iDaemonProcess == iWake ) { //
// The daemon process died.
//
ciDebugOut(( DEB_ERROR, "Daemon process died\n" )); KillProcess(); } } } CATCH(CException, e ) { ciDebugOut(( DEB_ERROR, "Error in the Slave Thread - 0x%X\n", e.GetErrorCode() ));
_ciManager.ProcessError( e.GetErrorCode() );
if ( IsCiCorruptStatus( e.GetErrorCode() ) ) { KillProcess(); fContinue = FALSE; } } END_CATCH } else { fContinue = FALSE; } } } //DoWork
|