/****************************************************************************** * * Copyright (C) 2001-2002 Microsoft Corporation. All Rights Reserved. * * File: threadpoolclassfac.cpp * * Content: DirectPlay Thread Pool class factory functions. * * History: * Date By Reason * ======== ======== ========= * 11/02/01 VanceO Created. * ******************************************************************************/ #include "dpnthreadpooli.h" //============================================================================= // Function type definitions //============================================================================= #ifndef DPNBUILD_LIBINTERFACE typedef STDMETHODIMP UnknownQueryInterface(IUnknown * pInterface, REFIID riid, LPVOID *ppvObj); typedef STDMETHODIMP_(ULONG) UnknownAddRef(IUnknown * pInterface); typedef STDMETHODIMP_(ULONG) UnknownRelease(IUnknown * pInterface); #endif // ! DPNBUILD_LIBINTERFACE #ifndef DPNBUILD_ONLYONETHREAD typedef STDMETHODIMP ThreadPoolQueryInterface(IDirectPlay8ThreadPool * pInterface, DP8REFIID riid, LPVOID *ppvObj); typedef STDMETHODIMP_(ULONG) ThreadPoolAddRef(IDirectPlay8ThreadPool * pInterface); typedef STDMETHODIMP_(ULONG) ThreadPoolRelease(IDirectPlay8ThreadPool * pInterface); #endif // ! DPNBUILD_ONLYONETHREAD #if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONETHREAD)) || (defined(DPNBUILD_MULTIPLETHREADPOOLS))) typedef STDMETHODIMP ThreadPoolWorkQueryInterface(IDirectPlay8ThreadPoolWork * pInterface, DP8REFIID riid, LPVOID *ppvObj); typedef STDMETHODIMP_(ULONG) ThreadPoolWorkAddRef(IDirectPlay8ThreadPoolWork * pInterface); typedef STDMETHODIMP_(ULONG) ThreadPoolWorkRelease(IDirectPlay8ThreadPoolWork * pInterface); #endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONETHREAD or DPNBUILD_MULTIPLETHREADPOOLS //============================================================================= // Function Prototypes //============================================================================= #ifndef DPNBUILD_LIBINTERFACE STDMETHODIMP DPTPCF_CreateInstance(IClassFactory * pInterface, LPUNKNOWN lpUnkOuter, REFIID riid, LPVOID * ppv); HRESULT DPTPCF_CreateInterface(OBJECT_DATA * pObject, REFIID riid, INTERFACE_LIST ** const ppv); HRESULT DPTPCF_CreateObject(IClassFactory * pInterface, LPVOID * ppv, REFIID riid); #endif // ! DPNBUILD_LIBINTERFACE HRESULT DPTPCF_FreeObject(PVOID pvObject); #ifndef DPNBUILD_LIBINTERFACE INTERFACE_LIST * DPTPCF_FindInterface(void * pvInterface, REFIID riid); #endif // ! DPNBUILD_LIBINTERFACE #if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONETHREAD) )|| (defined(DPNBUILD_MULTIPLETHREADPOOLS))) STDMETHODIMP DPTP_QueryInterface(void * pvInterface, DP8REFIID riid, void ** ppv); STDMETHODIMP_(ULONG) DPTP_AddRef(void * pvInterface); STDMETHODIMP_(ULONG) DPTP_Release(void * pvInterface); #endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONETHREAD or DPNBUILD_MULTIPLETHREADPOOLS //============================================================================= // External globals //============================================================================= #ifndef DPNBUILD_LIBINTERFACE IUnknownVtbl DPTP_UnknownVtbl = { (UnknownQueryInterface*) DPTP_QueryInterface, (UnknownAddRef*) DPTP_AddRef, (UnknownRelease*) DPTP_Release }; #endif // ! DPNBUILD_LIBINTERFACE #ifndef DPNBUILD_ONLYONETHREAD IDirectPlay8ThreadPoolVtbl DPTP_Vtbl = { (ThreadPoolQueryInterface*) DPTP_QueryInterface, (ThreadPoolAddRef*) DPTP_AddRef, (ThreadPoolRelease*) DPTP_Release, DPTP_Initialize, DPTP_Close, DPTP_GetThreadCount, DPTP_SetThreadCount, DPTP_DoWork, }; #endif // ! DPNBUILD_ONLYONETHREAD IDirectPlay8ThreadPoolWorkVtbl DPTPW_Vtbl = { #if ((! defined(DPNBUILD_LIBINTERFACE)) || (! defined(DPNBUILD_ONLYONETHREAD)) || (defined(DPNBUILD_MULTIPLETHREADPOOLS))) (ThreadPoolWorkQueryInterface*) DPTP_QueryInterface, (ThreadPoolWorkAddRef*) DPTP_AddRef, (ThreadPoolWorkRelease*) DPTP_Release, #endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONETHREAD or DPNBUILD_MULTIPLETHREADPOOLS DPTPW_QueueWorkItem, DPTPW_ScheduleTimer, DPTPW_StartTrackingFileIo, DPTPW_StopTrackingFileIo, DPTPW_CreateOverlapped, DPTPW_SubmitIoOperation, DPTPW_ReleaseOverlapped, DPTPW_CancelTimer, DPTPW_ResetCompletingTimer, DPTPW_WaitWhileWorking, DPTPW_SleepWhileWorking, DPTPW_RequestTotalThreadCount, DPTPW_GetThreadCount, DPTPW_GetWorkRecursionDepth, DPTPW_Preallocate, #ifdef DPNBUILD_MANDATORYTHREADS DPTPW_CreateMandatoryThread, #endif // DPNBUILD_MANDATORYTHREADS }; #ifndef DPNBUILD_LIBINTERFACE IClassFactoryVtbl DPTPCF_Vtbl = { DPCF_QueryInterface, // dplay8\common\classfactory.cpp will implement the rest of these DPCF_AddRef, DPCF_Release, DPTPCF_CreateInstance, DPCF_LockServer }; #undef DPF_MODNAME #define DPF_MODNAME "DPTPCF_CreateInstance" //============================================================================= // DPTPCF_CreateInstance //----------------------------------------------------------------------------- // // Description: Creates a new thread pool object COM instance. // // Arguments: // IClassFactory * pInterface - ? // LPUNKNOWN lpUnkOuter - ? // REFIID riid - ? // LPVOID * ppv - ? // // Returns: HRESULT //============================================================================= STDMETHODIMP DPTPCF_CreateInstance(IClassFactory * pInterface, LPUNKNOWN lpUnkOuter, REFIID riid, LPVOID * ppv) { HRESULT hResultCode; INTERFACE_LIST *pIntList; OBJECT_DATA *pObjectData; DPFX(DPFPREP, 6,"Parameters: pInterface [%p], lpUnkOuter [%p], riid [%p], ppv [%p]",pInterface,lpUnkOuter,&riid,ppv); if (pInterface == NULL) { DPFERR("Invalid COM interface specified"); hResultCode = E_INVALIDARG; goto Exit; } if (lpUnkOuter != NULL) { hResultCode = CLASS_E_NOAGGREGATION; goto Exit; } if (ppv == NULL) { DPFERR("Invalid target interface pointer specified"); hResultCode = E_INVALIDARG; goto Exit; } pObjectData = NULL; pIntList = NULL; if ((pObjectData = static_cast(DNMalloc(sizeof(OBJECT_DATA)))) == NULL) { DPFERR("Could not allocate object"); hResultCode = E_OUTOFMEMORY; goto Failure; } // Object creation and initialization if ((hResultCode = DPTPCF_CreateObject(pInterface, &pObjectData->pvData,riid)) != S_OK) { DPFERR("Could not create object"); goto Failure; } DPFX(DPFPREP, 7,"Created and initialized object"); // Get requested interface if ((hResultCode = DPTPCF_CreateInterface(pObjectData,riid,&pIntList)) != S_OK) { DPTPCF_FreeObject(pObjectData->pvData); goto Failure; } DPFX(DPFPREP, 7,"Found interface"); pObjectData->pIntList = pIntList; pObjectData->lRefCount = 1; DPTP_AddRef( pIntList ); DNInterlockedIncrement(&g_lDPTPInterfaceCount); *ppv = pIntList; DPFX(DPFPREP, 7,"*ppv = [0x%p]",*ppv); hResultCode = S_OK; Exit: DPFX(DPFPREP, 6,"Returning: [0x%lx]",hResultCode); return(hResultCode); Failure: if (pObjectData) { DNFree(pObjectData); pObjectData = NULL; } goto Exit; } // DPTPCF_CreateInstance #undef DPF_MODNAME #define DPF_MODNAME "DPTPCF_CreateInterface" //============================================================================= // DPTPCF_CreateInterface //----------------------------------------------------------------------------- // // Description: Creates a new thread pool object interface. // // Arguments: // OBJECT_DATA * pObject - ? // REFIID riid - ? // INTERFACE_LIST ** ppv - ? // // Returns: HRESULT //============================================================================= HRESULT DPTPCF_CreateInterface(OBJECT_DATA * pObject, REFIID riid, INTERFACE_LIST ** const ppv) { INTERFACE_LIST *pIntNew; PVOID lpVtbl; HRESULT hResultCode; DPFX(DPFPREP, 6,"Parameters: pObject [%p], riid [%p], ppv [%p]",pObject,&riid,ppv); DNASSERT(pObject != NULL); DNASSERT(ppv != NULL); const DPTHREADPOOLOBJECT* pDPTPObject = ((DPTHREADPOOLOBJECT *)pObject->pvData); if (IsEqualIID(riid,IID_IUnknown)) { DPFX(DPFPREP, 7,"riid = IID_IUnknown"); lpVtbl = &DPTP_UnknownVtbl; } else if (IsEqualIID(riid,IID_IDirectPlay8ThreadPool)) { DPFX(DPFPREP, 7,"riid = IID_IDirectPlay8ThreadPool"); lpVtbl = &DPTP_Vtbl; } else if (IsEqualIID(riid,IID_IDirectPlay8ThreadPoolWork)) { DPFX(DPFPREP, 7,"riid = IID_IDirectPlay8ThreadPoolWork"); lpVtbl = &DPTPW_Vtbl; } else { DPFERR("riid not found !"); hResultCode = E_NOINTERFACE; goto Exit; } if ((pIntNew = static_cast(DNMalloc(sizeof(INTERFACE_LIST)))) == NULL) { DPFERR("Could not allocate interface"); hResultCode = E_OUTOFMEMORY; goto Exit; } pIntNew->lpVtbl = lpVtbl; pIntNew->lRefCount = 0; pIntNew->pIntNext = NULL; DBG_CASSERT( sizeof( pIntNew->iid ) == sizeof( riid ) ); memcpy( &(pIntNew->iid), &riid, sizeof( pIntNew->iid ) ); pIntNew->pObject = pObject; *ppv = pIntNew; DPFX(DPFPREP, 7,"*ppv = [0x%p]",*ppv); hResultCode = S_OK; Exit: DPFX(DPFPREP, 6,"Returning: hResultCode = [%lx]",hResultCode); return(hResultCode); } // DPTPCF_CreateInterface #endif // ! DPNBUILD_LIBINTERFACE #undef DPF_MODNAME #define DPF_MODNAME "DPTPCF_CreateObject" //============================================================================= // DPTPCF_CreateObject //----------------------------------------------------------------------------- // // Description: Creates a new thread pool object. // // Arguments: // IClassFactory * pInterface - ? // PVOID * ppv - ? // REFIID riid - ? // // Returns: HRESULT //============================================================================= #ifdef DPNBUILD_LIBINTERFACE HRESULT DPTPCF_CreateObject(PVOID * ppv) #else // ! DPNBUILD_LIBINTERFACE HRESULT DPTPCF_CreateObject(IClassFactory * pInterface, PVOID * ppv, REFIID riid) #endif // ! DPNBUILD_LIBINTERFACE { HRESULT hr; DPTHREADPOOLOBJECT * pDPTPObject = NULL; #ifndef DPNBUILD_LIBINTERFACE const _IDirectPlayClassFactory * pDPClassFactory = (_IDirectPlayClassFactory*) pInterface; #endif // ! DPNBUILD_LIBINTERFACE BOOL fHaveGlobalThreadPoolLock = FALSE; BOOL fInittedLock = FALSE; #ifdef DPNBUILD_ONLYONEPROCESSOR BOOL fInittedWorkQueue = FALSE; #else // ! DPNBUILD_ONLYONEPROCESSOR SYSTEM_INFO SystemInfo; DWORD dwTemp; #endif // ! DPNBUILD_ONLYONEPROCESSOR #ifndef DPNBUILD_ONLYONETHREAD DWORD dwWorkerThreadTlsIndex = -1; #ifdef DBG DWORD dwError; #endif // DBG #endif // ! DPNBUILD_ONLYONETHREAD #ifndef DPNBUILD_LIBINTERFACE if ((riid != IID_IDirectPlay8ThreadPool) && (riid != IID_IDirectPlay8ThreadPoolWork)) { DPFX(DPFPREP, 0, "Requesting unknown interface from thread pool CLSID!"); hr = E_NOINTERFACE; goto Failure; } #endif // ! DPNBUILD_LIBINTERFACE #ifndef DPNBUILD_MULTIPLETHREADPOOLS // // See if we've already allocated a thread pool object, because you only // get one per process. // DNEnterCriticalSection(&g_csGlobalThreadPoolLock); fHaveGlobalThreadPoolLock = TRUE; #if ((defined(DPNBUILD_LIBINTERFACE)) && (defined(DPNBUILD_ONLYONETHREAD))) DNASSERT(g_pDPTPObject == NULL); #else // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONETHREAD if (g_pDPTPObject != NULL) { LONG lRefCount; #ifdef DPNBUILD_LIBINTERFACE DNASSERT(g_pDPTPObject->lRefCount >= 0); lRefCount = DNInterlockedIncrement(&g_pDPTPObject->lRefCount); #else // ! DPNBUILD_LIBINTERFACE lRefCount = ++g_dwDPTPRefCount; #endif // ! DPNBUILD_LIBINTERFACE DPFX(DPFPREP, 1, "Global thread pool object 0x%p already exists, ref count now %u.", g_pDPTPObject, lRefCount); (*ppv) = g_pDPTPObject; hr = S_OK; goto Exit; } #endif // ! DPNBUILD_LIBINTERFACE or ! DPNBUILD_ONLYONETHREAD #endif // ! DPNBUILD_MULTIPLETHREADPOOLS pDPTPObject = (DPTHREADPOOLOBJECT*) DNMalloc(sizeof(DPTHREADPOOLOBJECT)); if (pDPTPObject == NULL) { DPFX(DPFPREP, 0, "Couldn't allocate memory for thread pool object!"); hr = E_OUTOFMEMORY; goto Failure; } // // Zero out the entire structure to start. // memset(pDPTPObject, 0, sizeof(DPTHREADPOOLOBJECT)); pDPTPObject->Sig[0] = 'D'; pDPTPObject->Sig[1] = 'P'; pDPTPObject->Sig[2] = 'T'; pDPTPObject->Sig[3] = 'P'; #ifndef DPNBUILD_NOPARAMVAL // // Start by assuming the user will want parameter validation. // pDPTPObject->dwFlags = DPTPOBJECTFLAG_USER_PARAMVALIDATION; #endif // ! DPNBUILD_NOPARAMVAL #ifndef DPNBUILD_ONLYONEPROCESSOR GetSystemInfo(&SystemInfo); pDPTPObject->dwNumCPUs = SystemInfo.dwNumberOfProcessors; #endif // ! DPNBUILD_ONLYONEPROCESSOR #ifndef DPNBUILD_ONLYONETHREAD pDPTPObject->dwTotalUserThreadCount = -1; pDPTPObject->dwTotalDesiredWorkThreadCount = -1; pDPTPObject->dwWorkRecursionCountTlsIndex = -1; pDPTPObject->lNumThreadCountChangeWaiters = 0; #if ((defined(DPNBUILD_MANDATORYTHREADS)) && (defined(DBG))) pDPTPObject->blMandatoryThreads.Initialize(); #endif // DPNBUILD_MANDATORYTHREADS and DBG // // Allocate Thread Local Storage for tracking recursion on non-worker // threads. // pDPTPObject->dwWorkRecursionCountTlsIndex = TlsAlloc(); if (pDPTPObject->dwWorkRecursionCountTlsIndex == -1) { #ifdef DBG dwError = GetLastError(); DPFX(DPFPREP, 0, "Couldn't allocate Thread Local Storage slot for tracking recursion on non-worker threads (err = %u)!", dwError); #endif // DBG hr = E_OUTOFMEMORY; goto Failure; } // // Allocate Thread Local Storage for tracking worker threads. // dwWorkerThreadTlsIndex = TlsAlloc(); if (dwWorkerThreadTlsIndex == -1) { #ifdef DBG dwError = GetLastError(); DPFX(DPFPREP, 0, "Couldn't allocate Thread Local Storage slot for tracking worker threads (err = %u)!", dwError); #endif // DBG hr = E_OUTOFMEMORY; goto Failure; } // // Create a semaphore to release threads waiting on another thread changing // the thread count. // pDPTPObject->hThreadCountChangeComplete = DNCreateSemaphore(NULL, 0, 0xFFFF, NULL); if (pDPTPObject->hThreadCountChangeComplete == NULL) { #ifdef DBG dwError = GetLastError(); DPFX(DPFPREP, 0, "Couldn't create thread count change complete semaphore (err = %u)!", dwError); #endif // DBG hr = E_OUTOFMEMORY; goto Failure; } #endif // ! DPNBUILD_ONLYONETHREAD #ifdef DPNBUILD_ONLYONEPROCESSOR #ifdef DPNBUILD_ONLYONETHREAD hr = InitializeWorkQueue(&pDPTPObject->WorkQueue); #else // ! DPNBUILD_ONLYONETHREAD hr = InitializeWorkQueue(&pDPTPObject->WorkQueue, NULL, NULL, dwWorkerThreadTlsIndex); #endif // ! DPNBUILD_ONLYONETHREAD if (hr != DPN_OK) { DPFX(DPFPREP, 0, "Couldn't initialize work queue!"); goto Failure; } fInittedWorkQueue = TRUE; #else // ! DPNBUILD_ONLYONEPROCESSOR // // Allocate the array of work queues pointers, one for each processor. // pDPTPObject->papCPUWorkQueues = (DPTPWORKQUEUE**) DNMalloc(NUM_CPUS(pDPTPObject) * sizeof(DPTPWORKQUEUE*)); if (pDPTPObject->papCPUWorkQueues == NULL) { DPFX(DPFPREP, 0, "Couldn't allocate memory for array of work queue pointers!"); hr = E_OUTOFMEMORY; goto Failure; } // // Initialize each of the work queues. // for(dwTemp = 0; dwTemp < NUM_CPUS(pDPTPObject); dwTemp++) { #ifdef DPNBUILD_USEIOCOMPLETIONPORTS if (dwTemp > 0) { pDPTPObject->papCPUWorkQueues[dwTemp] = pDPTPObject->papCPUWorkQueues[0]; } else #endif // DPNBUILD_USEIOCOMPLETIONPORTS { // // Allocate the actual work queues object. // pDPTPObject->papCPUWorkQueues[dwTemp] = (DPTPWORKQUEUE*) DNMalloc(sizeof(DPTPWORKQUEUE)); if (pDPTPObject->papCPUWorkQueues[dwTemp] == NULL) { DPFX(DPFPREP, 0, "Couldn't allocate memory for work queue %u!", dwTemp); hr = E_OUTOFMEMORY; goto Failure; } #ifdef DPNBUILD_ONLYONETHREAD hr = InitializeWorkQueue(WORKQUEUE_FOR_CPU(pDPTPObject, dwTemp), dwTemp); #else // ! DPNBUILD_ONLYONETHREAD hr = InitializeWorkQueue(WORKQUEUE_FOR_CPU(pDPTPObject, dwTemp), dwTemp, NULL, NULL, dwWorkerThreadTlsIndex); #endif // ! DPNBUILD_ONLYONETHREAD if (hr != DPN_OK) { DPFX(DPFPREP, 0, "Couldn't intialize work queue %u!", dwTemp); DNFree(pDPTPObject->papCPUWorkQueues[dwTemp]); pDPTPObject->papCPUWorkQueues[dwTemp] = NULL; goto Failure; } } } #endif // ! DPNBUILD_ONLYONEPROCESSOR if (! DNInitializeCriticalSection(&pDPTPObject->csLock)) { DPFX(DPFPREP, 0, "Couldn't initialize object lock!"); hr = E_OUTOFMEMORY; goto Failure; } fInittedLock = TRUE; #ifdef DPNBUILD_LIBINTERFACE // // For lib interface builds, the Vtbl and reference are embedded in the // object directly. // #ifdef DPNBUILD_ONLYONETHREAD pDPTPObject->lpVtbl = &DPTPW_Vtbl; #ifdef DPNBUILD_MULTIPLETHREADPOOLS pDPTPObject->lRefCount = 1; #endif // DPNBUILD_MULTIPLETHREADPOOLS #else // ! DPNBUILD_ONLYONETHREAD // We assume only the work interface is created. The ID will have to be // passed in or something (see DNCF_CreateObject). #pragma error("Building with DPNBUILD_LIBINTERFACE but not DPNBUILD_ONLYONETHREAD requires minor changes") #endif // ! DPNBUILD_ONLYONETHREAD #endif // DPNBUILD_LIBINTERFACE #ifndef DPNBUILD_MULTIPLETHREADPOOLS // // Store this as the only object allowed in this process. // g_pDPTPObject = pDPTPObject; #ifndef DPNBUILD_LIBINTERFACE g_dwDPTPRefCount++; #endif // ! DPNBUILD_LIBINTERFACE #endif // ! DPNBUILD_MULTIPLETHREADPOOLS DPFX(DPFPREP, 2, "Created object 0x%p.", pDPTPObject); (*ppv) = pDPTPObject; Exit: #ifndef DPNBUILD_MULTIPLETHREADPOOLS // // See if we've already allocated a thread pool object, because you only // get one per process. // if (fHaveGlobalThreadPoolLock) { DNLeaveCriticalSection(&g_csGlobalThreadPoolLock); fHaveGlobalThreadPoolLock = FALSE; } #endif // ! DPNBUILD_MULTIPLETHREADPOOLS return hr; Failure: if (pDPTPObject != NULL) { if (fInittedLock) { DNDeleteCriticalSection(&pDPTPObject->csLock); fInittedLock = FALSE; } #ifdef DPNBUILD_ONLYONEPROCESSOR if (fInittedWorkQueue) { DeinitializeWorkQueue(&pDPTPObject->WorkQueue); fInittedWorkQueue = FALSE; } #else // ! DPNBUILD_ONLYONEPROCESSOR if (pDPTPObject->papCPUWorkQueues != NULL) { #ifdef DPNBUILD_USEIOCOMPLETIONPORTS dwTemp = 0; #else // ! DPNBUILD_USEIOCOMPLETIONPORTS for(dwTemp = 0; dwTemp < NUM_CPUS(pDPTPObject); dwTemp++) #endif // ! DPNBUILD_USEIOCOMPLETIONPORTS { if (WORKQUEUE_FOR_CPU(pDPTPObject, dwTemp) != NULL) { DeinitializeWorkQueue(WORKQUEUE_FOR_CPU(pDPTPObject, dwTemp)); DNFree(pDPTPObject->papCPUWorkQueues[dwTemp]); } } DNFree(pDPTPObject->papCPUWorkQueues); pDPTPObject->papCPUWorkQueues = NULL; } #endif // ! DPNBUILD_ONLYONEPROCESSOR #ifndef DPNBUILD_ONLYONETHREAD if (pDPTPObject->hThreadCountChangeComplete != NULL) { DNCloseHandle(pDPTPObject->hThreadCountChangeComplete); pDPTPObject->hThreadCountChangeComplete = NULL; } if (dwWorkerThreadTlsIndex != -1) { TlsFree(dwWorkerThreadTlsIndex); dwWorkerThreadTlsIndex = -1; } if (pDPTPObject->dwWorkRecursionCountTlsIndex != -1) { TlsFree(pDPTPObject->dwWorkRecursionCountTlsIndex); pDPTPObject->dwWorkRecursionCountTlsIndex = -1; } #endif // ! DPNBUILD_ONLYONETHREAD DNFree(pDPTPObject); pDPTPObject = NULL; } goto Exit; } // DPTPCF_CreateObject #if ((defined(DPNBUILD_LIBINTERFACE)) && (defined(DPNBUILD_ONLYONETHREAD)) && (! defined(DPNBUILD_MULTIPLETHREADPOOLS))) #undef DPF_MODNAME #define DPF_MODNAME "DPTPCF_GetObject" //============================================================================= // DPTPCF_GetObject //----------------------------------------------------------------------------- // // Description: Gets a pointer to the global thread pool object. // // Arguments: // PVOID * ppv - ? // // Returns: None //============================================================================= void DPTPCF_GetObject(PVOID * ppv) { (*ppv) = g_pDPTPObject; } // DPTPCF_GetObject #endif // DPNBUILD_LIBINTERFACE DPNBUILD_ONLYONETHREAD and ! DPNBUILD_MULTIPLETHREADPOOLS #undef DPF_MODNAME #define DPF_MODNAME "DPTPCF_FreeObject" //============================================================================= // DPTPCF_FreeObject //----------------------------------------------------------------------------- // // Description: Frees an existing thread pool object. // // Arguments: // PVOID pvObject - ? // // Returns: HRESULT //============================================================================= HRESULT DPTPCF_FreeObject(PVOID pvObject) { DPTHREADPOOLOBJECT * pDPTPObject = (DPTHREADPOOLOBJECT*) pvObject; #ifndef DPNBUILD_ONLYONEPROCESSOR DWORD dwTemp; #endif // ! DPNBUILD_ONLYONEPROCESSOR #ifndef DPNBUILD_ONLYONETHREAD DWORD dwWorkerThreadTlsIndex; #endif // ! DPNBUILD_ONLYONETHREAD DPFX(DPFPREP, 4, "Parameters: (0x%p)", pvObject); #ifndef DPNBUILD_MULTIPLETHREADPOOLS DNEnterCriticalSection(&g_csGlobalThreadPoolLock); DNASSERT(pDPTPObject == g_pDPTPObject); #ifdef DPNBUILD_LIBINTERFACE #ifndef DPNBUILD_ONLYONETHREAD // // It's possible somebody just took a reference on the object, so we may // need to bail. // DNASSERT(pDPTPObject->lRefCount >= 0); if (pDPTPObject->lRefCount > 0) { DPFX(DPFPREP, 1, "Global thread pool object 0x%p just got referenced (refcount now %i), not destroying.", g_pDPTPObject, pDPTPObject->lRefCount); DNLeaveCriticalSection(&g_csGlobalThreadPoolLock); return S_OK; } #endif // ! DPNBUILD_ONLYONETHREAD #else // ! DPNBUILD_LIBINTERFACE // // Reduce the global object count. There might be other users, though. // g_dwDPTPRefCount--; if (g_dwDPTPRefCount != 0) { DPFX(DPFPREP, 1, "Global thread pool object 0x%p still has other users, refcount now %u.", g_pDPTPObject, g_dwDPTPRefCount); DNLeaveCriticalSection(&g_csGlobalThreadPoolLock); return S_OK; } #endif // ! DPNBUILD_LIBINTERFACE g_pDPTPObject = NULL; DNLeaveCriticalSection(&g_csGlobalThreadPoolLock); #endif // ! DPNBUILD_MULTIPLETHREADPOOLS // // Double check to make sure the object is closed. // if (pDPTPObject->dwFlags & DPTPOBJECTFLAG_USER_INITIALIZED) { DPFX(DPFPREP, 0, "User has not closed IDirectPlay8ThreadPool interface!"); DNASSERT(FALSE); // // Forcefully mark the user's interface as no longer available. // pDPTPObject->dwFlags &= ~DPTPOBJECTFLAG_USER_INITIALIZED; } #ifdef DPNBUILD_LIBINTERFACE // // For lib interface builds, the reference is embedded in the object // directly. // #if ((! defined(DPNBUILD_ONLYONETHREAD)) || (defined(DPNBUILD_MULTIPLETHREADPOOLS))) DNASSERT(pDPTPObject->lRefCount == 0); #endif // ! DPNBUILD_ONLYONETHREAD or DPNBUILD_MULTIPLETHREADPOOLS #endif // DPNBUILD_LIBINTERFACE #ifndef DPNBUILD_ONLYONETHREAD // // Save the Thread Local Storage index value before cleaning up the work // queues. Since all work queues share the same TLS index, just use the // first CPU as representative of all of them. // dwWorkerThreadTlsIndex = (WORKQUEUE_FOR_CPU(pDPTPObject, 0))->dwWorkerThreadTlsIndex; #endif // ! DPNBUILD_ONLYONETHREAD DNDeleteCriticalSection(&pDPTPObject->csLock); #ifdef DPNBUILD_ONLYONEPROCESSOR DeinitializeWorkQueue(&pDPTPObject->WorkQueue); #else // ! DPNBUILD_ONLYONEPROCESSOR #ifdef DPNBUILD_USEIOCOMPLETIONPORTS dwTemp = 0; #else // ! DPNBUILD_USEIOCOMPLETIONPORTS for(dwTemp = 0; dwTemp < NUM_CPUS(pDPTPObject); dwTemp++) #endif // ! DPNBUILD_USEIOCOMPLETIONPORTS { DeinitializeWorkQueue(WORKQUEUE_FOR_CPU(pDPTPObject, dwTemp)); DNFree(pDPTPObject->papCPUWorkQueues[dwTemp]); } DNFree(pDPTPObject->papCPUWorkQueues); pDPTPObject->papCPUWorkQueues = NULL; #endif // ! DPNBUILD_ONLYONEPROCESSOR #ifndef DPNBUILD_ONLYONETHREAD // // Close the thread count change complete semaphore. // DNASSERT(pDPTPObject->lNumThreadCountChangeWaiters == 0); DNCloseHandle(pDPTPObject->hThreadCountChangeComplete); pDPTPObject->hThreadCountChangeComplete = NULL; // // Free the Thread Local Storage slot for tracking worker threads. // TlsFree(dwWorkerThreadTlsIndex); dwWorkerThreadTlsIndex = -1; // // Free the Thread Local Storage slot for tracking recursion on non-worker // threads. // TlsFree(pDPTPObject->dwWorkRecursionCountTlsIndex); pDPTPObject->dwWorkRecursionCountTlsIndex = -1; #ifdef DPNBUILD_MANDATORYTHREADS DNASSERT(pDPTPObject->dwMandatoryThreadCount == 0); #endif // DPNBUILD_MANDATORYTHREADS #endif // ! DPNBUILD_ONLYONETHREAD // // Make sure there aren't any flags set except possibly // USER_PARAMVALIDATION. // DNASSERT(! (pDPTPObject->dwFlags & ~(DPTPOBJECTFLAG_USER_PARAMVALIDATION))); DNFree(pDPTPObject); pDPTPObject = NULL; DPFX(DPFPREP, 4, "Returning: [S_OK]"); return S_OK; } // DPTPCF_FreeObject #ifdef DPNBUILD_LIBINTERFACE #if ((! defined(DPNBUILD_ONLYONETHREAD)) || (defined(DPNBUILD_MULTIPLETHREADPOOLS))) #undef DPF_MODNAME #define DPF_MODNAME "DPTP_QueryInterface" //============================================================================= // DPTP_QueryInterface //----------------------------------------------------------------------------- // // Description: Queries for a new interface for an existing object. // // Arguments: // void * pvInterface - ? // DP8REFIID riid - ? // void ** ppv - ? // // Returns: HRESULT //============================================================================= STDMETHODIMP DPTP_QueryInterface(void * pvInterface, DP8REFIID riid, void ** ppv) { HRESULT hResultCode; DPFX(DPFPREP, 2,"Parameters: pvInterface [0x%p], riid [0x%p], ppv [0x%p]",pvInterface,&riid,ppv); // // Get the object Vtbl and make sure it's one of ours // if (*((PVOID*) pvInterface) == (&DPTPW_Vtbl)) { // // It is one of our objects. Assume the IID is not specified, so just // return a reference to the existing object. // DNASSERT(riid == 0); hResultCode = S_OK; DPTP_AddRef(pvInterface); *ppv = pvInterface; } else { DPFX(DPFPREP, 0, "Invalid object!"); hResultCode = E_POINTER; } DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode); } // DPTP_QueryInterface #undef DPF_MODNAME #define DPF_MODNAME "DPTP_AddRef" //============================================================================= // DPTP_AddRef //----------------------------------------------------------------------------- // // Description: Adds a reference to a thread pool interface. // // Arguments: // void * pvInterface - ? // // Returns: ULONG //============================================================================= STDMETHODIMP_(ULONG) DPTP_AddRef(void * pvInterface) { DPTHREADPOOLOBJECT * pDPTPObject; LONG lRefCount; DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p]",pvInterface); #ifndef DPNBUILD_NOPARAMVAL if (pvInterface == NULL) { DPFERR("Invalid COM interface specified"); lRefCount = 0; goto Exit; } #endif // ! DPNBUILD_NOPARAMVAL pDPTPObject = static_cast(pvInterface); lRefCount = DNInterlockedIncrement(&pDPTPObject->lRefCount); DNASSERT(lRefCount > 0); DPFX(DPFPREP, 5,"New lRefCount [%ld]",lRefCount); #ifndef DPNBUILD_NOPARAMVAL Exit: #endif // ! DPNBUILD_NOPARAMVAL DPFX(DPFPREP, 2,"Returning: lRefCount [%ld]",lRefCount); return(lRefCount); } // DPTP_AddRef #undef DPF_MODNAME #define DPF_MODNAME "DPTP_Release" //============================================================================= // DPTP_Release //----------------------------------------------------------------------------- // // Description: Removes a reference from a thread pool interface. If it is // the last reference on the object, the object is destroyed. // // Arguments: // void * pvInterface - ? // // Returns: ULONG //============================================================================= STDMETHODIMP_(ULONG) DPTP_Release(void * pvInterface) { DPTHREADPOOLOBJECT * pDPTPObject; LONG lRefCount; DPFX(DPFPREP, 2,"Parameters: pInterface [%p]",pvInterface); #ifndef DPNBUILD_NOPARAMVAL if (pvInterface == NULL) { DPFERR("Invalid COM interface specified"); lRefCount = 0; goto Exit; } #endif // ! DPNBUILD_NOPARAMVAL pDPTPObject = static_cast(pvInterface); DNASSERT(pDPTPObject->lRefCount > 0); lRefCount = DNInterlockedDecrement(&pDPTPObject->lRefCount); DPFX(DPFPREP, 5,"New lRefCount [%ld]",lRefCount); if (lRefCount == 0) { // Free object here DPFX(DPFPREP, 5,"Free object"); DPTPCF_FreeObject(pvInterface); } #ifndef DPNBUILD_NOPARAMVAL Exit: #endif // ! DPNBUILD_NOPARAMVAL DPFX(DPFPREP, 2,"Returning: lRefCount [%ld]",lRefCount); return(lRefCount); } // DPTP_Release #endif // ! DPNBUILD_ONLYONETHREAD or DPNBUILD_MULTIPLETHREADPOOLS #else // ! DPNBUILD_LIBINTERFACE #undef DPF_MODNAME #define DPF_MODNAME "DPTPCF_FindInterface" //============================================================================= // DPTPCF_FindInterface //----------------------------------------------------------------------------- // // Description: Locates an interface for a given object. // // Initialize must have been called. // // Arguments: // void * pvInterface - ? // REFIID riid - ? // // Returns: HRESULT //============================================================================= INTERFACE_LIST * DPTPCF_FindInterface(void * pvInterface, REFIID riid) { INTERFACE_LIST * pInterfaceList; DPFX(DPFPREP, 6,"Parameters: (0x%p, 0x%p)", pvInterface, &riid); DNASSERT(pvInterface != NULL); pInterfaceList = (static_cast(pvInterface))->pObject->pIntList; // Find first interface while (pInterfaceList != NULL) { if (IsEqualIID(riid, pInterfaceList->iid)) { break; } pInterfaceList = pInterfaceList->pIntNext; } DPFX(DPFPREP, 6,"Returning: [0x%p]", pInterfaceList); return pInterfaceList; } // DPTPCF_FindInterface #undef DPF_MODNAME #define DPF_MODNAME "DPTP_QueryInterface" //============================================================================= // DPTP_QueryInterface //----------------------------------------------------------------------------- // // Description: Queries for a new interface for an existing object. // // Arguments: // void * pvInterface - ? // REFIID riid - ? // void ** ppv - ? // // Returns: HRESULT //============================================================================= STDMETHODIMP DPTP_QueryInterface(void * pvInterface, DP8REFIID riid, void ** ppv) { INTERFACE_LIST *pIntList; INTERFACE_LIST *pIntNew; HRESULT hResultCode; DPFX(DPFPREP, 2,"Parameters: pvInterface [0x%p], riid [0x%p], ppv [0x%p]",pvInterface,&riid,ppv); #ifndef DPNBUILD_NOPARAMVAL if (pvInterface == NULL) { DPFERR("Invalid COM interface specified"); hResultCode = E_INVALIDARG; goto Exit; } if (ppv == NULL) { DPFERR("Invalid target interface pointer specified"); hResultCode = E_POINTER; goto Exit; } #endif // ! DPNBUILD_NOPARAMVAL if ((pIntList = DPTPCF_FindInterface(pvInterface,riid)) == NULL) { // Interface must be created pIntList = (static_cast(pvInterface))->pObject->pIntList; if ((hResultCode = DPTPCF_CreateInterface(pIntList->pObject,riid,&pIntNew)) != S_OK) { goto Exit; } pIntNew->pIntNext = pIntList; pIntList->pObject->pIntList = pIntNew; pIntList = pIntNew; } if (pIntList->lRefCount == 0) // New interface exposed { DNInterlockedIncrement(&pIntList->pObject->lRefCount); } DNInterlockedIncrement(&pIntList->lRefCount); *ppv = static_cast(pIntList); DPFX(DPFPREP, 5,"*ppv = [0x%p]", *ppv); hResultCode = S_OK; Exit: DPFX(DPFPREP, 2,"Returning: [0x%lx]",hResultCode); return(hResultCode); } // DPTP_QueryInterface #undef DPF_MODNAME #define DPF_MODNAME "DPTP_AddRef" //============================================================================= // DPTP_AddRef //----------------------------------------------------------------------------- // // Description: Adds a reference to a thread pool interface. // // Arguments: // void * pvInterface - ? // // Returns: ULONG //============================================================================= STDMETHODIMP_(ULONG) DPTP_AddRef(void * pvInterface) { INTERFACE_LIST *pIntList; LONG lRefCount; DPFX(DPFPREP, 2,"Parameters: pInterface [0x%p]",pvInterface); #ifndef DPNBUILD_NOPARAMVAL if (pvInterface == NULL) { DPFERR("Invalid COM interface specified"); lRefCount = 0; goto Exit; } #endif // ! DPNBUILD_NOPARAMVAL pIntList = static_cast(pvInterface); lRefCount = DNInterlockedIncrement(&pIntList->lRefCount); DPFX(DPFPREP, 5,"New lRefCount [%ld]",lRefCount); #ifndef DPNBUILD_NOPARAMVAL Exit: #endif // !DPNBUILD_NOPARAMVAL DPFX(DPFPREP, 2,"Returning: lRefCount [%ld]",lRefCount); return(lRefCount); } // DPTP_AddRef #undef DPF_MODNAME #define DPF_MODNAME "DPTP_Release" //============================================================================= // DPTP_Release //----------------------------------------------------------------------------- // // Description: Removes a reference from a thread pool interface. If it is // the last reference on the object, the object is destroyed. // // Arguments: // void * pvInterface - ? // // Returns: ULONG //============================================================================= STDMETHODIMP_(ULONG) DPTP_Release(void * pvInterface) { INTERFACE_LIST *pIntList; INTERFACE_LIST *pIntCurrent; LONG lRefCount; LONG lObjRefCount; DPFX(DPFPREP, 2,"Parameters: pInterface [%p]",pvInterface); #ifndef DPNBUILD_NOPARAMVAL if (pvInterface == NULL) { DPFERR("Invalid COM interface specified"); lRefCount = 0; goto Exit; } #endif // ! DPNBUILD_NOPARAMVAL pIntList = static_cast(pvInterface); lRefCount = DNInterlockedDecrement( &pIntList->lRefCount ); DPFX(DPFPREP, 5,"New lRefCount [%ld]",lRefCount); if (lRefCount == 0) { // // Decrease object's interface count // lObjRefCount = DNInterlockedDecrement( &pIntList->pObject->lRefCount ); // // Free object and interfaces // if (lObjRefCount == 0) { // Free object here DPFX(DPFPREP, 5,"Free object"); DPTPCF_FreeObject(pIntList->pObject->pvData); pIntList = pIntList->pObject->pIntList; // Get head of interface list DNFree(pIntList->pObject); // Free Interfaces DPFX(DPFPREP, 5,"Free interfaces"); while(pIntList != NULL) { pIntCurrent = pIntList; pIntList = pIntList->pIntNext; DNFree(pIntCurrent); } DNInterlockedDecrement(&g_lDPTPInterfaceCount); } } #ifndef DPNBUILD_NOPARAMVAL Exit: #endif // ! DPNBUILD_NOPARAMVAL DPFX(DPFPREP, 2,"Returning: lRefCount [%ld]",lRefCount); return(lRefCount); } // DPTP_Release #endif // ! DPNBUILD_LIBINTERFACE