Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1433 lines
53 KiB

#include "wt.h"
#include "wtproto.h"
#include "workerinc.h"
//----------------------------------------------------------------------------------//
// WorkerFunction_ProcessClientNotifyWTEvent //
// the client has locks on wte_CS, so that no one can add or delete //
// if you need to add timers, you have to take lock on wte_CSTimer //
//----------------------------------------------------------------------------------//
VOID
WorkerFunction_ProcessClientNotifyWTEvent (
IN PVOID pContext
)
{
PWAIT_THREAD_ENTRY pwte;
BOOL bLockTimer;
pwte = (PWAIT_THREAD_ENTRY) pContext;
TRACE0(ENTER, "Entering WorkerFunction_ProcessClientNotifyWTEvent:");
switch (pwte->wte_ChangeType) {
case CHANGE_TYPE_ADD :
RegisterClientEventsTimers(pwte);
break;
case CHANGE_TYPE_DELETE :
DeRegisterClientEventsTimers(pwte);
break;
case CHANGE_TYPE_BIND_FUNCTION_ADD :
RegisterClientEventBinding(pwte);
break;
case CHANGE_TYPE_BIND_FUNCTION_DELETE :
DeRegisterClientEventBinding(pwte);
break;
}
SET_EVENT(pwte->wte_WTNotifyClientEvent, "wte_WTNotifyClientEvent",
"WorkerFunction_ProcessClientNotifyWTEvent");
TRACE0(LEAVE, "Leaving WorkerFunction_ProcessClientNotifyWTEvent:");
return;
} //end WorkerFunction_ProcessClientNotifyWTEvent
//----------------------------------------------------------------------------------//
// WorkerFunction_ProcessWorkQueueTimer //
//----------------------------------------------------------------------------------//
VOID
WorkerFunction_ProcessWorkQueueTimer (
IN PVOID pContext
)
{
TRACE0(ENTER, "Entering WorkerFunction_ProcessWorkQueueTimer:");
// Work queue has not been served within specified
// timeout
while (1) {
// Make a local copy of the count
LONG count = ThreadCount;
// Make sure we havn't exceded the limit
if (count>=MAX_WORKER_THREADS)
break;
else {
// Try to increment the value
// use another local variable
// because of MIPS optimizer bug
LONG newCount = count+1;
if (InterlockedCompareExchange (&ThreadCount,
newCount, count)==count) {
HANDLE hThread;
DWORD tid;
// Create new thread if increment succeded
hThread = CreateThread (NULL, 0, WorkerThread, NULL, 0, &tid);
if (hThread!=NULL) {
CloseHandle (hThread);
}
else // Restore the value if thread creation
// failed
InterlockedDecrement (&ThreadCount);
break;
}
// else repeat the loop if ThreadCount was modified
// while we were checking
}
}
TRACE0(LEAVE, "Leaving WorkerFunction_ProcessWorkQueueTimer:");
return;
} //end WorkerFunction_ProcessWorkQueueTimer
//----------------------------------------------------------------------------------//
// WorkerFunction_ProcessAlertableThreadSemaphore //
//----------------------------------------------------------------------------------//
VOID
WorkerFunction_ProcessAlertableThreadSemaphore (
IN PVOID pContext
)
{
WorkItem *workitem;
TRACE0(ENTER, "Entering WorkerFunction_ProcessAlertableThreadSemaphore:");
EnterCriticalSection(&AlertableWorkQueueLock);
ASSERT (!IsListEmpty (&AlertableWorkQueue));
workitem = (WorkItem *) RemoveHeadList (&AlertableWorkQueue) ;
LeaveCriticalSection(&AlertableWorkQueueLock);
(workitem->WI_Function) (workitem->WI_Context);
HeapFree (AlertableWorkerHeap, 0, workitem);
TRACE0(LEAVE, "Leaving WorkerFunction_ProcessAlertableThreadSemaphore:");
return;
}
//++-------------------------------------------------------------------------------*//
// WorkerFunction_ProcessWaitableTimer //
// Process event: waitable timer fired //
// takes lock on wte_CSTimer and releases it in the end //
//----------------------------------------------------------------------------------//
VOID
WorkerFunction_ProcessWaitableTimer(
IN PVOID pContext
)
{
PWAIT_THREAD_ENTRY pwte;
LONGLONG liCurrentTime;
PLIST_ENTRY ple, pHead, pleCurrent;
PWT_TIMER_ENTRY pte;
BOOL bActiveTimers;
TRACE0(ENTER, "Entering WorkerFunction_ProcessWaitableTimer:");
pwte = (PWAIT_THREAD_ENTRY) pContext;
// get lock on server threads timer
ENTER_CRITICAL_SECTION(&pwte->wte_CSTimer, "wte_CSTimer", "WorkerFunction_ProcessWaitableTimer");
NtQuerySystemTime((LARGE_INTEGER*) &liCurrentTime);
// ordered in increasing time, with inactive timers at the end
pHead = &pwte->wteL_ClientTimerEntries;
for (ple=pHead->Flink; ple!=pHead; ) {
pte = CONTAINING_RECORD(ple, WT_TIMER_ENTRY, te_ServerLinks);
if (pte->te_Status == TIMER_INACTIVE) // inactive timers at end of list
break;
if (IS_TIMER_INFINITE(pte->te_Timeout)) { //should have been inactive
ple = ple->Flink;
continue;
}
if (pte->te_Timeout<=liCurrentTime) {
//
// set timer status to inactive and insert at end of timer queue
//
pte->te_Status = TIMER_INACTIVE;
SET_TIMER_INFINITE(pte->te_Timeout);
pleCurrent = ple;
ple = ple->Flink;
RemoveEntryList(pleCurrent);
InsertTailList(pHead, pleCurrent);
// run the function in current thread or dispatch to worker thread
//
if (pte->te_RunInServer) {
(pte->te_Function)(pte->te_Context);
}
else {
QueueWorkItem( pte->te_Function, pte->te_Context, FALSE ); // do not run in alertable thread
}
}
else {
break;
}
}
//
// search for active timers with timeout which is not infinite
//
if (IsListEmpty(pHead))
bActiveTimers = FALSE;
else {
ple = pHead->Flink;
pte = CONTAINING_RECORD(ple, WT_TIMER_ENTRY, te_ServerLinks);
bActiveTimers = (pte->te_Status==TIMER_INACTIVE) ? FALSE : TRUE;
}
//
// if active timers present, then set waitableTimer
//
if (bActiveTimers) {
// set next timeout value for the wait server
pwte->wte_Timeout = pte->te_Timeout;
TRACE2(TIMER, "SetWaitableTimer set to <%lu:%lu> after being fired",
TIMER_HIGH(pte->te_Timeout), TIMER_LOW(pte->te_Timeout));
SetWaitableTimer(pwte->wte_Timer, (LARGE_INTEGER*)&pte->te_Timeout, 0, NULL, NULL, FALSE);
}
// no active timer in queue. do not set the waitable timer
else {
SET_TIMER_INFINITE(pwte->wte_Timeout);
}
#if DBG2
DebugPrintWaitWorkerThreads(DEBUGPRINT_FILTER_EVENTS);
#endif
LEAVE_CRITICAL_SECTION(&pwte->wte_CSTimer, "wte_CSTimer", "WorkerFunction_ProcessWaitableTimer");
TRACE0(LEAVE, "Leaving WorkerFunction_ProcessWaitableTimer:");
return;
} //end WorkerFunction_ProcessWaitableTimer
//---------------------------------------------------------------------------------*//
// CreateServerEventsAndTimer //
// Create the events for a server and the timer(called by server only) //
// assumes lock on server and server timer structure //
// THIS FUNCTION SHOULD NOT HAVE ANY CALLS TO API FUNCTIONS //
//----------------------------------------------------------------------------------//
DWORD
CreateServerEventsAndTimer (
IN PWAIT_THREAD_ENTRY pwte
)
{
PWT_EVENT_ENTRY peeWaitableTimer, peeClientNotifyWTEvent,
peeAlertableThreadSemaphore, peeWorkQueueTimer;
// waitable timer (set to infinity time)
peeWaitableTimer = CreateWaitEvent(
pwte->wte_Timer,
NULL, FALSE, FALSE, NULL,
TRUE, // highPriority
(WORKERFUNCTION) WorkerFunction_ProcessWaitableTimer,
(PVOID)pwte, // context
0, // context size=0, as just a pointer value is being passed
TRUE // run in server context
);
if (!peeWaitableTimer)
return ERROR_NOT_ENOUGH_MEMORY;
peeWaitableTimer->ee_EventId = 1;
RegisterClientEventLocal(peeWaitableTimer, pwte);
// ClientNotifyWTEvent
peeClientNotifyWTEvent = CreateWaitEvent(
pwte->wte_ClientNotifyWTEvent,
NULL, FALSE, FALSE, NULL,
TRUE, // highPriority
(WORKERFUNCTION) WorkerFunction_ProcessClientNotifyWTEvent,
(PVOID)pwte, // context
0, // context size=0, as just a pointer value is being passed
TRUE // run in server context
);
if (!peeClientNotifyWTEvent )
return ERROR_NOT_ENOUGH_MEMORY;
peeClientNotifyWTEvent->ee_EventId = 2;
RegisterClientEventLocal(peeClientNotifyWTEvent, pwte);
// AlertableThreadSemaphore
peeAlertableThreadSemaphore = CreateWaitEvent(
AlertableThreadSemaphore,
NULL, FALSE, FALSE, NULL,
FALSE, // Priority=low
(WORKERFUNCTION) WorkerFunction_ProcessAlertableThreadSemaphore,
NULL, // context
0, // context size=0, as just a pointer value is being passed
TRUE // run in server context
);
peeAlertableThreadSemaphore->ee_EventId = 3;
RegisterClientEventLocal(peeAlertableThreadSemaphore, pwte);
// WorkQueueTimer
peeWorkQueueTimer = CreateWaitEvent(
WorkQueueTimer,
NULL, FALSE, FALSE, NULL,
FALSE, // Priority=low
(WORKERFUNCTION) WorkerFunction_ProcessWorkQueueTimer,
NULL, // context
0, // context size=0, as just a pointer value is being passed
TRUE // run in server context
);
peeWorkQueueTimer->ee_EventId = 4;
RegisterClientEventLocal(peeWorkQueueTimer, pwte);
return NO_ERROR;
} //end CreateServerEventsAndTimer
//---------------------------------------------------------------------------------*//
// InitializeWaitGlobal //
// initialize the global data structure for all wait threads //
//----------------------------------------------------------------------------------//
DWORD
InitializeWaitGlobal(
)
{
BOOL bErr;
DWORD dwErr = NO_ERROR;
ZeroMemory(&WTG, sizeof(WTG));
WTG.g_Initialized = 0x12345678;
//
// initialize tracing and logging
//
WTG.g_TraceId = TraceRegister("WAIT_THREAD");
//todo:set the logging level
WTG.g_LogLevel = WT_LOGGING_ERROR;
WTG.g_LogHandle = RouterLogRegister("WAIT_THREAD");
TRACE0(ENTER, "Entering InitializeWaitGlobal()");
//
// initialize global structure
//
bErr = FALSE;
do { // error breakout loop
//
// create a private heap for Wait-Thread
//
WTG.g_Heap = AlertableWorkerHeap; // created in worker.c
if (WTG.g_Heap==NULL)
WTG.g_Heap = HeapCreate(0, 0, 0);
if (WTG.g_Heap == NULL) {
dwErr = GetLastError();
TRACE1(
ANY, "error %d creating Wait-Thread global heap", dwErr
);
LOGERR0(HEAP_CREATE_FAILED, dwErr);
bErr = FALSE;
break;
}
// initialize list for wait thread entries
//
InitializeListHead(&WTG.gL_WaitThreadEntries);
// initialize critical section
//
try {
InitializeCriticalSection(&WTG.g_CS);
}
except (EXCEPTION_EXECUTE_HANDLER) {
dwErr = GetExceptionCode();
TRACE1(
ANY, "exception %d initializing global critical section",
dwErr
);
LOGERR0(INIT_CRITSEC_FAILED, dwErr);
bErr = TRUE;
break;
}
} while (FALSE);
TRACE1(LEAVE, "leaving InitializeWaitGlobal: %d", dwErr);
if (bErr)
return dwErr;
else
return NO_ERROR;
} //end InitializeWaitGlobal
//---------------------------------------------------------------------------------*//
// DeInitializeWaitGlobal //
//deinitializes the global structure for wait-thread //
//todo: free the server entries and the event/timers etc associated with them //
//----------------------------------------------------------------------------------//
DWORD
DeInitializeWaitGlobal(
)
{
PLIST_ENTRY ple, pHead;
PWAIT_THREAD_ENTRY pwte;
ENTER_CRITICAL_SECTION(&WTG.g_CS, "g_CS", "DeInitializeWaitGlobal");
if (WTG.g_Initialized==0) {
LEAVE_CRITICAL_SECTION(&WTG.g_CS, "g_CS", "DeInitializeWaitGlobal");
TRACE0(LEAVE, "leaving DeInitializeWaitGlobal:Pending");
return ERROR_CAN_NOT_COMPLETE;
}
else
WTG.g_Initialized = 0;
//
// if waitThreadEntries exist, then for each server entry mark each event/binding
// as deleted and return pending
//
if (!IsListEmpty(&WTG.gL_WaitThreadEntries)) {
pHead = &WTG.gL_WaitThreadEntries;
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
pwte = CONTAINING_RECORD(ple, WAIT_THREAD_ENTRY, wte_Links);
ENTER_CRITICAL_SECTION(&pwte->wte_CS, "deleting wte_CS", "DeInitializeWaitGlobal");
pwte->wte_Status = WT_STATUS_DELETED;
}
//todo should I also mark each event and timer as deleted
TRACE0(LEAVE, "leaving DeInitializeWaitGlobal:Pending");
return ERROR_CAN_NOT_COMPLETE;
}
DeInitializeWaitGlobalComplete();
return NO_ERROR;
} //end DeInitializeWaitGlobal
//----------------------DeInitializeWaitGlobalComplete-----------------------------//
DWORD
DeInitializeWaitGlobalComplete (
)
{
TRACE0(LEAVE, "leaving DeInitializeWaitGlobal");
// for each server entry mark each event/binding as deleted
// and return pending
TraceDeregister(WTG.g_TraceId);
RouterLogDeregister(WTG.g_LogHandle);
// delete critical section
try{
DeleteCriticalSection(&WTG.g_CS);
}
except (EXCEPTION_EXECUTE_HANDLER) {
}
// destroy heap
/*if (WTG.g_Heap != NULL) {
HeapDestroy(WTG.g_Heap);
}*/
return NO_ERROR;
} //end DeInitializeWaitGlobal
//++-------------------------------------------------------------------------------*//
// InsertWaitThreadEntry //
// insert the new wait server thread into a list of increasing ServerIds //
// initializes the serverId //
// assumes: it has lock on WTG.g_cs, and pwte->wte_CS, and pwte->wte_CSTimer //
// NO CALLS TO APIS SHOULD BE MADE HERE //
//----------------------------------------------------------------------------------//
DWORD
InsertWaitThreadEntry (
IN PWAIT_THREAD_ENTRY pwteInsert
)
{
PLIST_ENTRY ple, pHead;
PWAIT_THREAD_ENTRY pwte;
DWORD dwServerId;
//
// find the lowest unallocated SeverId and insert the new server in the ordered list
//
dwServerId = 1;
pHead = &WTG.gL_WaitThreadEntries;
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink,dwServerId++) {
pwte = CONTAINING_RECORD(ple, WAIT_THREAD_ENTRY, wte_Links);
if (dwServerId==pwte->wte_ServerId) {
continue;
}
else
break;
}
// insert in list
if (dwServerId==1) { // not required. but kept for easy understanding
InsertHeadList(&WTG.gL_WaitThreadEntries, &pwteInsert->wte_Links);
}
else {
InsertTailList(ple, &pwteInsert->wte_Links);
}
// set serverId
pwteInsert->wte_ServerId = dwServerId;
pwteInsert->wte_Status = WT_STATUS_REGISTERED;
return NO_ERROR;
} //end InsertWaitThreadEntry
//---------------------------------------------------------------------------------*//
// RemoveWaitThreadEntry //
// removes a wait server thread from the list of servers //
// assumes: it has lock on WTG.g_cs and wte_CS //
//----------------------------------------------------------------------------------//
DWORD
DeleteWaitThreadEntry (
IN PWAIT_THREAD_ENTRY pwte
)
{
// set status to deleted
pwte->wte_Status = WT_STATUS_DELETED;
// if RefCount == 0, then remove it from the list and free it
if (pwte->wte_RefCount==0) {
// free the wait thread entry
RemoveEntryList(&pwte->wte_Links);
FreeWaitThreadEntry(pwte);
// deinitialize global structure if it is also marked for delete and its
// WaitThreadEntry list is empty
if ((WTG.g_Initialized==WT_STATUS_DELETED)
&&(IsListEmpty(&WTG.gL_WaitThreadEntries)))
{
DeInitializeWaitGlobalComplete();
}
}
return NO_ERROR;
}
//---------------------------------------------------------------------------------*//
// CreateWaitThreadEntry //
// creates a wait thread entry and initializes it //
// no locks required //
//----------------------------------------------------------------------------------//
DWORD
CreateWaitThreadEntry (
IN DWORD dwThreadId,
OUT PWAIT_THREAD_ENTRY *ppwte
)
{
PWAIT_THREAD_ENTRY pwte;
DWORD dwErr = NO_ERROR;
BOOL bErr = TRUE;
TRACE0(ENTER, "Entering CreateWaitThreadEntry");
//
// allocate wait-thread-entry entry
//
*ppwte = pwte = WT_MALLOC(sizeof(WAIT_THREAD_ENTRY));
if (pwte == NULL) {
dwErr = GetLastError();
TRACE2(
ANY, "error %d allocating %d bytes for wait-thread-entry",
dwErr, sizeof(WAIT_THREAD_ENTRY)
);
LOGERR0(HEAP_ALLOC_FAILED, dwErr);
return dwErr;
}
ZeroMemory(pwte, sizeof(WAIT_THREAD_ENTRY));
//
// initialize global structure
//
do { // error breakout loop
// critical section
try {
InitializeCriticalSection(&pwte->wte_CS);
}
except (EXCEPTION_EXECUTE_HANDLER) {
dwErr = GetExceptionCode();
TRACE1(
ANY, "exception %d initializing global critical section",
dwErr
);
LOGERR0(INIT_CRITSEC_FAILED, dwErr);
break;
}
// current clients
//server id is set when it is inserted into global list
pwte->wte_ThreadId = dwThreadId; //ServerId is assigned during insertion of wte
pwte->wte_NumClients = 0;
// list for events/timers
InitializeListHead(&pwte->wteL_ClientEventEntries);
InitializeListHead(&pwte->wteL_ClientTimerEntries);
// create waitable timer
pwte->wte_Timer = CreateWaitableTimer(NULL, FALSE, NULL);
if (pwte->wte_Timer == NULL) {
dwErr = GetLastError();
TRACE1(
ANY, "error creating waitable timer",
dwErr
);
LOGERR0(CREATE_WAITABLE_TIMER_FAILED, dwErr);
break;
}
SET_TIMER_INFINITE(pwte->wte_Timeout); //set timeout to infinity
// critical section for timers
try {
InitializeCriticalSection(&pwte->wte_CSTimer);
}
except (EXCEPTION_EXECUTE_HANDLER) {
dwErr = GetExceptionCode();
TRACE1(
ANY, "exception %d initializing critical section for timer",
dwErr
);
LOGERR0(INIT_CRITSEC_FAILED, dwErr);
break;
}
// array for WaitForMultipleObjects
pwte->wte_LowIndex = 0;
pwte->wte_NumTotalEvents = 0;
pwte->wte_NumActiveEvents = 0;
pwte->wte_NumHighPriorityEvents = 0;
pwte->wte_NumActiveHighPriorityEvents = 0;
//
// adding/deleting events/timers
//
// create event: Client notifies WT: wake up WT to add/delete events/timers
pwte->wte_ClientNotifyWTEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (pwte->wte_ClientNotifyWTEvent == NULL) {
dwErr = GetLastError();
TRACE1(START, "error %d creating event Client-notify-WT", dwErr);
LOGERR0(CREATE_EVENT_FAILED, dwErr);
break;
}
// create event: WT notifies Client: the work requested has been done
pwte->wte_WTNotifyClientEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (pwte->wte_WTNotifyClientEvent == NULL) {
dwErr = GetLastError();
TRACE1(START, "error:%d creating event WT-notify-Client", dwErr);
LOGERR0(CREATE_EVENT_FAILED, dwErr);
break;
}
// variables used to add/delete events/timers
pwte->wte_ChangeType = CHANGE_TYPE_NONE;
pwte->wte_Status = 0;
pwte->wte_RefCount = 0;
pwte->wtePL_EventsToChange = NULL;
pwte->wtePL_TimersToChange = NULL;
bErr = FALSE;
} while (FALSE);
TRACE1(LEAVE, "Leaving CreateWaitThreadEntry: %d", dwErr);
if (bErr) {
FreeWaitThreadEntry(pwte);
return dwErr;
}
else
return NO_ERROR;
}//end CreateWaitThreadEntry
//---------------------------------------------------------------------------------*//
// FreeWaitThreadEntry //
//----------------------------------------------------------------------------------//
DWORD
FreeWaitThreadEntry (
IN PWAIT_THREAD_ENTRY pwte
)
{
DWORD dwErr = NO_ERROR;
TRACE0(ENTER, "Entering FreeWaitThreadEntry");
DeleteCriticalSection(&pwte->wte_CS);
// delete waitable timer
if (pwte->wte_Timer!=NULL)
CloseHandle(pwte->wte_Timer);
DeleteCriticalSection(&pwte->wte_CSTimer);
// delete event: Client notifies WT
if (pwte->wte_ClientNotifyWTEvent!=NULL)
CloseHandle(&pwte->wte_ClientNotifyWTEvent);
// delete event: WT notifies Client
if (pwte->wte_WTNotifyClientEvent!=NULL)
CloseHandle(pwte->wte_WTNotifyClientEvent);
//
// free wait-thread-entry record
//
WT_FREE(pwte);
// deinitialize global structure if it is also marked for delete and its
// WaitThreadEntry list is empty
if ((WTG.g_Initialized==WT_STATUS_DELETED)
&&(IsListEmpty(&WTG.gL_WaitThreadEntries)))
{
DeInitializeWaitGlobalComplete();
}
TRACE1(LEAVE, "Leaving FreeWaitThreadEntry: %d", dwErr);
return NO_ERROR;
} //end FreeWaitThreadEntry
//----------------------------------------------------------------------------------//
// GetWaitThread //
// returns a wait thread which has the required number of free events //
// assumes lock on g_CS. //
// if NumTotalEvents is low enough, do interlocked increment. //
//----------------------------------------------------------------------------------//
PWAIT_THREAD_ENTRY
GetWaitThread (
IN DWORD dwNumEventsToAdd, //==0, if only timers are being added
IN DWORD dwNumTimersToadd
)
{
PLIST_ENTRY ple, pHead;
PWAIT_THREAD_ENTRY pwte;
BOOL bFound;
DWORD dwIncrRefCount = dwNumEventsToAdd + dwNumTimersToadd;
pHead = &WTG.gL_WaitThreadEntries;
//
// Locate a wait-thread with required events free.
//
bFound = FALSE;
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
pwte = CONTAINING_RECORD(ple, WAIT_THREAD_ENTRY, wte_Links);
// cannot allocate this server because it is not active
if ((pwte->wte_Status != WT_STATUS_REGISTERED)
&& (pwte->wte_Status != WT_STATUS_ACTIVE)
)
{
ETRACE0("could not allocate this wte as it is not registered");
continue;
}
if (NUM_CLIENT_EVENTS_FREE(pwte) >= dwNumEventsToAdd) {
// increment RefCount so that it cannot be deleted
// interlocked operation as it can be decremented outside g_CS and inside only wte_CS
InterlockedExchangeAdd((PLONG)&pwte->wte_RefCount, dwIncrRefCount);
InterlockedExchangeAdd((PLONG)&pwte->wte_NumTotalEvents,
(LONG)dwNumEventsToAdd);
bFound = TRUE;
break;
}
}
if (bFound) {
//shift the wte to the end so that all server threads are balanced
RemoveEntryList(ple);
InsertTailList(pHead, ple);
return pwte;
}
else {
return NULL;
}
}
//----------------------------------------------------------------------------------//
// RegisterClientEventLocal //
// Register the wait event locally //
// event being registered by the server itself: //
// assumes lock on server //
// somewhat similar to AddClientEvent //
//----------------------------------------------------------------------------------//
DWORD
RegisterClientEventLocal (
IN PWT_EVENT_ENTRY pee,
IN PWAIT_THREAD_ENTRY pwte
)
{
// insert wait event in list of event entries //dont have to do interlocked here
pwte->wte_RefCount ++;
pwte->wte_NumTotalEvents ++;
InsertInEventsList(pee, pwte);
// insert wait event in array of event entries
if (pee->ee_bInitialState == FALSE) {
InsertInEventsArray(pee, pwte);
}
else {
pee->ee_Status = WT_STATUS_INACTIVE + WT_STATUS_FIRED; // but arrayIndex ==-1
}
return NO_ERROR;
}
//----------------------------------------------------------------------------------//
// InsertInEventsList //
// assumes lock on server //
// Insert the event in the list and increment the counters //
// NumTotalEvents has been increased during allocation of the server //
//----------------------------------------------------------------------------------//
VOID
InsertInEventsList (
IN PWT_EVENT_ENTRY pee,
IN PWAIT_THREAD_ENTRY pwte
)
{
InsertHeadList(&pwte->wteL_ClientEventEntries, &pee->ee_ServerLinks);
//
// set fields of event entry
//
pee->ee_ServerId = pwte->wte_ServerId;
pee->eeP_wte = pwte;
pee->ee_Status = WT_STATUS_REGISTERED;
//
// change fields of wait thread entry
//
//pwte->wte_RefCount++; //RefCount incremented during allocation
//pwte->wte_NumTotalEvents ++; //incremented during allocation
if (pee->ee_bHighPriority) {
pwte->wte_NumHighPriorityEvents ++;
}
return;
}
//----------------------------------------------------------------------------------//
// DeleteFromEventsList //
// NumTotalEvents/Refcount is interlockedDecremented //
//----------------------------------------------------------------------------------//
VOID
DeleteFromEventsList (
IN PWT_EVENT_ENTRY pee,
IN PWAIT_THREAD_ENTRY pwte
)
{
// remove entry from list
RemoveEntryList(&pee->ee_ServerLinks);
//
// set fields of event entry
//
pee->ee_Status = WT_STATUS_DELETED;
//
// change fields of wait thread entry
//
// pwte->wte_NumTotalEvents ++; interlocked incremented during allocation
if (pee->ee_bHighPriority) {
pwte->wte_NumHighPriorityEvents --;
}
InterlockedDecrement(&pwte->wte_NumTotalEvents);
// decremented in DeleteClientEventComplete if ee_RefCount is 0
//InterlockedDecrement(&pwte->wte_RefCount);
return;
}
//----------------------------------------------------------------------------------//
// DeleteFromEventsArray //
// pee: status is not set to inactive, but array pointer is set to -1 //
// pwte: decrement active counters //
//----------------------------------------------------------------------------------//
VOID
DeleteFromEventsArray (
IN PWT_EVENT_ENTRY pee,
IN PWAIT_THREAD_ENTRY pwte
)
{
INT iIndex;
DWORD dwCount;
iIndex = pee->ee_ArrayIndex;
dwCount = pwte->wte_NumActiveEvents + pwte->wte_LowIndex - iIndex - 1;
// shift right part towards left if its size is smaller
if (dwCount <= pwte->wte_NumActiveEvents/2) {
EventsArray_MoveOverlap (
pwte,
iIndex, //dstn
iIndex+1, //src
dwCount //count
);
}
// shift left part towards right
else {
EventsArray_MoveOverlap (
pwte,
pwte->wte_LowIndex+1, //dstn
pwte->wte_LowIndex, //src
pwte->wte_NumActiveEvents - dwCount -1 //count
);
pwte->wte_LowIndex ++;
}
// set fields of event entry
//
pee->ee_ArrayIndex = -1;
// change fields of wait thread entry
//
pwte->wte_NumActiveEvents --;
if (pee->ee_bHighPriority) {
pwte->wte_NumActiveHighPriorityEvents--;
}
}//end DeleteFromEventsArray
//----------------------------------------------------------------------------------//
// InsertInEventsArray //
// assumes lock on server:wte_CS :todo is the lock required //
// Insert the event in the events array and the map array (no checks are performed)//
// pee: status set to active, set index to array position //
// pwte: increment active counters //
//----------------------------------------------------------------------------------//
VOID
InsertInEventsArray (
IN PWT_EVENT_ENTRY pee,
IN PWAIT_THREAD_ENTRY pwte
)
{
INT iIndex;
// if the array is filled to the extreme right, then shift all events to the left end
if (EA_OVERFLOW(pwte, 1))
EventsArray_CopyLeftEnd(pwte);
//
// get index where it has to be inserted
//
if (pee->ee_bHighPriority) {
// the highPriority event has to be moved to the place right of the righmost HighPriority event
iIndex = EA_INDEX_LOW_LOW_PRIORITY_EVENT(pwte);
//copy the 1st low priority event to end+1;
if (EA_EXISTS_LOW_PRIORITY_EVENT(pwte)) {
EventsArray_Move(pwte,
EA_INDEX_HIGH_LOW_PRIORITY_EVENT(pwte)+1, //dstn
iIndex, //src
1 //count
);
}
}
else { // low priority event: insert in the end
iIndex = EA_INDEX_HIGH_LOW_PRIORITY_EVENT(pwte)+1;
}
// insert the event
EventsArray_InsertEvent(pee, pwte, iIndex);
// set fields of event entry
//
pee->ee_Status = WT_STATUS_ACTIVE;
pee->ee_ArrayIndex = iIndex;
// change fields of wait thread entry
//
pwte->wte_NumActiveEvents ++;
if (pee->ee_bHighPriority) {
pwte->wte_NumActiveHighPriorityEvents++;
}
}//end InsertInEventsArray
//----------------------------------------------------------------------------------//
// InactivateEvent //
// Remove the event from the arrays and set the inactive flag // //
// Used with bManual reset //
//----------------------------------------------------------------------------------//
VOID
InactivateEvent (
IN PWT_EVENT_ENTRY pee
)
{
DWORD dwIndex;
PWAIT_THREAD_ENTRY pwte;
dwIndex = pee->ee_ArrayIndex;
pwte = pee->eeP_wte;
// if event is not at the right end of the array, then events on its right have to be shifted
if (dwIndex != EA_INDEX_HIGH_LOW_PRIORITY_EVENT(pwte)) {
EventsArray_MoveOverlap(pwte, dwIndex, dwIndex+1,
(pwte->wte_NumActiveEvents + pwte->wte_LowIndex - dwIndex -1)
);
}
//
// change fields in event entry to make it inactive
//
pee->ee_ArrayIndex = -1;
pee->ee_Status = (pee->ee_Status&WT_STATUS_FIRED) + WT_STATUS_INACTIVE;
//
// change fields in wait thread entry
//
pwte->wte_NumActiveEvents --;
if (pee->ee_bHighPriority) {
pwte->wte_NumActiveHighPriorityEvents --;
}
return;
}
//----------------------------------------------------------------------------------//
// EventsArray_CopyLeftEnd //
// copy all the events to the left end of the array //
// sets the wte_LowIndex value //
//----------------------------------------------------------------------------------//
VOID
EventsArray_CopyLeftEnd (
IN PWAIT_THREAD_ENTRY pwte
)
{
EventsArray_Move(pwte,
0, //dstn
pwte->wte_LowIndex, //src
pwte->wte_NumActiveEvents //count
);
//
// change fields of wait thread entry
//
pwte->wte_LowIndex = 0;
return;
}
//----------------------------------------------------------------------------------//
// EventsArray_Move //
// copy dwCount events from the srcIndex to dstnIndex (no overlap) //
//----------------------------------------------------------------------------------//
VOID
EventsArray_Move (
IN PWAIT_THREAD_ENTRY pwte,
IN DWORD dwDstnIndex,
IN DWORD dwSrcIndex,
IN DWORD dwCount
)
{
PWT_EVENT_ENTRY pee;
DWORD i;
if (dwCount==0)
return;
CopyMemory( &pwte->wteA_Events[dwDstnIndex],
&pwte->wteA_Events[dwSrcIndex],
sizeof(HANDLE) * dwCount
);
CopyMemory( &pwte->wteA_EventMapper[dwDstnIndex],
&pwte->wteA_EventMapper[dwSrcIndex],
sizeof(PWT_EVENT_ENTRY) * dwCount
);
for (i=0; i<dwCount; i++) {
pee = pwte->wteA_EventMapper[dwDstnIndex + i];
pee->ee_ArrayIndex = dwDstnIndex + i;
}
return;
}
//----------------------------------------------------------------------------------//
// EventsArray_MoveOverlap //
// copy dwCount events from the srcIndex to dstnIndex (with overlap) //
//----------------------------------------------------------------------------------//
VOID
EventsArray_MoveOverlap (
IN PWAIT_THREAD_ENTRY pwte,
IN DWORD dwDstnIndex,
IN DWORD dwSrcIndex,
IN DWORD dwCount
)
{
PWT_EVENT_ENTRY pee;
DWORD i;
if (dwCount==0)
return;
MoveMemory( &pwte->wteA_Events[dwDstnIndex],
&pwte->wteA_Events[dwSrcIndex],
sizeof(HANDLE) * dwCount
);
MoveMemory( &pwte->wteA_EventMapper[dwDstnIndex],
&pwte->wteA_EventMapper[dwSrcIndex],
sizeof(PWT_EVENT_ENTRY) * dwCount
);
for (i=0; i<dwCount; i++) {
pee = pwte->wteA_EventMapper[dwDstnIndex + i];
pee->ee_ArrayIndex = dwDstnIndex + i;
}
return;
}
//----------------------------------------------------------------------------------//
// EventsArray_InsertEvent //
// Insert the event in the events array and the map array //
//----------------------------------------------------------------------------------//
VOID
EventsArray_InsertEvent (
IN PWT_EVENT_ENTRY pee,
IN PWAIT_THREAD_ENTRY pwte,
IN INT iIndex
)
{
// insert event in events array
pwte->wteA_Events[iIndex] = pee->ee_Event;
// insert pointer in map array
pwte->wteA_EventMapper[iIndex] = pee;
return;
}
//---------------------------------------------------------------------------------*//
// GetListLength //
// returns the length of the list //
// returns 0 if the list contains the header only //
//----------------------------------------------------------------------------------//
INT
GetListLength (
IN PLIST_ENTRY pHead
)
{
PLIST_ENTRY ple;
DWORD dwCount=0;
if (pHead==NULL)
return -1;
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
dwCount++;
}
return dwCount;
}
VOID
PrintEvent (
PWT_EVENT_ENTRY pee,
DWORD level
)
{
PLIST_ENTRY pHead, ple;
PWT_WORK_ITEM pwi;
if (pee->ee_Event==NULL)
printf(" Event is NULL\n");
printf("-- -------------------------------------------------------------------------\n");
printf("-- <%2d><ee_bManualReset:%2d> <ee_bInitialState:%2d> <ee_Status:%2d> <ee_bHighPriority:%2d>\n",
pee->ee_EventId, pee->ee_bManualReset, pee->ee_bInitialState, pee->ee_Status,
pee->ee_bHighPriority);
printf("-- <ee_bSignalSingle:%2d> <ee_bOwnerSelf:%2d> <ee_ArrayIndex:%2d> <ee_ServerId:4%d>\n",
pee->ee_bSignalSingle, pee->ee_bOwnerSelf, pee->ee_ArrayIndex, pee->ee_ServerId);
printf("-- <ee_RefCount:%d\n", pee->ee_RefCount);
pHead = &pee->eeL_wi;
printf("-- LIST OF EVENT BINDINGS\n");
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
pwi = CONTAINING_RECORD(ple, WT_WORK_ITEM, wi_ServerLinks);
printf("-- <wi_ContextSz:%lu> <wi_RunInServer:%d> <wiP_ee:%lu>\n",
pwi->wi_ContextSz, pwi->wi_RunInServer, (UINT_PTR)(PVOID)pwi->wiP_ee);
}
return;
}
VOID
PrintTimer (
PWT_TIMER_ENTRY pte,
DWORD level
)
{
LARGE_INTEGER li;
TRACE0(WAIT_TIMER,"__ ________________________________________________________________________");
TRACE4(WAIT_TIMER, "__ <TimerId:%2d><Timeout:%lu:%lu> <te_ContextSz:%lu>",
pte->te_TimerId, TIMER_HIGH(pte->te_Timeout), TIMER_LOW(pte->te_Timeout), pte->te_ContextSz);
TRACE3(WAIT_TIMER, "__ <te_RunInServer:%1d> <te_Status:%1d> <te_ServerId:%d>",
pte->te_RunInServer, pte->te_Status, pte->te_ServerId);
return;
}
//----------------------------------------------------------------------------------//
// PrintWaitThreadEntry //
// Prints the events and timers registered with this server. //
//----------------------------------------------------------------------------------//
VOID
PrintWaitThreadEntry (
PWAIT_THREAD_ENTRY pwte,
DWORD level
)
{
PLIST_ENTRY ple, pHead;
PWT_EVENT_ENTRY pee;
PWT_TIMER_ENTRY pte;
DWORD dwHigh, dwLow;
LARGE_INTEGER li;
BOOL bPrint;
DWORD i;
TRACE0(WAIT_TIMER, "\n");
TRACE0(WAIT_TIMER, "=================================================================================");
TRACE3(WAIT_TIMER, "== <wte_ServerId:%2lu> <wte_ThreadId:%2lu> <wte_NumClients:%2lu>",
pwte->wte_ServerId, pwte->wte_ThreadId, pwte->wte_NumClients);
TRACE2(WAIT_TIMER, "== <wte_Status:%2lu> <wte_RefCount:%2lu>", pwte->wte_Status, pwte->wte_RefCount);
//
// print list of events registered
//
if (!(level&DEBUGPRINT_FILTER_EVENTS)) {
TRACE0(WAIT_TIMER, "-- ");
TRACE0(WAIT_TIMER, "---------------------------------------------------------------------------------");
TRACE2(WAIT_TIMER,"-- <wte_LowIndex:%2lu> <wte_NumTotalEvents:%2lu>",
pwte->wte_LowIndex, pwte->wte_NumTotalEvents);
TRACE2(WAIT_TIMER, "-- <wte_NumActiveEvents:%2lu> <wte_NumHighPriorityEvents:%2lu>",
pwte->wte_NumActiveEvents, pwte->wte_NumHighPriorityEvents);
TRACE1(WAIT_TIMER, "-- <wte_NumActiveHighPriorityEvents:%2lu>", pwte->wte_NumActiveHighPriorityEvents);
if (level&0x2) {//dont print the initial 4 reserved events
bPrint = FALSE;
i = 0;
}
else
bPrint = TRUE;
TRACE0(WAIT_TIMER, "--");
pHead = &pwte->wteL_ClientEventEntries;
for (ple=pHead->Blink; ple!=pHead; ple=ple->Blink) {
if (!bPrint) {
if (++i==4)
bPrint=TRUE;
continue;
}
pee = CONTAINING_RECORD(ple, WT_EVENT_ENTRY, ee_ServerLinks);
PrintEvent(pee, level);
}
for (i=0; i<=10; i++) {
if (pwte->wteA_EventMapper[i]==NULL)
TRACE0(WAIT_TIMER, "--");
else
TRACE2(WAIT_TIMER, "<%d:%d>", (pwte->wteA_EventMapper[i])->ee_EventId,
(pwte->wteA_EventMapper[i])->ee_ArrayIndex);
}
}
//
// print list of timers registered
//
if (!(level&DEBUGPRINT_FILTER_TIMERS)) {
li = *(LARGE_INTEGER*)(PVOID)&pwte->wte_Timeout;
dwHigh = li.HighPart;
dwLow = li.LowPart;
TRACE0(WAIT_TIMER, "--");
TRACE0(WAIT_TIMER,"_________________________________________________________________________________");
TRACE2(WAIT_TIMER, "__ <wte_Timeout.high:%lu> <wte_Timeout.low:%lu>", dwHigh, dwLow);
pHead = &pwte->wteL_ClientTimerEntries;
for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
pte = CONTAINING_RECORD(ple, WT_TIMER_ENTRY, te_ServerLinks);
PrintTimer(pte, level);
}
}
return;
} //PrintWaitThreadEntry