diff options
Diffstat (limited to 'private/unimodem/tapisp/timer.c')
-rw-r--r-- | private/unimodem/tapisp/timer.c | 527 |
1 files changed, 527 insertions, 0 deletions
diff --git a/private/unimodem/tapisp/timer.c b/private/unimodem/tapisp/timer.c new file mode 100644 index 000000000..cb22775d5 --- /dev/null +++ b/private/unimodem/tapisp/timer.c @@ -0,0 +1,527 @@ +//**************************************************************************** +// +// Module: Unimdm +// File: timer.c +// +// Copyright (c) 1992-1996, Microsoft Corporation, all rights reserved +// +// Revision History +// +// +// +// +// Description: +// +//**************************************************************************** + +#include "unimdm.h" +#include "umdmspi.h" + +#include "timer.h" + +typedef struct _TIMER_CONTROL { + + CRITICAL_SECTION Lock; + + PUNIMODEM_TIMER TimerToBeSet; + + HANDLE Event; + + HANDLE ThreadHandle; + + DWORD ThreadID; + + BOOL TimerEnd; + + HANDLE TimerThreadRunningEvent; + + CRITICAL_SECTION CancelCriticalSection; + +} TIMER_CONTROL, *PTIMER_CONTROL; + +VOID WINAPI +TimerThreadProc( + PTIMER_CONTROL TimerControl + ); + +VOID WINAPI +TimerApcRoutine( + PUNIMODEM_TIMER ThisTimer, + DWORD LowTime, + DWORD HighTime + ); + + +TIMER_CONTROL TimerControlBlock; + +LONG WINAPI +InitializeTimerThread( + VOID + ) + +{ + LONG Result; + PTIMER_CONTROL TimerControl; + + TimerControl=&TimerControlBlock; + + TimerControl->TimerEnd=FALSE; + + TimerControl->TimerToBeSet=NULL; + + InitializeCriticalSection( + &TimerControl->Lock + ); + + + InitializeCriticalSection( + &TimerControl->CancelCriticalSection + ); + + TimerControl->Event=CreateEvent( + NULL, + FALSE, // autoreset + FALSE, // reset + NULL + ); + + + if (TimerControl->Event == NULL) { + + return GetLastError(); + + } + + TimerControl->TimerThreadRunningEvent=CreateEvent( + NULL, + TRUE, // man reset + FALSE, // reset + NULL + ); + + if (TimerControl->TimerThreadRunningEvent == NULL) { + + Result=GetLastError(); + + CloseHandle(TimerControl->Event); + + return Result; + } + + TimerControl->ThreadHandle=CreateThread( + NULL, + 0, + TimerThreadProc, + TimerControl, + 0, + &TimerControl->ThreadID + ); + + if (TimerControl->ThreadHandle == NULL) { + + Result=GetLastError(); + + CloseHandle(TimerControl->TimerThreadRunningEvent); + + CloseHandle(TimerControl->Event); + + return Result; + } + + return ERROR_SUCCESS; + +} + + +VOID WINAPI +TimerThreadProc( + PTIMER_CONTROL TimerControl + ) + +{ + + while (!TimerControl->TimerEnd) { + + // + // if canceling, block here until the cancel code is done + // + EnterCriticalSection( + &TimerControl->CancelCriticalSection + ); + + D_TRACE(McxDpf(888,"TimerThreadProc: Past cancel spinlock");) + + // + // done running for now + // + ResetEvent( + TimerControl->TimerThreadRunningEvent + ); + + // + // release it now, since the cancel routine has done what it needed to + // + LeaveCriticalSection( + &TimerControl->CancelCriticalSection + ); + + D_TRACE(McxDpf(888,"TimerThreadProc: Thread waiting");) + + // + // wait for APC's, or our event to be signaled + // + WaitForSingleObjectEx( + TimerControl->Event, + INFINITE, + TRUE + ); + + D_TRACE(McxDpf(888,"TimerThreadProc: thread running");) + + // + // set this so the cancel code can tell when the thread non alertable + // + SetEvent( + TimerControl->TimerThreadRunningEvent + ); + + + + EnterCriticalSection( + &TimerControl->Lock + ); + + while (TimerControl->TimerToBeSet != NULL) { + + PUNIMODEM_TIMER NewTimer; + + NewTimer=TimerControl->TimerToBeSet; + + TimerControl->TimerToBeSet=NewTimer->Next; + + D_TRACE(McxDpf(888,"TimerThreadProc: Setting new timer");) + + SetWaitableTimer( + NewTimer->TimerHandle, + &NewTimer->DueTime, + 0, + TimerApcRoutine, + NewTimer, + FALSE + ); + + } + + LeaveCriticalSection( + &TimerControl->Lock + ); + + + + + } + + return; + +} + + +VOID WINAPI +TimerApcRoutine( + PUNIMODEM_TIMER TimerObject, + DWORD LowTime, + DWORD HighTime + ) + +{ + + TIMER_CALLBACK *Callback; + HANDLE Context1; + HANDLE Context2; + + + EnterCriticalSection( + &TimerObject->CriticalSection + ); + + Callback=TimerObject->CallbackProc; + Context1=TimerObject->Context1; + Context2=TimerObject->Context2; + + + TimerObject->CallbackProc=NULL; + TimerObject->Context1=NULL; + TimerObject->Context2=NULL; + + LeaveCriticalSection( + &TimerObject->CriticalSection + ); + + + (*Callback)( + Context1, + Context2 + ); + + return; + +} + + +HANDLE WINAPI +CreateUnimodemTimer( + VOID + ) + +{ + + PUNIMODEM_TIMER TimerObject; + + TimerObject=LocalAlloc(LPTR,sizeof(UNIMODEM_TIMER)); + + if (TimerObject == NULL) { + + return NULL; + } + + + TimerObject->Next=NULL; + + TimerObject->CallbackProc=NULL; + TimerObject->Context1=NULL; + TimerObject->Context2=NULL; + + InitializeCriticalSection( + &TimerObject->CriticalSection + ); + + + TimerObject->TimerHandle=CreateWaitableTimer( + NULL, + TRUE, + NULL + ); + + if (TimerObject->TimerHandle == NULL) { + + LocalFree(TimerObject); + + return NULL; + } + + return (HANDLE)TimerObject; + +} + +VOID WINAPI +FreeUnimodemTimer( + HANDLE TimerHandle + ) + +{ + PUNIMODEM_TIMER TimerObject=(PUNIMODEM_TIMER) TimerHandle; + + CancelUnimodemTimer( + TimerObject + ); + + + CloseHandle( + TimerObject->TimerHandle + ); + + LocalFree(TimerObject); + + return; +} + + + +VOID WINAPI +SetUnimodemTimer( + HANDLE TimerHandle, + DWORD Duration, + TIMER_CALLBACK CallbackFunc, + HANDLE Context1, + HANDLE Context2 + ) + +{ + + PUNIMODEM_TIMER TimerObject=(PUNIMODEM_TIMER) TimerHandle; + + EnterCriticalSection( + &TimerControlBlock.Lock + ); + + EnterCriticalSection( + &TimerObject->CriticalSection + ); + + D_TRACE(McxDpf(888,"SetUnimodemTimer: ");) + + TimerObject->Next=NULL; + + TimerObject->CallbackProc=CallbackFunc; + TimerObject->Context1=Context1; + TimerObject->Context2=Context2; + + + TimerObject->DueTime=Int32x32To64(Duration,-10000); + + + TimerObject->Next=TimerControlBlock.TimerToBeSet; + + TimerControlBlock.TimerToBeSet=TimerObject; + + SetEvent( + TimerControlBlock.Event + ); + + D_TRACE(McxDpf(888,"SetUnimodemTimer: Done");) + + LeaveCriticalSection( + &TimerObject->CriticalSection + ); + + LeaveCriticalSection( + &TimerControlBlock.Lock + ); + + return; + +} + + +BOOL WINAPI +CancelUnimodemTimer( + HANDLE TimerHandle + ) + +{ + + PUNIMODEM_TIMER TimerObject=(PUNIMODEM_TIMER) TimerHandle; + + PUNIMODEM_TIMER Current; + PUNIMODEM_TIMER Prev; + BOOL ReturnValue=TRUE; + + D_TRACE(McxDpf(888,"CancelUnimodemTimer: ");) + // + // enter the cancel critical section, so the timer thread will block + // + EnterCriticalSection( + &TimerControlBlock.CancelCriticalSection + ); + + D_TRACE(McxDpf(888,"CancelUnimodemTimer: Got cancel lock");) + // + // Signal the event, so the timer thread will run and block on the criical section + // + SetEvent( + TimerControlBlock.Event + ); + + D_TRACE(McxDpf(888,"CancelUnimodemTimer: Waiting for thread to run");) + // + // now wait for the thread to actaully run so we know it is not alerted + // + WaitForSingleObject( + TimerControlBlock.TimerThreadRunningEvent, + INFINITE + ); + + + EnterCriticalSection( + &TimerControlBlock.Lock + ); + + EnterCriticalSection( + &TimerObject->CriticalSection + ); + + + Prev=NULL; + + Current=TimerControlBlock.TimerToBeSet; + + // + // see if it waiting to be set + // + while (Current != NULL) { + + if (Current == TimerObject) { + // + // found it + // + if (Current == TimerControlBlock.TimerToBeSet) { + + TimerControlBlock.TimerToBeSet=Current->Next; + + } else { + + Prev->Next=Current->Next; + } + + TimerObject->Next=NULL; + TimerObject->CallbackProc=NULL; + + D_TRACE(McxDpf(888,"CancelUnimodemTimer: timer not set yet");) + + goto Done; + + } + + Prev=Current; + Current=Current->Next; + } + + // + // not on list + // + if (TimerObject->CallbackProc != NULL) { + // + // hasn't run yet, so kill it + // + D_TRACE(McxDpf(888,"CancelUnimodemTimer: Canceling pending timer");) + + CancelWaitableTimer( + TimerObject->TimerHandle + ); + + TimerObject->Next=NULL; + TimerObject->CallbackProc=NULL; + + } else { + // + // didn't get the timer, it has run + // + D_TRACE(McxDpf(888,"CancelUnimodemTimer: Missed timer");) + + ReturnValue=FALSE; + } + +Done: + + LeaveCriticalSection( + &TimerObject->CriticalSection + ); + + + LeaveCriticalSection( + &TimerControlBlock.Lock + ); + + + // + // Done canceling, let the thread go + // + LeaveCriticalSection( + &TimerControlBlock.CancelCriticalSection + ); + + D_TRACE(McxDpf(888,"CancelUnimodemTimer: done canceling");) + + return ReturnValue; + +} |