You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
653 lines
18 KiB
653 lines
18 KiB
/*++
|
|
|
|
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 <wmium.h>
|
|
#include <ntdddisk.h>
|
|
#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_
|