/*++ Copyright (c) 2000 Microsoft Corporation Module Name: idletsks.h Abstract: This module contains private declarations for the idle task & detection server. Author: Dave Fields (davidfie) 26-July-1998 Cenk Ergan (cenke) 14-June-2000 Revision History: --*/ #ifndef _IDLETSKS_H_ #define _IDLETSKS_H_ // // Include public and common definitions. // #include #include #include "idlrpc.h" #include "idlecomn.h" // // Define the default period in ms for checking if the system is idle. // #define IT_DEFAULT_IDLE_DETECTION_PERIOD (12 * 60 * 1000) // 12 minutes. // // If the system has been idle over the idle detection period, we // verify that it is really idle by checking frequently over a shorter // period for a number of times. This helps us know when there were // 100 disk I/O's in the last second of idle detection period, but // over 15 minutes it does not look a lot. // #define IT_DEFAULT_IDLE_VERIFICATION_PERIOD (30 * 1000) // 30 seconds. #define IT_DEFAULT_NUM_IDLE_VERIFICATIONS 5 // 5 times. // // We will be polling for user input when running idle tasks every // this many ms. We want to catch user input and notify the idle task // to stop running as soon as possible. Even though the system is // idle, we don't want to create too much overhead which may mislead // ourself. // #define IT_DEFAULT_IDLE_USER_INPUT_CHECK_PERIOD 250 // 4 times a sec. // FUTURE-2002/03/26-ScottMa -- The constant (below) is not used, except // to initialize the [unused] IdleTaskRunningCheckPeriod parameter. // // We check to see if the idle task we asked to run is really running // (i.e. it is using the disk and CPU) every this many ms. This is our // mechanism for cleaning up after unregistered/orphaned tasks. This // should be greater than IT_USER_INPUT_POLL_PERIOD_WHEN_IDLE. // #define IT_DEFAULT_IDLE_TASK_RUNNING_CHECK_PERIOD (5 * 60 * 1000) // 5 min. // // If the CPU is not idle more than this percent over a time interval, // the system is not considered idle. // #define IT_DEFAULT_MIN_CPU_IDLE_PERCENTAGE 90 // // If a disk is not idle more than this percent over a time interval, // the system is not considered idle. // #define IT_DEFAULT_MIN_DISK_IDLE_PERCENTAGE 90 // // We will not try to run our tasks if there is only this many seconds // left before the system will enter hibernate or standby automatically. // Note that the time remaining is updated every so many seconds (e.g. // 15) so this number should not be very small. // // FUTURE-2002/03/26-ScottMa -- This constant doesn't have a corresponding // parameter in the IT_IDLE_DETECTION_PARAMETERS structure. Should it // be added to the structure like the others? #define IT_DEFAULT_MAX_TIME_REMAINING_TO_SLEEP 60 // // This is the maximum number of registered idle tasks. This is a // sanity check. It also protects against evil callers. // #define IT_DEFAULT_MAX_REGISTERED_TASKS 512 // // We set timer period for idle detection callback to this while the // callback is running to prevent new callbacks from firing. We end up // having to do this because you cannot requeue/change a timer for // which you don't specify a period. If a callback fires while another // one is already running, it simply returns without doing anything. // #define IT_VERYLONG_TIMER_PERIOD 0x7FFFFFFF // // This is the number of recent server statuses that we keep track // of. Do not make this number smaller without revisiting the logic & // code that uses the LastStatus history. // #define ITSRV_GLOBAL_STATUS_HISTORY_SIZE 8 // // Hints for the number of outstanding RPC call-ins we will have. // #define ITSRV_RPC_MIN_CALLS 1 #define ITSRV_RPC_MAX_CALLS 1 // // Define useful macros. // #define IT_ALLOC(NumBytes) (HeapAlloc(GetProcessHeap(),0,(NumBytes))) #define IT_FREE(Buffer) (HeapFree(GetProcessHeap(),0,(Buffer))) // // These macros are used to acquire/release a mutex. // #define IT_ACQUIRE_LOCK(Lock) \ WaitForSingleObject((Lock), INFINITE); \ #define IT_RELEASE_LOCK(Lock) \ ReleaseMutex((Lock)); \ // // This macro is used in the idle detection callback (while holding // the global lock of the input global context) to determine if the // idle detection callback should just exit/go away. // #define ITSP_SHOULD_STOP_IDLE_DETECTION(GlobalContext) \ ((GlobalContext->Status == ItSrvStatusStoppingIdleDetection) || \ (GlobalContext->Status == ItSrvStatusUninitializing)) \ // // Status of a server global context. It also acts as a magic to // identify/verify the global context, as it starts from Df00. There // is not a full-blown state machine, although the state is used as a // critical hint for making decisions when registering an idle // task. This is more for informative and verification purposes. If // you add a new status without updating everything that needs to be // updated, you may hit several asserts, especially in the idle // detection callback. Frankly, don't add a new state without a very // good reason. // typedef enum _ITSRV_GLOBAL_CONTEXT_STATUS { ItSrvStatusMinStatus = 'Df00', ItSrvStatusInitializing, ItSrvStatusWaitingForIdleTasks, ItSrvStatusDetectingIdle, ItSrvStatusRunningIdleTasks, ItSrvStatusStoppingIdleDetection, ItSrvStatusUninitializing, ItSrvStatusUninitialized, ItSrvStatusMaxStatus } ITSRV_GLOBAL_CONTEXT_STATUS, *PITSRV_GLOBAL_CONTEXT_STATUS; // // These are the various types of idle detection overrides. Multiple // overrides can be specified by OR'ing them (i.e. these are bits!) // // If you are adding an override here, check whether you need to specify // it when force-processing all idle tasks. // typedef enum _ITSRV_IDLE_DETECTION_OVERRIDE { ItSrvOverrideIdleDetection = 0x00000001, ItSrvOverrideIdleVerification = 0x00000002, ItSrvOverrideUserInputCheckToStopTask = 0x00000004, // FUTURE-2002/03/26-ScottMa -- The ItSrvOverrideTaskRunningCheck value // is never used, presumably because some code was removed. ItSrvOverrideTaskRunningCheck = 0x00000008, ItSrvOverridePostTaskIdleCheck = 0x00000010, ItSrvOverrideLongRequeueTime = 0x00000020, ItSrvOverrideBatteryCheckToStopTask = 0x00000040, ItSrvOverrideAutoPowerCheckToStopTask = 0x00000080, } ITSRV_IDLE_DETECTION_OVERRIDE, *PITSRV_IDLE_DETECTION_OVERRIDE; // // These are the various reasons why ItSpIsSystemIdle function may be // called. // // FUTURE-2002/03/26-ScottMa -- The ItSrvIdleTaskRunningCheck is never passed // to the ItSpIsSystemIdle function, presumably because the call was removed. // to initialize the [unused] IdleTaskRunningCheckPeriod parameter. Further, // there is no difference between the other two reasons -- is it needed? typedef enum _ITSRV_IDLE_CHECK_REASON { ItSrvInitialIdleCheck, ItSrvIdleVerificationCheck, ItSrvIdleTaskRunningCheck, ItSrvMaxIdleCheckReason }ITSRV_IDLE_CHECK_REASON, *PITSRV_IDLE_CHECK_REASON; // // This structure is used to keep context for a registered task for // the server. // typedef struct _ITSRV_IDLE_TASK_CONTEXT { // // Link in the list of idle tasks. // LIST_ENTRY IdleTaskLink; // // Status of the idle task. // IT_IDLE_TASK_STATUS Status; // // Idle task properties the client specified. // IT_IDLE_TASK_PROPERTIES Properties; // // Event to be notified when the task should start running // (e.g. the system is idle). // HANDLE StartEvent; // // Event to be notified when the task should stop running. // HANDLE StopEvent; } ITSRV_IDLE_TASK_CONTEXT, *PITSRV_IDLE_TASK_CONTEXT; // // This structure contains disk performance information we are // interested in. // typedef struct _ITSRV_DISK_PERFORMANCE_DATA { // // How long the disk was idle in ms. // ULONG DiskIdleTime; } ITSRV_DISK_PERFORMANCE_DATA, *PITSRV_DISK_PERFORMANCE_DATA; // // Define structure to contain system resource information & state at // a specific time. // typedef struct _ITSRV_SYSTEM_SNAPSHOT { // // When this snapshot was taken, in ms elapsed since system was // started (i.e. GetTickCount) // DWORD SnapshotTime; // // Whether we were able to get the specified data in this snapshot. // ULONG GotLastInputInfo:1; ULONG GotSystemPerformanceInfo:1; ULONG GotDiskPerformanceInfo:1; ULONG GotSystemPowerStatus:1; ULONG GotSystemPowerInfo:1; ULONG GotSystemExecutionState:1; ULONG GotDisplayPowerStatus:1; // // This is when the last user input happened before the snapshot // was taken. // LASTINPUTINFO LastInputInfo; // // System performance information when the snapshot was taken. // SYSTEM_PERFORMANCE_INFORMATION SystemPerformanceInfo; // // Disk performance data on registered harddisks when the snapshot // was taken. // ULONG NumPhysicalDisks; ITSRV_DISK_PERFORMANCE_DATA *DiskPerfData; // // System power status (e.g. are we running on battery etc.) // SYSTEM_POWER_STATUS SystemPowerStatus; // // System power information (e.g. how long till system turns itself // off & goes to sleep.) // SYSTEM_POWER_INFORMATION PowerInfo; // // System execution state (e.g. is somebody running a presentation?) // EXECUTION_STATE ExecutionState; // // Whether the screen saver is running. // BOOL ScreenSaverIsRunning; } ITSRV_SYSTEM_SNAPSHOT, *PITSRV_SYSTEM_SNAPSHOT; // // Type for the routine that is called to notify that forced processing of // idle tasks have been requested. // typedef VOID (*PIT_PROCESS_IDLE_TASKS_NOTIFY_ROUTINE)(VOID); // // Define structure to contain server global context for idle // detection and keeping track of registered idle tasks. // typedef struct _ITSRV_GLOBAL_CONTEXT { // // Status of the server and its history, LastStatus[0] being the // most recent. The status version is incremented each time the // status is updated. // ITSRV_GLOBAL_CONTEXT_STATUS Status; ITSRV_GLOBAL_CONTEXT_STATUS LastStatus[ITSRV_GLOBAL_STATUS_HISTORY_SIZE]; LONG StatusVersion; // // Nearly all operations involve the idle tasks list and instead // of having a lock for the list and seperate synchronization // mechanisms for other operations on the structure, we have a // single global lock to make life simpler. // HANDLE GlobalLock; // // This is the list and number of idle tasks that have been // scheduled. // LIST_ENTRY IdleTasksList; ULONG NumIdleTasks; // // Handle to the timer queue timer that is used to periodically // check for system idleness. // HANDLE IdleDetectionTimerHandle; // // This manual reset event gets signaled when idle detection // should stop (e.g. because there are no more idle tasks, the // server is shutting down etc.) It signals a running idle // detection callback to quickly exit. // HANDLE StopIdleDetection; // // This manual reset event gets signaled when idle detection has // fully stopped (i.e. no callback is running, the timer is not in // the queue etc. // HANDLE IdleDetectionStopped; // // This manual reset event is signaled when an idle task that was // running is unregistered/removed. This would happen usually // after an idle task that was told to run completes and has no // more to do. It unregisters itself, and this event is set to // notify the idle detection callback to move on to other idle // tasks. // HANDLE RemovedRunningIdleTask; // FUTURE-2002/03/26-ScottMa -- The field (below) is never used as an // L-value, except in the [unused] ItSpSetProcessIdleTasksNotifyRoutine // function. // // If it is set, this routine is called to notify that // forced processing of idle tasks have been requested. // PIT_PROCESS_IDLE_TASKS_NOTIFY_ROUTINE ProcessIdleTasksNotifyRoutine; // // These are the parameters that control idle detection. // IT_IDLE_DETECTION_PARAMETERS Parameters; // // This is the WMI handle used in disk performance queries. // WMIHANDLE DiskPerfWmiHandle; // // Number of processors on the system. Used to calculate CPU // utilization. // UCHAR NumProcessors; // // This buffer is used to make Wmi queries. It is maintained here // so we don't have to allocate a new one each time. // PVOID WmiQueryBuffer; ULONG WmiQueryBufferSize; // // The last system resource / activity snapshot we took. // // FUTURE-2002/03/26-ScottMa -- Adding the CurrentSystemSnapshot to the // global context would remove the need to repeatedly initialize and // cleanup the stack variable in the ItSpIdleDetectionCallbackRoutine. // Since the calls to that function are already protected against // re-entrancy issues, adding it to the global context is safe. ITSRV_SYSTEM_SNAPSHOT LastSystemSnapshot; // // Is an idle detection callback already running? This is used to // protect us from idle detection callbacks being fired while // there is already one active. // BOOLEAN IsIdleDetectionCallbackRunning; // // Various phases of idle detection can be overriden by setting // this. // ITSRV_IDLE_DETECTION_OVERRIDE IdleDetectionOverride; // // RPC binding vector used to register ourselves in the local // endpoint-map database. // RPC_BINDING_VECTOR *RpcBindingVector; // // Whether we actually registered our endpoint and interface. // BOOLEAN RegisteredRPCEndpoint; BOOLEAN RegisteredRPCInterface; } ITSRV_GLOBAL_CONTEXT, *PITSRV_GLOBAL_CONTEXT; // // Server function declarations. They should be only used by the // server host and the client functions. // DWORD ItSrvInitialize ( VOID ); VOID ItSrvUninitialize ( VOID ); // // Local support function prototypes for the server. // RPC_STATUS RPC_ENTRY ItSpRpcSecurityCallback ( IN RPC_IF_HANDLE *Interface, IN PVOID Context ); VOID ItSpUnregisterIdleTask ( ITRPC_HANDLE Reserved, IT_HANDLE *ItHandle, BOOLEAN CalledInternally ); VOID ItSpUpdateStatus ( PITSRV_GLOBAL_CONTEXT GlobalContext, ITSRV_GLOBAL_CONTEXT_STATUS NewStatus ); VOID ItSpCleanupGlobalContext ( PITSRV_GLOBAL_CONTEXT GlobalContext ); VOID ItSpCleanupIdleTask ( PITSRV_IDLE_TASK_CONTEXT IdleTask ); ULONG ItpVerifyIdleTaskProperties ( PIT_IDLE_TASK_PROPERTIES IdleTaskProperties ); DWORD ItSpStartIdleDetection ( PITSRV_GLOBAL_CONTEXT GlobalContext ); VOID ItSpStopIdleDetection ( PITSRV_GLOBAL_CONTEXT GlobalContext ); VOID CALLBACK ItSpIdleDetectionCallbackRoutine ( PVOID Parameter, BOOLEAN TimerOrWaitFired ); PITSRV_IDLE_TASK_CONTEXT ItSpFindRunningIdleTask ( PITSRV_GLOBAL_CONTEXT GlobalContext ); PITSRV_IDLE_TASK_CONTEXT ItSpFindIdleTask ( PITSRV_GLOBAL_CONTEXT GlobalContext, IT_HANDLE ItHandle ); VOID ItSpInitializeSystemSnapshot ( PITSRV_SYSTEM_SNAPSHOT SystemSnapshot ); VOID ItSpCleanupSystemSnapshot ( PITSRV_SYSTEM_SNAPSHOT SystemSnapshot ); DWORD ItSpCopySystemSnapshot ( PITSRV_SYSTEM_SNAPSHOT DestSnapshot, PITSRV_SYSTEM_SNAPSHOT SourceSnapshot ); DWORD ItSpGetSystemSnapshot ( PITSRV_GLOBAL_CONTEXT GlobalContext, PITSRV_SYSTEM_SNAPSHOT SystemSnapshot ); // FUTURE-2002/03/26-ScottMa -- If the CurrentSystemSnapshot is added to the // global context, both parameters no longer need to be passed to this // function. It is only called from within ItSpIdleDetectionCallbackRoutine, // and always uses the same values for current & last snapshot. BOOLEAN ItSpIsSystemIdle ( PITSRV_GLOBAL_CONTEXT GlobalContext, PITSRV_SYSTEM_SNAPSHOT CurrentSnapshot, PITSRV_SYSTEM_SNAPSHOT LastSnapshot, ITSRV_IDLE_CHECK_REASON IdleCheckReason ); DWORD ItSpGetLastInputInfo ( PLASTINPUTINFO LastInputInfo ); DWORD ItSpGetWmiDiskPerformanceData( IN WMIHANDLE DiskPerfWmiHandle, OUT PITSRV_DISK_PERFORMANCE_DATA *DiskPerfData, OUT ULONG *NumPhysicalDisks, OPTIONAL IN OUT PVOID *InputQueryBuffer, OPTIONAL IN OUT ULONG *InputQueryBufferSize ); BOOLEAN ItSpIsPhysicalDrive ( PDISK_PERFORMANCE DiskPerformanceData ); DWORD ItSpGetDisplayPowerStatus( PBOOL ScreenSaverIsRunning ); #endif // _IDLETSKS_H_