windows-nt/Source/XPSP1/NT/admin/services/drizzle/newjob/init.cpp
2020-09-26 16:20:57 +08:00

384 lines
8.3 KiB
C++

#include "stdafx.h"
#if !defined(BITS_V12_ON_NT4)
#include "init.tmh"
#endif
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_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;
}
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;
}