|
|
#include "stdafx.h"
#if !defined(BITS_V12_ON_NT4)
#include "init.tmh"
#endif
EVENT_LOG * g_EventLogger;
BOOL CreateAndWaitForThread( LPTHREAD_START_ROUTINE fn, HANDLE * pThreadHandle, DWORD * pThreadId );
//
// The whole block of code is an attempt to work
// around the C++ termination handler. The idea is to
// intercept the C++ exception code and map it to
// a bogus code which probably won't be handled.
// This should give us the Dr. Watson.
//
// The NT exception # used by C runtime
#define EH_EXCEPTION_NUMBER ('msc' | 0xE0000000)
DWORD BackgroundThreadProcFilter( LPEXCEPTION_POINTERS ExceptionPointers ) {
// Values are 32 bit values layed out as follows:
//
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// +---+-+-+-----------------------+-------------------------------+
// |Sev|C|R| Facility | Code |
// +---+-+-+-----------------------+-------------------------------+
// pick a random code that probably won't be handled.
if ( EH_EXCEPTION_NUMBER == ExceptionPointers->ExceptionRecord->ExceptionCode ) ExceptionPointers->ExceptionRecord->ExceptionCode = 0xE0000001;
return EXCEPTION_CONTINUE_SEARCH; }
DWORD BackgroundThreadProc( void *lp );
DWORD WINAPI BackgroundThreadProcWrap( void *lp ) { __try { return BackgroundThreadProc( lp ); } __except( BackgroundThreadProcFilter( GetExceptionInformation() ) ) { ASSERT( 0 ); } ASSERT( 0 );
return 0; }
DWORD BackgroundThreadProc( void *lp ) //
// 5-18-2001: I'm avoiding LogInfo calls before g_Manager is initialized,
// in order to catch a bug where init and Uninit seem to overlap.
//
{ MSG msg; HRESULT hr = S_OK; DWORD dwRegCONew = 0; DWORD dwRegCOOld = 0;
DWORD instance = g_ServiceInstance;
HANDLE hEvent = (HANDLE) lp;
//CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); //not on Win95!
//hr = CoInitialize(NULL);
hr = CoInitializeEx( NULL, COINIT_MULTITHREADED ); if (FAILED(hr)) { LogInfo( "background thread failed CoInit, instance %d, hr %x", instance, hr );
return hr; }
//force it to create a msg queue
PeekMessage(&msg, NULL, WM_APP, WM_APP, PM_NOREMOVE);
try { ASSERT( g_Manager == NULL );
g_EventLogger = new EVENT_LOG; g_Manager = new CJobManager;
LogInfo( "background thread starting, instance %d, manager %p", instance, g_Manager );
THROW_HRESULT( g_Manager->Unserialize() );
//
// List currently active users as logged in.
// List the Big Three service accounts as logged in.
//
THROW_HRESULT( g_Manager->m_Users.AddActiveUsers() ); THROW_HRESULT( g_Manager->m_Users.AddServiceAccounts() );
g_Manager->m_Users.Dump();
//
// If any networks are active, begin processing jobs.
//
g_Manager->OnNetworkChange();
//
// Allow client calls.
//
THROW_HRESULT( g_Manager->RegisterClassObjects() );
LogInfo( "Background thread initialized.");
//
// The thread has set up completely.
//
SetEvent( hEvent ); } catch (ComError exception) { hr = exception.Error(); LogInfo( "background thread failed, instance %d, hr %x", instance, hr ); goto exit; } catch (HRESULT exception ) { LogError( "init : caught unhandled HRESULT %x", exception);
#ifdef DBG
DbgBreakPoint(); #endif
hr = exception; goto exit; } catch (DWORD exception ) { LogError( "init : caught unhandled error %d", exception);
#ifdef DBG
DbgBreakPoint(); #endif
hr = exception;
goto exit;
}
//
// Message & task pump: returns only when the object shuts down.
// Intentionally, call this function outside of a try/catch
// since any unhandled exception in this function should
// be an AV.
g_Manager->TaskThread();
exit: LogInfo("task thread exiting, hr %x", hr);
if (g_Manager) { ASSERT( instance == g_ServiceInstance );
g_Manager->Shutdown(); delete g_Manager; g_Manager = NULL; }
delete g_EventLogger; g_EventLogger = NULL;
CoUninitialize(); return hr; }
HANDLE g_hBackgroundThread; DWORD g_dwBackgroundThreadId;
// void TestImpersonationObjects();
HRESULT WINAPI InitQmgr() { ++g_ServiceInstance;
if (!CreateAndWaitForThread( BackgroundThreadProcWrap, &g_hBackgroundThread, &g_dwBackgroundThreadId )) { return HRESULT_FROM_WIN32( GetLastError() ); }
LogInfo( "Finishing InitQmgr()" );
return S_OK; }
HRESULT WINAPI UninitQmgr() { DWORD s; HANDLE hThread = g_hBackgroundThread;
if (hThread == NULL) { // never set up
LogInfo("Uninit Qmgr: nothing to do"); return S_OK; }
LogInfo("Uninit Qmgr: beginning");
//
// Tell the thread to terminate.
//
// 3.5 interrupt the downloader.
g_Manager->LockWriter();
// Hold the writer lock while killing the downloader.
g_Manager->InterruptDownload();
g_Manager->UnlockWriter();
PostThreadMessage(g_dwBackgroundThreadId, WM_QUIT, 0, 0);
g_dwBackgroundThreadId = 0; g_hBackgroundThread = NULL;
//
// Wait until the thread actually terminates.
//
s = WaitForSingleObject( hThread, INFINITE );
LogInfo("Uninit Qmgr: wait finished with %d", s);
CloseHandle(hThread);
if (s != WAIT_OBJECT_0) { return HRESULT_FROM_WIN32( s ); }
return S_OK; }
HRESULT CheckServerInstance( long ObjectServiceInstance ) { IncrementCallCount();
if (g_ServiceInstance != ObjectServiceInstance || g_ServiceState != MANAGER_ACTIVE) { LogWarning("call blocked: mgr state %d, instance %d vs. %d", g_ServiceState, g_ServiceInstance, ObjectServiceInstance);
DecrementCallCount();
return CO_E_SERVER_STOPPING; }
return S_OK; }
BOOL CreateAndWaitForThread( LPTHREAD_START_ROUTINE fn, HANDLE * pThreadHandle, DWORD * pThreadId ) { HANDLE hThread = NULL; HANDLE hEvent = NULL; HANDLE Handles[2]; DWORD dwThreadID; DWORD s = 0;
*pThreadHandle = NULL; *pThreadId = 0;
//
// Create the message-pump thread, then wait for the thread to exit or to signal success.
//
hEvent = CreateEvent( NULL, // no security
FALSE, // not manual reset
FALSE, // initially not set
NULL ); if (!hEvent) { goto Cleanup; }
hThread = CreateThread(NULL, 0, fn, PVOID(hEvent), 0, &dwThreadID); if (hThread == NULL) { goto Cleanup; }
enum { THREAD_INDEX = 0, EVENT_INDEX = 1 };
Handles[ THREAD_INDEX ] = hThread; Handles[ EVENT_INDEX ] = hEvent;
s = WaitForMultipleObjects( 2, // 2 handles
Handles, FALSE, // don't wait for all
INFINITE ); switch (s) { case WAIT_OBJECT_0 + THREAD_INDEX: { // the thread exited.
if (GetExitCodeThread( hThread, &s)) { SetLastError( s ); } goto Cleanup; }
case WAIT_OBJECT_0 + EVENT_INDEX: { // success
break; }
default: { // some random error. We are really toasted if
// WaitForMultipleObjects is failing.
ASSERT(0); goto Cleanup; } }
CloseHandle( hEvent ); hEvent = NULL;
*pThreadHandle = hThread; *pThreadId = dwThreadID;
return TRUE;
Cleanup:
if (hThread) { CloseHandle( hThread ); }
if (hEvent) { CloseHandle( hEvent ); }
return FALSE; }
|