summaryrefslogtreecommitdiffstats
path: root/private/unimodem/tapisp/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/unimodem/tapisp/timer.c')
-rw-r--r--private/unimodem/tapisp/timer.c527
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;
+
+}