/*++ Copyright (c) 1994 Microsoft Corporation All rights reserved. Module Name: sleepn.cxx Abstract: Handles delayed callbacks. Delay must be < 49.7 days, and the callback must execute very quickly. Author: Albert Ting (AlbertT) 19-Dec-1994 Revision History: --*/ #include "spllibp.hxx" #pragma hdrstop TSleepNotify:: TSleepNotify( VOID ) /*++ Routine Description: Single thread that servers as a timer. Arguments: Return Value: Notes: _hEvent is our validity variable. --*/ { _hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); if( !_hEvent ){ return; } } #if 0 TSleepNotify:: ~TSleepNotify( VOID ) /*++ Routine Description: Destroys the SleepNotify. This should never be called since we never should destruct the object. Arguments: Return Value: --*/ { if( _hEvent ){ CloseHandle( _hEvent ); } } #endif VOID TSleepNotify:: vRun( VOID ) /*++ Routine Description: Main worker loop for callbacks. We will wait on an object to pickup new notifications, and when we time out, do the callback. Arguments: VOID Return Value: VOID: never returns. --*/ { DWORD dwTimeout; DWORD dwResult; VSleepWorker* pSleepWorker; TCritSecLock CSL( _CritSec ); while( TRUE ){ pSleepWorker = SleepWorker_pHead(); dwTimeout = pSleepWorker ? pSleepWorker->TickCountWake - GetTickCount() : INFINITE; { TCritSecUnlock CSU( _CritSec ); dwResult = WaitForSingleObject( _hEvent, dwTimeout ); } if( dwResult == WAIT_TIMEOUT ){ // // We added a new item, so go back to sleep with the // new timeout value. // continue; } // // Traverse linked list for all items that must be callbacked. // PDLINK pdlink; TICKCOUNT TickCountNow = GetTickCount(); for( pdlink = SleepWorker_pdlHead(); SleepWorker_bValid( pdlink ); ){ pSleepWorker = SleepWorker_pConvert( pdlink ); pdlink = SleepWorker_pdlNext( pdlink ); if( pSleepWorker->TickCountWake - TickCountNow < kTickCountMargin ){ // // We should wake up this guy now. // There is a 1 hr margin since these call backs to // take time to execute, and we may miss one of them. // pSleepWorker->vCallback(); // // Remove current item from linked list. // pSleepWorker->SleepWorker_vDelinkSelf(); } else { // // This item still needs to sleep a little longer. // Since they are ordered by sleep time, we can // stop now. // break; } } } } VOID TSleepNotify:: vAdd( VSleepWorker& SleepWorkerAdd, TICKCOUNT TickCountWake ) /*++ Routine Description: Insert a SleepWorker into the list of items sleeping based on when it wants to wake. The shortest sleepers are first on the list. Arguments: SleepWorkerAdd -- Item that wants to sleep a while. TickCountWake -- Tick count that we want to wake at. Return Value: --*/ { TCritSecLock CSL( _CritSec ); // // Traverse until we see someone that wants to sleep more than us. // PDLINK pdlink; VSleepWorker* pSleepWorker; TICKCOUNT TickCountNow = GetTickCount(); TICKCOUNT TickCountSleep = TickCountWake - TickCountNow; for( pdlink = SleepWorker_pdlHead(); SleepWorker_bValid( pdlink ); pdlink = SleepWorker_pdlNext( pdlink ) ){ pSleepWorker = SleepWorker_pConvert( pdlink ); // // If the amount this item wants to sleep is greater than // the amount we want to sleep, then insert item here. // if( pSleepWorker->TickCountWake - TickCountNow > TickCountSleep ){ SleepWorker_vInsertBefore( pdlink, &SleepWorkerAdd ); return; } } // // No items or last item. // Add to end of list. // SleepWorker_vAppend( &SleepWorkerAdd ); }