windows-nt/Source/XPSP1/NT/admin/services/sched/idletask/server/idletsks.h
2020-09-26 16:20:57 +08:00

729 lines
17 KiB
C

/*++
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.
//
// 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.
//
#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_REALLOC(Buffer,NumBytes) (HeapReAlloc(GetProcessHeap(),0,(Buffer),(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,
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.
//
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;
//
// This manual-reset event is reset while ItSrvServiceHandler is
// running. It is signaled when the function is done. It is used
// to synchronize shutdown with ItSrvServiceHandler call ins.
//
HANDLE ServiceHandlerNotRunning;
//
// 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.
//
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;
//
// Reference count structure.
//
typedef struct _ITSRV_REFCOUNT {
//
// This is set when somebody wants to gain exclusive access to the
// protected structure.
//
LONG Exclusive;
//
// When initialized or reset, this reference count starts from
// 1. When exclusive access is granted it stays at 0: even if it
// may get bumped by an AddRef by mistake, it will return to 0.
//
LONG RefCount;
//
// The thread that got exclusive access.
//
HANDLE ExclusiveOwner;
} ITSRV_REFCOUNT, *PITSRV_REFCOUNT;
//
// Server function declarations. They should be only used by the
// server host and the client functions.
//
DWORD
ItSrvInitialize (
VOID
);
VOID
ItSrvUninitialize (
VOID
);
BOOLEAN
ItSrvServiceHandler(
IN DWORD ControlCode,
IN DWORD EventType,
IN LPVOID EventData,
IN LPVOID Context,
OUT PDWORD ErrorCode
);
DWORD
ItSrvRegisterIdleTask (
ITRPC_HANDLE Reserved,
IT_HANDLE *ItHandle,
PIT_IDLE_TASK_PROPERTIES IdleTaskProperties
);
VOID
ItSrvUnregisterIdleTask (
ITRPC_HANDLE Reserved,
IT_HANDLE *ItHandle
);
DWORD
ItSrvSetDetectionParameters (
ITRPC_HANDLE Reserved,
PIT_IDLE_DETECTION_PARAMETERS Parameters
);
DWORD
ItSrvProcessIdleTasks (
ITRPC_HANDLE Reserved
);
VOID
__RPC_USER
IT_HANDLE_rundown (
IT_HANDLE ItHandle
);
//
// Local support function prototypes for the server.
//
RPC_STATUS
__stdcall
ItSpRpcSecurityCallback (
IN PVOID 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
);
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
);
//
// Reference count functions.
//
VOID
ItSpInitializeRefCount(
PITSRV_REFCOUNT RefCount
);
DWORD
FASTCALL
ItSpAddRef(
PITSRV_REFCOUNT RefCount
);
VOID
FASTCALL
ItSpDecRef(
PITSRV_REFCOUNT RefCount
);
DWORD
ItSpAcquireExclusiveRef(
PITSRV_REFCOUNT RefCount
);
#endif // _IDLETSKS_H_