|
|
//+-------------------------------------------------------------
//
// File: perfcli.cxx
//
// Contents: First attempt at getting perfcliing to work
//
// This is the client side
//
//
//---------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <io.h>
#include <ole2.h>
#include <com.hxx>
#include "app.hxx"
#include <memalloc.h>
#include <objerror.h>
#pragma hdrstop
//+--------------------------------------------------------------
/* Definitions. */
#define MAX_CALLS 1000
#define MAX_THREADS 10
typedef enum what_next_en { wait_wn, interrupt_wn, quit_wn } what_next_en;
//+--------------------------------------------------------------
/* Prototypes. */ void interrupt ( void ); void check_for_request ( void ); BOOL server_loop ( void ); DWORD _stdcall ThreadHelper ( void * ); void wait_for_message ( void ); void wake_up_and_smell_the_roses( void );
//+--------------------------------------------------------------
/* Globals. */ DWORD thread_mode = COINIT_MULTITHREADED; HANDLE Done; BOOL server; BOOL Multicall_Test; BOOL InterruptTestResults; BOOL InterruptTestDone; DWORD MainThread; DWORD NestedCallCount = 0; what_next_en WhatNext; ITest *global_test = NULL; BOOL global_interrupt_test;
/***************************************************************************/ STDMETHODIMP_(ULONG) CTest::AddRef( THIS ) { InterlockedIncrement( (long *) &ref_count ); return ref_count; }
/***************************************************************************/ CTest::CTest() { ref_count = 1; custom = NULL; }
/***************************************************************************/ CTest::~CTest() { if (custom != NULL) { custom->Release(); custom = NULL; } }
/***************************************************************************/ STDMETHODIMP CTest::sick( ULONG val ) { TRY { THROW( CException(val) ); } CATCH( CException, exp ) { } END_CATCH; return S_OK; }
/***************************************************************************/ STDMETHODIMP CTest::die_cpp( ULONG val ) { THROW( CException(val) ); return S_OK; }
/***************************************************************************/ STDMETHODIMP CTest::die_nt( ULONG val ) { RaiseException( val, 0, 0, NULL ); return S_OK; }
/***************************************************************************/ STDMETHODIMP_(DWORD) CTest::die( ITest *callback, ULONG catch_depth, ULONG throw_depth, ULONG throw_val ) { if (catch_depth == 0) { TRY { return callback->die( this, catch_depth - 1, throw_depth - 1, throw_val ); } CATCH( CException, exp ) { #if DBG==1
if (DebugCoGetRpcFault() != throw_val) { printf( "Propogated server fault was returned as 0x%x not 0x%x\n", DebugCoGetRpcFault(), throw_val ); // return FALSE;
} #endif
return TRUE; } END_CATCH } else if (throw_depth == 0) { THROW( CException(throw_val) ); } else return callback->die( this, catch_depth - 1, throw_depth - 1, throw_val ); return FALSE; }
/***************************************************************************/ STDMETHODIMP CTest::interrupt( ITest *param, BOOL go ) { global_interrupt_test = go; if (go) { global_test = param; global_test->AddRef(); WhatNext = interrupt_wn; wake_up_and_smell_the_roses(); } else WhatNext = wait_wn; return S_OK; }
/***************************************************************************/ STDMETHODIMP_(BOOL) CTest::hello() { if (GetCurrentThreadId() == MainThread) printf( "Hello on the main thread.\n" ); else printf( "Hello on thread %d.\n", GetCurrentThreadId ); return !InterruptTestDone; }
/***************************************************************************/ STDMETHODIMP CTest::recurse( ITest *callback, ULONG depth ) { if (depth == 0) return S_OK; else return callback->recurse( this, depth-1 ); }
/***************************************************************************/ STDMETHODIMP CTest::recurse_interrupt( ITest *callback, ULONG depth ) { MSG msg;
if (PeekMessage( &msg, NULL, 0, 0, PM_REMOVE )) { TranslateMessage (&msg); DispatchMessage (&msg); }
if (depth == 0) return S_OK; else return callback->recurse( this, depth-1 ); }
/***************************************************************************/ STDMETHODIMP CTest::sleep( ULONG time ) {
// For single threaded mode, verify that this is the only call on the
// main thread.
NestedCallCount += 1; printf( "Sleeping on thread %d for the %d time concurrently.\n", GetCurrentThreadId(), NestedCallCount ); if (thread_mode == COINIT_SINGLETHREADED) { if (GetCurrentThreadId() != MainThread) { printf( "Sleep called on the wrong thread in single threaded mode.\n" ); NestedCallCount -= 1; return FALSE; } else if (NestedCallCount != 1) { printf( "Sleep nested call count is %d instead of not 1 in single threaded mode.\n", NestedCallCount ); NestedCallCount -= 1; return FALSE; } }
// For multithreaded mode, verify that this is not the main thread.
else if (GetCurrentThreadId() == MainThread) { printf( "Sleep called on the main thread in multi threaded mode.\n" ); NestedCallCount -= 1; return FALSE; }
Sleep( time ); NestedCallCount -= 1; return S_OK; }
/***************************************************************************/ STDMETHODIMP_(DWORD) CTest::DoTest( ITest *test, ITest *another ) { HRESULT result; int i; BOOL success; HANDLE helper[MAX_THREADS]; DWORD thread_id; DWORD status;
// Let the server throw and exception and catch it before returning.
result = test->sick( 95 ); if (result != S_OK) { printf( "Internal server fault was not dealt with correctly.\n" ); return FALSE; }
// Let the server throw a C++ exception here.
result = test->die_cpp( 0xdeaff00d ); if (result != RPC_E_FAULT) { printf( "C++ server fault was not dealt with correctly.\n" ); return FALSE; } #if DBG==1
if (DebugCoGetRpcFault() != 0xdeaff00d) { printf( "C++ server fault was returned as 0x%x not 0x%x\n", DebugCoGetRpcFault(), 0xdeaff00d ); // return FALSE;
} #endif
// Let the server throw a NT exception here.
result = test->die_nt( 0xaaaabdbd ); if (result != RPC_E_FAULT) { printf( "NT server fault was not dealt with correctly.\n" ); return FALSE; } #if DBG==1
if (DebugCoGetRpcFault() != 0xaaaabdbd) { printf( "C++ server fault was returned as 0x%x not 0x%x\n", DebugCoGetRpcFault(), 0xaaaabdbd ); return FALSE; } #endif
// Test a recursive call.
result = test->recurse( this, 10 ); if (result != S_OK) { printf( "Recursive call failed: 0x%x\n", result ); return FALSE; }
// Test throwing and immediately catching an exception.
//success = test->die( this, 2, 3, 0x12345678 );
//if (!success)
//{
// printf( "Could not catch server exception.\n" );
// return FALSE;
//}
// Test throwing, propogating, and then catching an exception.
// success = test->die( this, 1, 3, 0x87654321 );
//if (!success)
//{
// printf( "Could not catch propogated server exception.\n" );
// return FALSE;
//}
// Test multiple threads.
Multicall_Test = TRUE; for (i = 0; i < MAX_THREADS; i++) { helper[i] = CreateThread( NULL, 0, ThreadHelper, test, 0, &thread_id ); if (helper == NULL) { printf( "Could not create helper thread number %d.\n", i ); return FALSE; } } result = test->sleep(4000); if (result != S_OK) { printf( "Multiple call failed on main thread: 0x%x\n", result ); return FALSE; } status = WaitForMultipleObjects( MAX_THREADS, helper, TRUE, INFINITE ); if (status == WAIT_FAILED) { printf( "Could not wait for helper threads to die: 0x%x\n", status ); return FALSE; } if (!Multicall_Test) { printf( "Multiple call failed on helper thread.\n" ); return FALSE; }
// See if methods can correctly call GetMessage.
another->interrupt( test, TRUE ); result = test->recurse_interrupt( this, 10 ); if (result != S_OK) { printf( "Recursive call with interrupts failed: 0x%x\n", result ); return FALSE; } another->interrupt( test, FALSE );
// Finally, its all over.
return TRUE; }
/***************************************************************************/ STDMETHODIMP CTest::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj) { if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITest)) { *ppvObj = (IUnknown *) this; AddRef(); return S_OK; } else if (IsEqualIID( riid, IID_IMarshal)) { if (custom == NULL) { custom = new CCMarshal; if (custom == NULL) return E_FAIL; } *ppvObj = (IMarshal *) custom; custom->AddRef(); return S_OK; } else { *ppvObj = NULL; return E_NOINTERFACE; } }
/***************************************************************************/ STDMETHODIMP_(ULONG) CTest::Release( THIS ) { if (InterlockedDecrement( (long*) &ref_count ) == 0) { WhatNext = quit_wn; wake_up_and_smell_the_roses(); delete this; return 0; } else return ref_count; }
/***************************************************************************/ STDMETHODIMP_(ULONG) CTestCF::AddRef( THIS ) { InterlockedIncrement( (long *) &ref_count ); return ref_count; }
/***************************************************************************/ CTestCF::CTestCF() { ref_count = 1; }
/***************************************************************************/ CTestCF::~CTestCF() { }
/***************************************************************************/ STDMETHODIMP CTestCF::CreateInstance( IUnknown FAR* pUnkOuter, REFIID iidInterface, void FAR* FAR* ppv) { *ppv = NULL; if (pUnkOuter != NULL) { return E_FAIL; }
if (!IsEqualIID( iidInterface, IID_ITest )) return E_NOINTERFACE;
CTest *Test = new FAR CTest();
if (Test == NULL) { return E_OUTOFMEMORY; }
*ppv = Test; return S_OK; }
/***************************************************************************/ STDMETHODIMP CTestCF::LockServer(BOOL fLock) { return E_FAIL; }
/***************************************************************************/ STDMETHODIMP CTestCF::QueryInterface( THIS_ REFIID riid, LPVOID FAR* ppvObj) { if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) { *ppvObj = (IUnknown *) this; AddRef(); return S_OK; }
*ppvObj = NULL; return E_NOINTERFACE; }
/***************************************************************************/ STDMETHODIMP_(ULONG) CTestCF::Release( THIS ) { if (InterlockedDecrement( (long*) &ref_count ) == 0) { delete this; return 0; } else return ref_count; }
/***************************************************************************/ void interrupt() { while (global_interrupt_test) { global_test->hello(); check_for_request(); } global_test->Release(); }
//+--------------------------------------------------------------
// Function: Main
//
// Synopsis: Executes the BasicBnd test
//
// Effects: None
//
//
// Returns: Exits with exit code 0 if success, 1 otherwise
//
// History: 05-Mar-92 Sarahj Created
//
//---------------------------------------------------------------
int _cdecl main(int argc, char *argv[]) { HRESULT result; DWORD wrong; BOOL success = TRUE; ITest *another = NULL; ITest *test = NULL; CTest *tester = new CTest;
// Initialize Globals.
MainThread = GetCurrentThreadId();
// Create an event for termination notification.
Done = CreateEvent( NULL, FALSE, FALSE, NULL ); if (Done == NULL) { printf( "Could not create event.\n" ); success = FALSE; goto exit_main; }
int len; TCHAR buffer[80];
// Look up the thread mode from the win.ini file.
len = GetProfileString( L"My Section", L"ThreadMode", L"MultiThreaded", buffer, sizeof(buffer) ); if (lstrcmp(buffer, L"SingleThreaded") == 0) { thread_mode = COINIT_SINGLETHREADED; wrong = COINIT_MULTITHREADED; printf( "Testing channel in single threaded mode.\n" ); } else if (lstrcmp(buffer, L"MultiThreaded") == 0) { thread_mode = COINIT_MULTITHREADED; wrong = COINIT_SINGLETHREADED; printf( "Testing channel in multithreaded mode.\n" ); }
// Initialize OLE.
result = OleInitializeEx(NULL, thread_mode); if (!SUCCEEDED(result)) { success = FALSE; printf( "OleInitializeEx failed: %x\n", result ); goto exit_main; } result = CoInitializeEx(NULL, thread_mode); if (!SUCCEEDED(result)) { success = FALSE; printf( "Recalling CoInitializeEx failed: %x\n", result ); goto exit_main; } result = CoInitializeEx(NULL, wrong); if (result == S_OK) { success = FALSE; printf( "Recalling CoInitializeEx with wrong thread mode succeeded: %x\n", result ); goto exit_main; } CoUninitialize(); CoUninitialize();
// If this is a server app, register and wait for a quit message.
if (argv[1] == NULL) server = FALSE; else server = strcmp( argv[1], "-Embedding" ) == 0; if (server) { success = server_loop( ); }
// Initialize and run the tests.
else { // Get a test object.
result = CoCreateInstance( CLSID_ITest, NULL, CLSCTX_LOCAL_SERVER, IID_ITest, (void **) &test ); if (!SUCCEEDED(result)) { printf( "Could not create instance of test server: %x\n", result ); success = FALSE; goto exit_main; }
// Get another test object.
result = CoCreateInstance( CLSID_ITest, NULL, CLSCTX_LOCAL_SERVER, IID_ITest, (void **) &another ); if (!SUCCEEDED(result)) { printf( "Could not create another instance of test server: %x\n", result ); success = FALSE; goto exit_main; }
success = tester->DoTest( test, another ); }
exit_main:
// Release the external test objects used.
if (test != NULL) test->Release(); if (another != NULL) another->Release();
// Release the internal test object.
tester->Release(); //wait_for_message();
OleUninitialize();
if (!server) if (success) printf("\nChannel Unit Test: PASSED\n"); else printf("\nChannel Unit Test: FAILED\n");
return !success; }
//+--------------------------------------------------------------
void check_for_request() { MSG msg;
if (thread_mode == COINIT_SINGLETHREADED) { if (PeekMessage( &msg, NULL, 0, 0, PM_REMOVE )) { TranslateMessage (&msg); DispatchMessage (&msg); } } }
//+--------------------------------------------------------------
BOOL server_loop( ) { HRESULT result; DWORD dwRegistration;
// Create our class factory
WhatNext = wait_wn; CTestCF *test_cf = new CTestCF();
// Register our class with OLE
result = CoRegisterClassObject(CLSID_ITest, test_cf, CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &dwRegistration); if (!SUCCEEDED(result)) { printf( "CoRegisterClassObject failed: %x\n", result ); return FALSE; }
// CoRegister bumps reference count so we don't have to!
test_cf->Release();
// Do whatever we have to do till it is time to pay our taxes and die.
while (WhatNext != quit_wn) switch (WhatNext) {
// Wait till a quit arrives.
case wait_wn: wait_for_message(); break;
case interrupt_wn: interrupt(); break; }
// Deregister out class - should release object as well
result = CoRevokeClassObject(dwRegistration); if (!SUCCEEDED(result)) { printf( "CoRevokeClassObject failed: %x\n", result ); return FALSE; }
return TRUE; }
/***************************************************************************/ DWORD _stdcall ThreadHelper( void *param ) { ITest *test = (ITest *) param; HRESULT result;
// Call the server.
result = test->sleep( 2000 );
// Check the result for single threaded mode.
if (thread_mode == COINIT_SINGLETHREADED) { if (SUCCEEDED(result)) { Multicall_Test = FALSE; printf( "Call succeeded on wrong thread in single threaded mode: 0x%x.\n", result ); } #if DBG==1
else if (DebugCoGetRpcFault() != RPC_E_ATTEMPTED_MULTITHREAD) { printf( "Multithread failure code was 0x%x not 0x%x\n", DebugCoGetRpcFault(), RPC_E_ATTEMPTED_MULTITHREAD ); Multicall_Test = FALSE; } #endif
}
// Check the result for multithreaded mode.
else if (result != S_OK) { printf( "Could not make multiple calls in multithreaded mode: 0x%x\n", result ); Multicall_Test = FALSE; }
#define DO_DA 42
return DO_DA; }
/***************************************************************************/ void wait_for_message() { MSG msg; DWORD status;
if (thread_mode == COINIT_MULTITHREADED) { status = WaitForSingleObject( Done, INFINITE ); if (status != WAIT_OBJECT_0 ) { printf( "Could not wait for event.\n" ); } } else { while (GetMessage( &msg, NULL, 0, 0 ) && msg.message != WM_USER) { TranslateMessage (&msg); DispatchMessage (&msg); } } }
/***************************************************************************/ void wake_up_and_smell_the_roses() { if (thread_mode == COINIT_MULTITHREADED) SetEvent( Done ); else PostThreadMessage(MainThread, WM_USER, 0, 0); }
|