/********************************************************************/ /** Copyright(c) 1989 Microsoft Corporation. **/ /********************************************************************/ //*** // // Filename: timer.c // // Description: All timer queue related funtions live here. // // History: // Nov 11,1993. NarenG Created original version. // #include #include #include // needed for winbase.h #include // Win32 base API's #include #include #include #include #include #include #include #include #include #include #include #include //** // // Call: MakeTimeoutWorkItem // // Returns: PCB_WORK_ITEM * - Pointer to the timeout work item // NULL - On any error. // // Description: // PCB_WORK_ITEM * MakeTimeoutWorkItem( IN DWORD dwPortId, IN HPORT hPort, IN DWORD Protocol, IN DWORD Id, IN BOOL fAuthenticator, IN TIMER_EVENT_TYPE EventType ) { PCB_WORK_ITEM * pWorkItem = (PCB_WORK_ITEM *) LOCAL_ALLOC( LPTR, sizeof( PCB_WORK_ITEM ) ); if ( pWorkItem == (PCB_WORK_ITEM *)NULL ) { LogPPPEvent( ROUTERLOG_NOT_ENOUGH_MEMORY, 0 ); return( NULL ); } pWorkItem->dwPortId = dwPortId; pWorkItem->Id = Id; pWorkItem->hPort = hPort; pWorkItem->Protocol = Protocol; pWorkItem->fAuthenticator = fAuthenticator; pWorkItem->TimerEventType = EventType; pWorkItem->Process = ProcessTimeout; return( pWorkItem ); } //** // // Call: TimerTick // // Returns: None. // // Description: Called each second if there are elements in the timeout queue. // VOID TimerTick( OUT BOOL * pfQueueEmpty ) { TIMER_EVENT * pTimerEvent; TIMER_EVENT * pTimerEventTmp; if ( ( pTimerEvent = TimerQ.pQHead ) == (TIMER_EVENT*)NULL ) { *pfQueueEmpty = TRUE; return; } *pfQueueEmpty = FALSE; // // Decrement time on the first element // if ( pTimerEvent->Delta > 0 ) { (pTimerEvent->Delta)--; return; } // // Now run through and remove all completed (delta 0) elements. // while ( (pTimerEvent != (TIMER_EVENT*)NULL) && (pTimerEvent->Delta == 0) ) { pTimerEvent = pTimerEvent->pNext; } if ( pTimerEvent == (TIMER_EVENT*)NULL ) { pTimerEvent = TimerQ.pQHead; TimerQ.pQHead = (TIMER_EVENT*)NULL; } else { pTimerEvent->pPrev->pNext = (TIMER_EVENT*)NULL; pTimerEvent->pPrev = (TIMER_EVENT*)NULL; pTimerEventTmp = TimerQ.pQHead; TimerQ.pQHead = pTimerEvent; pTimerEvent = pTimerEventTmp; } // // Now make a timeout work item and put it in the work item Q for all the // items with delta == 0 // while( pTimerEvent != (TIMER_EVENT*)NULL ) { PCB_WORK_ITEM * pWorkItem = MakeTimeoutWorkItem( pTimerEvent->dwPortId, pTimerEvent->hPort, pTimerEvent->Protocol, pTimerEvent->Id, pTimerEvent->fAuthenticator, pTimerEvent->EventType ); if ( pWorkItem == ( PCB_WORK_ITEM *)NULL ) { LogPPPEvent( ROUTERLOG_NOT_ENOUGH_MEMORY, GetLastError() ); } else { InsertWorkItemInQ( pWorkItem ); } if ( pTimerEvent->pNext == (TIMER_EVENT *)NULL ) { LOCAL_FREE( pTimerEvent ); pTimerEvent = (TIMER_EVENT*)NULL; } else { pTimerEvent = pTimerEvent->pNext; LOCAL_FREE( pTimerEvent->pPrev ); } } } //** // // Call: InsertInTimerQ // // Returns: NO_ERROR - Success // return from GetLastError() - Failure // // Description: Adds a timeout element into the delta queue. If the Timer is not // started it is started. Since there is a LocalAlloc() call here - // this may fail in which case it will simply not insert it in the // queue and the request will never timeout. BAP passes in an HCONN in // hPort. // DWORD InsertInTimerQ( IN DWORD dwPortId, IN HPORT hPort, IN DWORD Id, IN DWORD Protocol, IN BOOL fAuthenticator, IN TIMER_EVENT_TYPE EventType, IN DWORD Timeout ) { TIMER_EVENT * pLastEvent; TIMER_EVENT * pTimerEventWalker; TIMER_EVENT * pTimerEvent = (TIMER_EVENT *)LOCAL_ALLOC( LPTR, sizeof(TIMER_EVENT)); if ( pTimerEvent == (TIMER_EVENT *)NULL ) { PppLog( 1, "InsertInTimerQ failed: out of memory" ); return( GetLastError() ); } PppLog( 2, "InsertInTimerQ called portid=%d,Id=%d,Protocol=%x," "EventType=%d,fAuth=%d", dwPortId, Id, Protocol, EventType, fAuthenticator ); pTimerEvent->dwPortId = dwPortId; pTimerEvent->Id = Id; pTimerEvent->Protocol = Protocol; pTimerEvent->hPort = hPort; pTimerEvent->EventType = EventType; pTimerEvent->fAuthenticator = fAuthenticator; for ( pTimerEventWalker = TimerQ.pQHead, pLastEvent = pTimerEventWalker; ( pTimerEventWalker != NULL ) && ( pTimerEventWalker->Delta < Timeout ); pLastEvent = pTimerEventWalker, pTimerEventWalker = pTimerEventWalker->pNext ) { Timeout -= pTimerEventWalker->Delta; } // // Insert before pTimerEventWalker. If pTimerEventWalker is NULL then // we insert at the end of the list. // if ( pTimerEventWalker == (TIMER_EVENT*)NULL ) { // // If the list was empty // if ( TimerQ.pQHead == (TIMER_EVENT*)NULL ) { TimerQ.pQHead = pTimerEvent; pTimerEvent->pNext = (TIMER_EVENT *)NULL; pTimerEvent->pPrev = (TIMER_EVENT *)NULL; // // Wake up thread since the Q is not empty any longer // SetEvent( TimerQ.hEventNonEmpty ); } else { pLastEvent->pNext = pTimerEvent; pTimerEvent->pPrev = pLastEvent; pTimerEvent->pNext = (TIMER_EVENT*)NULL; } } else if ( pTimerEventWalker == TimerQ.pQHead ) { // // Insert before the first element // pTimerEvent->pNext = TimerQ.pQHead; TimerQ.pQHead->pPrev = pTimerEvent; TimerQ.pQHead->Delta -= Timeout; pTimerEvent->pPrev = (TIMER_EVENT*)NULL; TimerQ.pQHead = pTimerEvent; } else { // // Insert middle element // pTimerEvent->pNext = pLastEvent->pNext; pLastEvent->pNext = pTimerEvent; pTimerEvent->pPrev = pLastEvent; pTimerEventWalker->pPrev = pTimerEvent; pTimerEventWalker->Delta -= Timeout; } pTimerEvent->Delta = Timeout; return( NO_ERROR ); } //** // // Call: RemoveFromTimerQ // // Returns: None. // // Description: Will remove a timeout event for a certain Id,hPort combination // from the delta Q. // VOID RemoveFromTimerQ( IN DWORD dwPortId, IN DWORD Id, IN DWORD Protocol, IN BOOL fAuthenticator, IN TIMER_EVENT_TYPE EventType ) { TIMER_EVENT * pTimerEvent; PppLog( 2, "RemoveFromTimerQ called portid=%d,Id=%d,Protocol=%x," "EventType=%d,fAuth=%d", dwPortId, Id, Protocol, EventType, fAuthenticator ); for ( pTimerEvent = TimerQ.pQHead; ( pTimerEvent != (TIMER_EVENT *)NULL ) && ( ( pTimerEvent->EventType != EventType ) || ( pTimerEvent->dwPortId != dwPortId ) || ( ( pTimerEvent->EventType == TIMER_EVENT_TIMEOUT ) && ( ( pTimerEvent->Id != Id ) || ( pTimerEvent->Protocol != Protocol ) || ( pTimerEvent->fAuthenticator != fAuthenticator ) ) ) ); pTimerEvent = pTimerEvent->pNext ); // // If event was not found simply return. // if ( pTimerEvent == (TIMER_EVENT *)NULL ) { return; } // // If this is the first element to be removed // if ( pTimerEvent == TimerQ.pQHead ) { TimerQ.pQHead = pTimerEvent->pNext; if ( TimerQ.pQHead != (TIMER_EVENT *)NULL ) { TimerQ.pQHead->pPrev = (TIMER_EVENT*)NULL; TimerQ.pQHead->Delta += pTimerEvent->Delta; } } else if ( pTimerEvent->pNext == (TIMER_EVENT*)NULL ) { // // If this was the last element to be removed // pTimerEvent->pPrev->pNext = (TIMER_EVENT*)NULL; } else { pTimerEvent->pNext->Delta += pTimerEvent->Delta; pTimerEvent->pPrev->pNext = pTimerEvent->pNext; pTimerEvent->pNext->pPrev = pTimerEvent->pPrev; } LOCAL_FREE( pTimerEvent ); }