Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1258 lines
35 KiB

/******************************************************************************
*
* 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<OBJECT_DATA*>(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<INTERFACE_LIST*>(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<DPTHREADPOOLOBJECT*>(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<DPTHREADPOOLOBJECT*>(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<INTERFACE_LIST*>(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<INTERFACE_LIST*>(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<void*>(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<INTERFACE_LIST*>(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<INTERFACE_LIST*>(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