1013 lines
23 KiB
C++
1013 lines
23 KiB
C++
/***************************************************************************
|
|
*
|
|
* Copyright (C) 2001 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: dp8simworkerthread.cpp
|
|
*
|
|
* Content: DP8SIM worker thread functions.
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ======== ======== =========
|
|
* 04/23/01 VanceO Created.
|
|
*
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "dp8simi.h"
|
|
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// Globals
|
|
//=============================================================================
|
|
LONG g_lWorkerThreadRefCount = 0; // number of times worker thread has been started
|
|
DNCRITICAL_SECTION g_csJobQueueLock; // lock protecting the job queue
|
|
CBilink g_blJobQueue; // list of jobs to be performed
|
|
HANDLE g_hWorkerThreadJobEvent = NULL; // event to signal when worker thread has a new job
|
|
HANDLE g_hWorkerThread = NULL; // handle to worker thread
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// Prototypes
|
|
//=============================================================================
|
|
DWORD DP8SimWorkerThreadProc(PVOID pvParameter);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "StartGlobalWorkerThread"
|
|
//=============================================================================
|
|
// StartGlobalWorkerThread
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Starts the global worker thread if it hasn't already been
|
|
// started. Each successful call to this function must be
|
|
// balanced by a call to StopGlobalWorkerThread.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
HRESULT StartGlobalWorkerThread(void)
|
|
{
|
|
HRESULT hr = DPN_OK;
|
|
DWORD dwThreadID;
|
|
BOOL fInittedCriticalSection = FALSE;
|
|
|
|
|
|
DPFX(DPFPREP, 5, "Enter");
|
|
|
|
|
|
DNEnterCriticalSection(&g_csGlobalsLock);
|
|
|
|
DNASSERT(g_lWorkerThreadRefCount >= 0);
|
|
if (g_lWorkerThreadRefCount == 0)
|
|
{
|
|
//
|
|
// This is the first worker thread user.
|
|
//
|
|
|
|
|
|
if (! DNInitializeCriticalSection(&g_csJobQueueLock))
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed initializing job queue critical section!");
|
|
hr = DPNERR_GENERIC;
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// Don't allow critical section re-entry.
|
|
//
|
|
DebugSetCriticalSectionRecursionCount(&g_csJobQueueLock, 0);
|
|
|
|
|
|
fInittedCriticalSection = TRUE;
|
|
|
|
g_blJobQueue.Initialize();
|
|
|
|
|
|
//
|
|
// Create the new job notification event.
|
|
//
|
|
g_hWorkerThreadJobEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (g_hWorkerThreadJobEvent == NULL)
|
|
{
|
|
hr = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed creating worker thread job event!");
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// Create the thread.
|
|
//
|
|
g_hWorkerThread = CreateThread(NULL,
|
|
0,
|
|
DP8SimWorkerThreadProc,
|
|
NULL,
|
|
0,
|
|
&dwThreadID);
|
|
if (g_hWorkerThread == NULL)
|
|
{
|
|
hr = GetLastError();
|
|
DPFX(DPFPREP, 0, "Failed creating worker thread!");
|
|
goto Failure;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Bump the refcount for this successful call.
|
|
//
|
|
g_lWorkerThreadRefCount++;
|
|
|
|
|
|
|
|
Exit:
|
|
|
|
DNLeaveCriticalSection(&g_csGlobalsLock);
|
|
|
|
|
|
DPFX(DPFPREP, 5, "Returning: [0x%lx]", hr);
|
|
|
|
return hr;
|
|
|
|
|
|
Failure:
|
|
|
|
if (g_hWorkerThreadJobEvent != NULL)
|
|
{
|
|
CloseHandle(g_hWorkerThreadJobEvent);
|
|
g_hWorkerThreadJobEvent = NULL;
|
|
}
|
|
|
|
if (fInittedCriticalSection)
|
|
{
|
|
DNDeleteCriticalSection(&g_csJobQueueLock);
|
|
fInittedCriticalSection = FALSE;
|
|
}
|
|
|
|
goto Exit;
|
|
} // StartGlobalWorkerThread
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "StopGlobalWorkerThread"
|
|
//=============================================================================
|
|
// StopGlobalWorkerThread
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Stop the global worker thread. This must balance a successful
|
|
// call to StartGlobalWorkerThread.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: None.
|
|
//=============================================================================
|
|
void StopGlobalWorkerThread(void)
|
|
{
|
|
DPFX(DPFPREP, 5, "Enter");
|
|
|
|
|
|
DNEnterCriticalSection(&g_csGlobalsLock);
|
|
|
|
|
|
DNASSERT(g_lWorkerThreadRefCount > 0);
|
|
g_lWorkerThreadRefCount--;
|
|
if (g_lWorkerThreadRefCount == 0)
|
|
{
|
|
//
|
|
// Time to shut down the worker thread.
|
|
//
|
|
|
|
|
|
//
|
|
// The job queue had better be empty.
|
|
//
|
|
DNASSERT(g_blJobQueue.IsEmpty());
|
|
|
|
//
|
|
// Submit a quit job. Ignore error.
|
|
//
|
|
AddWorkerJob(0, DP8SIMJOBTYPE_QUIT, NULL, NULL, FALSE);
|
|
|
|
|
|
//
|
|
// Wait for the worker thread to close.
|
|
//
|
|
WaitForSingleObject(g_hWorkerThread, INFINITE);
|
|
|
|
|
|
//
|
|
// The job queue needs to be empty again.
|
|
//
|
|
DNASSERT(g_blJobQueue.IsEmpty());
|
|
|
|
|
|
//
|
|
// Close the thread handle.
|
|
//
|
|
CloseHandle(g_hWorkerThread);
|
|
g_hWorkerThread = NULL;
|
|
|
|
|
|
//
|
|
// Close the event handle.
|
|
//
|
|
CloseHandle(g_hWorkerThreadJobEvent);
|
|
g_hWorkerThreadJobEvent = NULL;
|
|
|
|
|
|
//
|
|
// Delete the critical section.
|
|
//
|
|
DNDeleteCriticalSection(&g_csJobQueueLock);
|
|
}
|
|
|
|
|
|
DNLeaveCriticalSection(&g_csGlobalsLock);
|
|
|
|
|
|
DPFX(DPFPREP, 5, "Leave");
|
|
} // StopGlobalWorkerThread
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "AddWorkerJob"
|
|
//=============================================================================
|
|
// AddWorkerJob
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Submits a new job of the given type to performed dwDelay
|
|
// milliseconds from now.
|
|
//
|
|
// If fDelayFromPreviousJob is TRUE, then if there is a job of
|
|
// the same type already queued, the new job is delayed further so
|
|
// that it occurs dwDelay milliseconds after the last similar job.
|
|
//
|
|
// Arguments:
|
|
// DWORD dwDelay - How long to wait before performing job, in
|
|
// milliseconds.
|
|
// DWORD dwJobType - ID indicating the type of type.
|
|
// PVOID pvContext - Context for the job.
|
|
// CDP8SimSP * pDP8SimSP - Pointer to interface submitting job, or NULL
|
|
// for none.
|
|
// BOOL fDelayFromPreviousJob - Whether to add the delay beyond the last job
|
|
// of the same type or not.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
HRESULT AddWorkerJob(const DWORD dwDelay,
|
|
const DWORD dwJobType,
|
|
PVOID const pvContext,
|
|
CDP8SimSP * const pDP8SimSP,
|
|
const BOOL fDelayFromPreviousJob)
|
|
{
|
|
HRESULT hr = DPN_OK;
|
|
DP8SIMJOB_FPMCONTEXT JobFPMContext;
|
|
CDP8SimJob * pDP8SimJob;
|
|
CBilink * pBilinkOriginalFirstItem;
|
|
CBilink * pBilink;
|
|
CDP8SimJob * pDP8SimTempJob;
|
|
|
|
|
|
DPFX(DPFPREP, 5, "Parameters: (%u, %u, 0x%p, 0x%p, %i)",
|
|
dwDelay, dwJobType, pvContext, pDP8SimSP, fDelayFromPreviousJob);
|
|
|
|
|
|
|
|
DNASSERT(g_hWorkerThreadJobEvent != NULL);
|
|
DNASSERT(g_hWorkerThread != NULL);
|
|
|
|
|
|
//
|
|
// Get a job object from the pool.
|
|
//
|
|
// Assume the job should execute after the appropriate delay. If
|
|
// fDelayFromPreviousJob is TRUE, we may need to adjust this.
|
|
//
|
|
|
|
ZeroMemory(&JobFPMContext, sizeof(JobFPMContext));
|
|
JobFPMContext.dwTime = timeGetTime() + dwDelay;
|
|
JobFPMContext.dwJobType = dwJobType;
|
|
JobFPMContext.pvContext = pvContext;
|
|
JobFPMContext.pDP8SimSP = pDP8SimSP;
|
|
|
|
pDP8SimJob = g_pFPOOLJob->Get(&JobFPMContext);
|
|
if (pDP8SimJob == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// Lock the job queue.
|
|
//
|
|
DNEnterCriticalSection(&g_csJobQueueLock);
|
|
|
|
|
|
//
|
|
// If fDelayFromPreviousJob is TRUE, look for a previous job of the same
|
|
// type. If found, we need to delay this new job from the end of the last
|
|
// one.
|
|
//
|
|
if (fDelayFromPreviousJob)
|
|
{
|
|
//
|
|
// Work backward through the list.
|
|
//
|
|
pBilink = g_blJobQueue.GetPrev();
|
|
while (pBilink != &g_blJobQueue)
|
|
{
|
|
pDP8SimTempJob = DP8SIMJOB_FROM_BILINK(pBilink);
|
|
DNASSERT(pDP8SimTempJob->IsValidObject());
|
|
if (dwJobType == pDP8SimTempJob->GetJobType())
|
|
{
|
|
//
|
|
// We found a similar job. Update the new job's time so that
|
|
// the delay is added on top of the previous job.
|
|
//
|
|
|
|
DPFX(DPFPREP, 9, "Found similar job 0x%p (job time = %u, type = %u, context 0x%p, interface = 0x%p).",
|
|
pDP8SimTempJob, pDP8SimTempJob->GetTime(), dwJobType, pDP8SimTempJob->GetContext(), pDP8SimSP);
|
|
|
|
pDP8SimJob->SetNewTime(pDP8SimTempJob->GetTime() + dwDelay);
|
|
|
|
break;
|
|
}
|
|
|
|
pBilink = pBilink->GetPrev();
|
|
}
|
|
}
|
|
|
|
|
|
DPFX(DPFPREP, 8, "Adding new job 0x%p (job time = %u, type = %u, context 0x%p, interface = 0x%p).",
|
|
pDP8SimJob, pDP8SimJob->GetTime(), dwJobType, pDP8SimJob->GetContext(), pDP8SimSP);
|
|
|
|
|
|
//
|
|
// Remember the current first item.
|
|
//
|
|
pBilinkOriginalFirstItem = g_blJobQueue.GetNext();
|
|
|
|
|
|
//
|
|
// Find the first job that needs to be fired after this one and insert the
|
|
// new job before it.
|
|
//
|
|
pBilink = pBilinkOriginalFirstItem;
|
|
while (pBilink != &g_blJobQueue)
|
|
{
|
|
pDP8SimTempJob = DP8SIMJOB_FROM_BILINK(pBilink);
|
|
DNASSERT(pDP8SimTempJob->IsValidObject());
|
|
|
|
if ((int) (pDP8SimJob->GetTime() - pDP8SimTempJob->GetTime()) < 0)
|
|
{
|
|
//
|
|
// Stop looping.
|
|
//
|
|
break;
|
|
}
|
|
|
|
pBilink = pBilink->GetNext();
|
|
}
|
|
|
|
|
|
//
|
|
// If we didn't find a place to insert the job, pBilink will point to the
|
|
// end/beginning of the list.
|
|
//
|
|
pDP8SimJob->m_blList.InsertBefore(pBilink);
|
|
|
|
|
|
//
|
|
// If the front of the queue changed, alert the worker thread.
|
|
//
|
|
if (g_blJobQueue.GetNext() != pBilinkOriginalFirstItem)
|
|
{
|
|
DPFX(DPFPREP, 9, "Front of job queue changed, alerting worker thread.");
|
|
|
|
//
|
|
// Ignore error, there's nothing we can do about it.
|
|
//
|
|
SetEvent(g_hWorkerThreadJobEvent);
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 9, "Front of job queue did not change.");
|
|
}
|
|
|
|
|
|
DNLeaveCriticalSection(&g_csJobQueueLock);
|
|
|
|
|
|
Exit:
|
|
|
|
|
|
DPFX(DPFPREP, 5, "Returning: [0x%lx]", hr);
|
|
|
|
return hr;
|
|
|
|
|
|
Failure:
|
|
|
|
goto Exit;
|
|
} // AddWorkerJob
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "FlushAllDelayedSendsToEndpoint"
|
|
//=============================================================================
|
|
// FlushAllDelayedSendsToEndpoint
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Removes all delayed sends intended for the given endpoint that
|
|
// are still queued. If fDrop is TRUE, the messages are dropped.
|
|
// If fDrop is FALSE, they are all submitted to the real SP.
|
|
//
|
|
// Arguments:
|
|
// CDP8SimEndpoint * pDP8SimEndpoint - Endpoint whose sends are to be
|
|
// removed.
|
|
// BOOL fDrop - Whether to drop the sends or not.
|
|
//
|
|
// Returns: None.
|
|
//=============================================================================
|
|
void FlushAllDelayedSendsToEndpoint(CDP8SimEndpoint * const pDP8SimEndpoint,
|
|
BOOL fDrop)
|
|
{
|
|
CBilink blDelayedSendJobs;
|
|
CBilink * pBilinkOriginalFirstItem;
|
|
CBilink * pBilink;
|
|
CDP8SimJob * pDP8SimJob;
|
|
CDP8SimSend * pDP8SimSend;
|
|
CDP8SimSP * pDP8SimSP;
|
|
|
|
|
|
DPFX(DPFPREP, 5, "Parameters: (0x%p, %i)", pDP8SimEndpoint, fDrop);
|
|
|
|
|
|
DNASSERT(pDP8SimEndpoint->IsValidObject());
|
|
|
|
|
|
blDelayedSendJobs.Initialize();
|
|
|
|
|
|
DNEnterCriticalSection(&g_csJobQueueLock);
|
|
|
|
pBilinkOriginalFirstItem = g_blJobQueue.GetNext();
|
|
pBilink = pBilinkOriginalFirstItem;
|
|
while (pBilink != &g_blJobQueue)
|
|
{
|
|
pDP8SimJob = DP8SIMJOB_FROM_BILINK(pBilink);
|
|
DNASSERT(pDP8SimJob->IsValidObject());
|
|
|
|
pBilink = pBilink->GetNext();
|
|
|
|
//
|
|
// See if the job is a delayed send.
|
|
//
|
|
if (pDP8SimJob->GetJobType() == DP8SIMJOBTYPE_DELAYEDSEND)
|
|
{
|
|
pDP8SimSend = (CDP8SimSend*) pDP8SimJob->GetContext();
|
|
DNASSERT(pDP8SimSend->IsValidObject());
|
|
|
|
//
|
|
// See if the delayed send is for the right endpoint.
|
|
//
|
|
if (pDP8SimSend->GetEndpoint() == pDP8SimEndpoint)
|
|
{
|
|
//
|
|
// Pull the job out of the queue.
|
|
//
|
|
pDP8SimJob->m_blList.RemoveFromList();
|
|
|
|
|
|
//
|
|
// Place it on the temporary list.
|
|
//
|
|
pDP8SimJob->m_blList.InsertBefore(&blDelayedSendJobs);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Not intended for the given endpoint.
|
|
//
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Not a delayed send.
|
|
//
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If the front of the queue changed, alert the worker thread.
|
|
//
|
|
if (g_blJobQueue.GetNext() != pBilinkOriginalFirstItem)
|
|
{
|
|
DPFX(DPFPREP, 9, "Front of job queue changed, alerting worker thread.");
|
|
SetEvent(g_hWorkerThreadJobEvent);
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 9, "Front of job queue did not change.");
|
|
}
|
|
|
|
|
|
DNLeaveCriticalSection(&g_csJobQueueLock);
|
|
|
|
|
|
//
|
|
// Now actually drop or transmit those messages.
|
|
//
|
|
pBilink = blDelayedSendJobs.GetNext();
|
|
while (pBilink != &blDelayedSendJobs)
|
|
{
|
|
pDP8SimJob = DP8SIMJOB_FROM_BILINK(pBilink);
|
|
DNASSERT(pDP8SimJob->IsValidObject());
|
|
pBilink = pBilink->GetNext();
|
|
|
|
|
|
//
|
|
// Pull the job out of the temporary list.
|
|
//
|
|
pDP8SimJob->m_blList.RemoveFromList();
|
|
|
|
|
|
pDP8SimSend = (CDP8SimSend*) pDP8SimJob->GetContext();
|
|
pDP8SimSP = pDP8SimJob->GetDP8SimSP();
|
|
DNASSERT(pDP8SimSP != NULL);
|
|
|
|
//
|
|
// Either drop the data on the floor or submit it.
|
|
//
|
|
if (fDrop)
|
|
{
|
|
//
|
|
// Remove the send counter.
|
|
//
|
|
pDP8SimSP->DecSendsPending();
|
|
|
|
DPFX(DPFPREP, 7, "Releasing cancelled send 0x%p.", pDP8SimSend);
|
|
pDP8SimSend->Release();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Transmit the message.
|
|
//
|
|
pDP8SimSP->PerformDelayedSend(pDP8SimSend);
|
|
}
|
|
|
|
|
|
//
|
|
// Release the job object.
|
|
//
|
|
DPFX(DPFPREP, 7, "Returning job object 0x%p to pool.", pDP8SimJob);
|
|
g_pFPOOLJob->Release(pDP8SimJob);
|
|
}
|
|
|
|
|
|
DNASSERT(blDelayedSendJobs.IsEmpty());
|
|
|
|
|
|
DPFX(DPFPREP, 5, "Leave");
|
|
} // FlushAllDelayedSendsToEndpoint
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "FlushAllDelayedReceivesFromEndpoint"
|
|
//=============================================================================
|
|
// FlushAllDelayedReceivesFromEndpoint
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Removes all data received from the given endpoint that has not
|
|
// been indicated yet. If fDrop is TRUE, the messages are
|
|
// dropped. If fDrop is FALSE, they are all indicated to the
|
|
// upper layer.
|
|
//
|
|
// Arguments:
|
|
// CDP8SimEndpoint * pDP8SimEndpoint - Endpoint whose receives are to be
|
|
// removed.
|
|
// BOOL fDrop - Whether to drop the receives or not.
|
|
//
|
|
// Returns: None.
|
|
//=============================================================================
|
|
void FlushAllDelayedReceivesFromEndpoint(CDP8SimEndpoint * const pDP8SimEndpoint,
|
|
BOOL fDrop)
|
|
{
|
|
HRESULT hr;
|
|
CBilink blDelayedReceiveJobs;
|
|
CBilink * pBilinkOriginalFirstItem;
|
|
CBilink * pBilink;
|
|
CDP8SimJob * pDP8SimJob;
|
|
CDP8SimReceive * pDP8SimReceive;
|
|
CDP8SimSP * pDP8SimSP;
|
|
SPIE_DATA * pData;
|
|
|
|
|
|
DPFX(DPFPREP, 5, "Parameters: (0x%p, %i)", pDP8SimEndpoint, fDrop);
|
|
|
|
|
|
DNASSERT(pDP8SimEndpoint->IsValidObject());
|
|
|
|
|
|
blDelayedReceiveJobs.Initialize();
|
|
|
|
|
|
DNEnterCriticalSection(&g_csJobQueueLock);
|
|
|
|
pBilinkOriginalFirstItem = g_blJobQueue.GetNext();
|
|
pBilink = pBilinkOriginalFirstItem;
|
|
while (pBilink != &g_blJobQueue)
|
|
{
|
|
pDP8SimJob = DP8SIMJOB_FROM_BILINK(pBilink);
|
|
DNASSERT(pDP8SimJob->IsValidObject());
|
|
|
|
pBilink = pBilink->GetNext();
|
|
|
|
//
|
|
// See if the job is a delayed receive.
|
|
//
|
|
if (pDP8SimJob->GetJobType() == DP8SIMJOBTYPE_DELAYEDRECEIVE)
|
|
{
|
|
pDP8SimReceive = (CDP8SimReceive*) pDP8SimJob->GetContext();
|
|
DNASSERT(pDP8SimReceive->IsValidObject());
|
|
|
|
//
|
|
// See if the delayed receive is for the right endpoint.
|
|
//
|
|
if (pDP8SimReceive->GetEndpoint() == pDP8SimEndpoint)
|
|
{
|
|
//
|
|
// Pull the job out of the queue.
|
|
//
|
|
pDP8SimJob->m_blList.RemoveFromList();
|
|
|
|
|
|
//
|
|
// Place it on the temporary list.
|
|
//
|
|
pDP8SimJob->m_blList.InsertBefore(&blDelayedReceiveJobs);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Not intended for the given endpoint.
|
|
//
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Not a delayed receive.
|
|
//
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If the front of the queue changed, alert the worker thread.
|
|
//
|
|
if (g_blJobQueue.GetNext() != pBilinkOriginalFirstItem)
|
|
{
|
|
DPFX(DPFPREP, 9, "Front of job queue changed, alerting worker thread.");
|
|
SetEvent(g_hWorkerThreadJobEvent);
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 9, "Front of job queue did not change.");
|
|
}
|
|
|
|
|
|
DNLeaveCriticalSection(&g_csJobQueueLock);
|
|
|
|
|
|
//
|
|
// Now actually drop or transmit those messages.
|
|
//
|
|
pBilink = blDelayedReceiveJobs.GetNext();
|
|
while (pBilink != &blDelayedReceiveJobs)
|
|
{
|
|
pDP8SimJob = DP8SIMJOB_FROM_BILINK(pBilink);
|
|
DNASSERT(pDP8SimJob->IsValidObject());
|
|
pBilink = pBilink->GetNext();
|
|
|
|
|
|
//
|
|
// Pull the job out of the temporary list.
|
|
//
|
|
pDP8SimJob->m_blList.RemoveFromList();
|
|
|
|
|
|
pDP8SimReceive = (CDP8SimReceive*) pDP8SimJob->GetContext();
|
|
pDP8SimSP = pDP8SimJob->GetDP8SimSP();
|
|
DNASSERT(pDP8SimSP != NULL);
|
|
|
|
|
|
//
|
|
// Either drop the data on the floor or submit it.
|
|
//
|
|
if (fDrop)
|
|
{
|
|
pData = pDP8SimReceive->GetReceiveDataBlockPtr();
|
|
|
|
|
|
DPFX(DPFPREP, 8, "Returning receive data 0x%p (wrapper object 0x%p).",
|
|
pData->pReceivedData, pDP8SimSP);
|
|
|
|
|
|
hr = pDP8SimSP->ReturnReceiveBuffers(pData->pReceivedData);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed returning receive buffers 0x%p (err = 0x%lx)! Ignoring.",
|
|
pData->pReceivedData, hr);
|
|
|
|
//
|
|
// Ignore failure.
|
|
//
|
|
}
|
|
|
|
|
|
//
|
|
// Remove the receive counter.
|
|
//
|
|
pDP8SimSP->DecReceivesPending();
|
|
|
|
|
|
DPFX(DPFPREP, 7, "Releasing cancelled receive 0x%p.", pDP8SimReceive);
|
|
pDP8SimReceive->Release();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Indicate the message.
|
|
//
|
|
pDP8SimSP->PerformDelayedReceive(pDP8SimReceive);
|
|
}
|
|
|
|
|
|
//
|
|
// Release the job object.
|
|
//
|
|
DPFX(DPFPREP, 7, "Returning job object 0x%p to pool.", pDP8SimJob);
|
|
g_pFPOOLJob->Release(pDP8SimJob);
|
|
}
|
|
|
|
|
|
DNASSERT(blDelayedReceiveJobs.IsEmpty());
|
|
|
|
|
|
DPFX(DPFPREP, 5, "Leave");
|
|
} // FlushAllDelayedReceivesFromEndpoint
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DP8SimWorkerThreadProc"
|
|
//=============================================================================
|
|
// DP8SimWorkerThreadProc
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: The global worker thread function.
|
|
//
|
|
// Arguments:
|
|
// PVOID pvParameter - Thread parameter. Ignored.
|
|
//
|
|
// Returns: 0 if all goes well.
|
|
//=============================================================================
|
|
DWORD DP8SimWorkerThreadProc(PVOID pvParameter)
|
|
{
|
|
DWORD dwReturn;
|
|
DWORD dwWaitTimeout = INFINITE;
|
|
BOOL fRunning = TRUE;
|
|
BOOL fFoundJob;
|
|
DWORD dwCurrentTime;
|
|
CBilink * pBilink;
|
|
CDP8SimJob * pDP8SimJob;
|
|
CDP8SimSP * pDP8SimSP;
|
|
|
|
|
|
DPFX(DPFPREP, 5, "Parameters: (0x%p)", pvParameter);
|
|
|
|
|
|
//
|
|
// Keep looping until we're told to quit.
|
|
//
|
|
do
|
|
{
|
|
//
|
|
// Wait for the next job.
|
|
//
|
|
dwReturn = WaitForSingleObject(g_hWorkerThreadJobEvent, dwWaitTimeout);
|
|
switch (dwReturn)
|
|
{
|
|
case WAIT_OBJECT_0:
|
|
case WAIT_TIMEOUT:
|
|
{
|
|
//
|
|
// There's a change in the job queue or a timer expired. See
|
|
// if it's time to execute something.
|
|
//
|
|
|
|
//
|
|
// Keep looping while we have jobs to perform now.
|
|
//
|
|
do
|
|
{
|
|
fFoundJob = FALSE;
|
|
|
|
|
|
//
|
|
// Take the lock while we look at the list.
|
|
//
|
|
DNEnterCriticalSection(&g_csJobQueueLock);
|
|
|
|
|
|
pBilink = g_blJobQueue.GetNext();
|
|
if (pBilink != &g_blJobQueue)
|
|
{
|
|
pDP8SimJob = DP8SIMJOB_FROM_BILINK(pBilink);
|
|
DNASSERT(pDP8SimJob->IsValidObject());
|
|
|
|
dwCurrentTime = timeGetTime();
|
|
|
|
|
|
//
|
|
// If the timer has expired, pull the job from the list
|
|
// and execute it.
|
|
//
|
|
if ((int) (pDP8SimJob->GetTime() - dwCurrentTime) <= 0)
|
|
{
|
|
pDP8SimJob->m_blList.RemoveFromList();
|
|
|
|
|
|
//
|
|
// Drop the list lock.
|
|
//
|
|
DNLeaveCriticalSection(&g_csJobQueueLock);
|
|
|
|
|
|
pDP8SimSP = pDP8SimJob->GetDP8SimSP();
|
|
|
|
|
|
DPFX(DPFPREP, 8, "Job 0x%p has expired (job time = %u, current time = %u, type = %u, context 0x%p, interface = 0x%p).",
|
|
pDP8SimJob, pDP8SimJob->GetTime(), dwCurrentTime,
|
|
pDP8SimJob->GetJobType(), pDP8SimJob->GetContext(),
|
|
pDP8SimSP);
|
|
|
|
|
|
//
|
|
// Figure out what to do with the job.
|
|
//
|
|
switch (pDP8SimJob->GetJobType())
|
|
{
|
|
case DP8SIMJOBTYPE_DELAYEDSEND:
|
|
{
|
|
//
|
|
// Finally submit the send.
|
|
//
|
|
DNASSERT(pDP8SimSP != NULL);
|
|
pDP8SimSP->PerformDelayedSend(pDP8SimJob->GetContext());
|
|
break;
|
|
}
|
|
|
|
case DP8SIMJOBTYPE_DELAYEDRECEIVE:
|
|
{
|
|
//
|
|
// Finally indicate the receive.
|
|
//
|
|
DNASSERT(pDP8SimSP != NULL);
|
|
pDP8SimSP->PerformDelayedReceive(pDP8SimJob->GetContext());
|
|
break;
|
|
}
|
|
|
|
case DP8SIMJOBTYPE_QUIT:
|
|
{
|
|
//
|
|
// Stop looping.
|
|
//
|
|
DNASSERT(pDP8SimSP == NULL);
|
|
DPFX(DPFPREP, 2, "Quit job received.");
|
|
fRunning = FALSE;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DPFX(DPFPREP, 0, "Unexpected job type %u!",
|
|
pDP8SimJob->GetJobType());
|
|
DNASSERT(FALSE);
|
|
fRunning = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Release the job object.
|
|
//
|
|
DPFX(DPFPREP, 7, "Returning job object 0x%p to pool.", pDP8SimJob);
|
|
g_pFPOOLJob->Release(pDP8SimJob);
|
|
|
|
|
|
//
|
|
// Check out the next job (unless we're bailing).
|
|
//
|
|
fFoundJob = fRunning;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Not time for job yet. Figure out when it will
|
|
// be.
|
|
//
|
|
dwWaitTimeout = pDP8SimJob->GetTime() - dwCurrentTime;
|
|
|
|
|
|
//
|
|
// Drop the list lock.
|
|
//
|
|
DNLeaveCriticalSection(&g_csJobQueueLock);
|
|
|
|
|
|
DPFX(DPFPREP, 8, "Next job in %u ms.", dwWaitTimeout);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Nothing in the job queue. Drop the list lock.
|
|
//
|
|
DNLeaveCriticalSection(&g_csJobQueueLock);
|
|
|
|
//
|
|
// Wait until something gets put into the queue.
|
|
//
|
|
dwWaitTimeout = INFINITE;
|
|
|
|
|
|
DPFX(DPFPREP, 8, "No more jobs.");
|
|
}
|
|
}
|
|
while (fFoundJob);
|
|
|
|
|
|
//
|
|
// Go back to waiting.
|
|
//
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
//
|
|
// Something unusual happened.
|
|
//
|
|
DPFX(DPFPREP, 0, "Got unexpected return value from WaitForSingleObject (%u)!");
|
|
DNASSERT(FALSE);
|
|
fRunning = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
while (fRunning);
|
|
|
|
|
|
|
|
DPFX(DPFPREP, 5, "Returning: [%u]", dwReturn);
|
|
|
|
|
|
return dwReturn;
|
|
} // DP8SimWorkerThreadProc
|
|
|