Leaked source code of windows server 2003
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.
 
 
 
 
 
 

700 lines
18 KiB

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
conidle.c
Abstract:
This module builds a console test program to stress idle
detection, and registration/unregistration mechanisms.
The quality of the code for the test programs is as such.
Author:
Cenk Ergan (cenke)
Environment:
User Mode
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <wmium.h>
#include <ntdddisk.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "idlrpc.h"
#include "idlecomn.h"
//
// Note that the following code is test quality code.
//
DWORD
RegisterIdleTask (
IN IT_IDLE_TASK_ID IdleTaskId,
OUT HANDLE *ItHandle,
OUT HANDLE *StartEvent,
OUT HANDLE *StopEvent
);
DWORD
UnregisterIdleTask (
IN HANDLE ItHandle,
IN HANDLE StartEvent,
IN HANDLE StopEvent
);
DWORD
ProcessIdleTasks (
VOID
);
#define NUM_TEST_TASKS 3
typedef enum _WORKTYPE {
CpuWork,
DiskWork,
MaxWorkType
} WORKTYPE, *PWORKTYPE;
typedef struct _TESTTASK {
HANDLE ThreadHandle;
ULONG No;
IT_IDLE_TASK_ID Id;
IT_HANDLE ItHandle;
HANDLE StartEvent;
HANDLE StopEvent;
} TESTTASK, *PTESTTASK;
typedef struct _TESTWORK {
ULONG No;
WORKTYPE Type;
DWORD WorkLength;
HANDLE StopEvent;
} TESTWORK, *PTESTWORK;
TESTTASK g_Tasks[NUM_TEST_TASKS];
BOOLEAN g_ProcessingIdleTasks = FALSE;
HANDLE g_ProcessedIdleTasksEvent = NULL;
#define MAX_WAIT_FOR_START 20000
#define MAX_WORK_LENGTH 5000
#define MAX_READ_SIZE (64 * 1024)
DWORD
WINAPI
DoWorkThreadProc(
LPVOID lpParameter
)
{
PTESTWORK Work;
DWORD EndTime;
DWORD WaitResult;
DWORD ErrorCode;
DWORD RunTillTime;
HANDLE DiskHandle;
PVOID ReadBuffer;
BOOL ReadResult;
ULONG NumBytesRead;
LARGE_INTEGER VolumeSize;
LARGE_INTEGER SeekPosition;
ULONG ReadIdx;
DISK_GEOMETRY DiskGeometry;
ULONG BytesReturned;
static LONG DiskNumber;
//
// Initialize locals.
//
Work = lpParameter;
EndTime = GetTickCount() + Work->WorkLength;
DiskHandle = NULL;
ReadBuffer = NULL;
//
// Do initialization for performing specified work.
//
switch (Work->Type) {
case DiskWork:
//
// Open disk. Maybe we could open different physical drives
// each time.
//
DiskHandle = CreateFile(L"\\\\.\\PHYSICALDRIVE0",
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING,
0);
if (!DiskHandle) {
ErrorCode = GetLastError();
printf("W%d: Failed open PHYSICALDRIVE0.\n", Work->No);
goto cleanup;
}
//
// Get volume size.
//
if (!DeviceIoControl(DiskHandle,
IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL,
0,
&DiskGeometry,
sizeof(DiskGeometry),
&BytesReturned,
NULL)) {
ErrorCode = GetLastError();
printf("W%d: Failed GET_DRIVE_GEOMETRY.\n", Work->No);
goto cleanup;
}
VolumeSize.QuadPart = DiskGeometry.Cylinders.QuadPart *
DiskGeometry.TracksPerCylinder *
DiskGeometry.SectorsPerTrack *
DiskGeometry.BytesPerSector;
//
// Allocate buffer.
//
ReadBuffer = VirtualAlloc(NULL,
MAX_READ_SIZE,
MEM_COMMIT,
PAGE_READWRITE);
if (!ReadBuffer) {
ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
printf("W%d: Failed VirtualAlloc.\n", Work->No);
goto cleanup;
}
break;
default:
//
// Nothing to prepare.
//
break;
}
while (GetTickCount() < EndTime) {
//
// Check if we are asked to stop.
//
WaitResult = WaitForSingleObject(Work->StopEvent, 0);
if (WaitResult == WAIT_OBJECT_0) {
ErrorCode = ERROR_SUCCESS;
goto cleanup;
}
//
// Do a unit of work that should not take more than several
// tens of milliseconds.
//
switch (Work->Type) {
case CpuWork:
RunTillTime = GetTickCount() + 10;
while (GetTickCount() < RunTillTime) ;
break;
case DiskWork:
//
// Seek to random position.
//
SeekPosition.QuadPart = rand() * 4 * 1024;
SeekPosition.QuadPart %= VolumeSize.QuadPart;
if (!SetFilePointerEx(DiskHandle,
SeekPosition,
NULL,
FILE_BEGIN)) {
printf("W%d: Failed SetFilePointerEx.\n", Work->No);
ErrorCode = GetLastError();
goto cleanup;
}
//
// Issue read.
//
ReadResult = ReadFile(DiskHandle,
ReadBuffer,
MAX_READ_SIZE,
&NumBytesRead,
NULL);
if (!ReadResult) {
printf("W%d: Failed ReadFile.\n", Work->No);
ErrorCode = GetLastError();
goto cleanup;
}
break;
default:
printf("W%d: Not valid work type %d!\n", Work->No, Work->Type);
ErrorCode = ERROR_INVALID_PARAMETER;
goto cleanup;
}
}
ErrorCode = ERROR_SUCCESS;
cleanup:
if (DiskHandle) {
CloseHandle(DiskHandle);
}
if (ReadBuffer) {
VirtualFree(ReadBuffer, 0, MEM_RELEASE);
}
printf("W%d: Exiting with error code: %d\n", Work->No, ErrorCode);
return ErrorCode;
}
DWORD
WINAPI
TaskThreadProc(
LPVOID lpParameter
)
{
PTESTTASK Task = lpParameter;
TESTWORK Work;
DWORD ErrorCode;
WORKTYPE Type;
DWORD WaitResult;
DWORD WaitForStart;
HANDLE WorkerThreadHandle;
DWORD WorkLength;
HANDLE Events[2];
DWORD ElapsedTime;
DWORD StartTime;
ULONG TryIdx;
BOOLEAN RegisteredIdleTask;
//
// Initialize locals.
//
RegisteredIdleTask = FALSE;
WorkerThreadHandle = NULL;
RtlZeroMemory(&Work, sizeof(Work));
//
// Initialize work structure.
//
Work.StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!Work.StopEvent) {
goto cleanup;
}
Work.No = Task->No;
//
// Loop registering, running, unregistering idle tasks.
//
while (TRUE) {
//
// If we are force-processing all tasks, usually wait for all tasks
// to complete before queueing a new task.
//
if (g_ProcessingIdleTasks) {
if ((rand() % 3) != 0) {
printf("%d: Waiting for g_ProcessedIdleTasksEvent\n", Task->No);
WaitResult = WaitForSingleObject(g_ProcessedIdleTasksEvent, INFINITE);
if (WaitResult != WAIT_OBJECT_0) {
ErrorCode = GetLastError();
printf("%d: Failed wait for g_ProcessedIdleTasksEvent=%x\n", Task->No, ErrorCode);
goto cleanup;
}
}
}
//
// Register the idle task.
//
ErrorCode = RegisterIdleTask(Task->Id,
&Task->ItHandle,
&Task->StartEvent,
&Task->StopEvent);
if (ErrorCode != ERROR_SUCCESS) {
printf("%d: Could not register: %d\n", Task->No, ErrorCode);
goto cleanup;
}
RegisteredIdleTask = TRUE;
//
// Determine task parameters.
//
Type = rand() % MaxWorkType;
WaitForStart = rand() % MAX_WAIT_FOR_START;
WorkLength = rand() % MAX_WORK_LENGTH;
//
// Update work item.
//
Work.Type = Type;
Work.WorkLength = WorkLength;
printf("%d: NewTask Type=%d,WStart=%d,Length=%d,Handle=%p\n",
Task->No, Type, WaitForStart, WorkLength, Task->ItHandle);
do {
//
// Wait to be signaled.
//
printf("%d: Waiting for start\n", Task->No);
WaitResult = WaitForSingleObject(Task->StartEvent, WaitForStart);
if (WaitResult == WAIT_TIMEOUT) {
printf("%d: Timed out wait for start. Re-registering\n", Task->No);
break;
}
//
// Spawn the work.
//
ResetEvent(Work.StopEvent);
StartTime = GetTickCount();
WorkerThreadHandle = CreateThread(NULL,
0,
DoWorkThreadProc,
&Work,
0,
NULL);
if (!WorkerThreadHandle) {
ErrorCode = GetLastError();
printf("%d: Failed spawn work: %d\n", Task->No, ErrorCode);
goto cleanup;
}
//
// Wait for stop event to be signaled or the work to be
// completed.
//
Events[0] = WorkerThreadHandle;
Events[1] = Task->StopEvent;
printf("%d: Waiting for stop or workdone\n", Task->No);
WaitResult = WaitForMultipleObjects(2,
Events,
FALSE,
INFINITE);
if (WaitResult == WAIT_OBJECT_0) {
//
// Break out if the work was done.
//
printf("%d: Work done.\n", Task->No);
CloseHandle(WorkerThreadHandle);
WorkerThreadHandle = NULL;
break;
} else if (WaitResult == WAIT_OBJECT_0 + 1) {
//
// We were told to stop. Signal the worker thread and
// wait.
//
printf("%d: Stopped, Waiting for thread to exit\n", Task->No);
SetEvent(Work.StopEvent);
WaitForSingleObject(WorkerThreadHandle, INFINITE);
CloseHandle(WorkerThreadHandle);
WorkerThreadHandle = NULL;
//
// This is not really the time we worked (e.g. we may be
// switched out etc.) We want to keep rolling and this is
// what we can get easily.
//
ElapsedTime = GetTickCount() - StartTime;
if (ElapsedTime > Work.WorkLength) {
//
// We've gone too long with this work. Unregistester
// this task and pick another one.
//
break;
}
Work.WorkLength -= ElapsedTime;
//
// Loop on until we pass enough time with this work.
//
} else {
//
// There was an error.
//
ErrorCode = GetLastError();
printf("%d: WaitForMultipleObjects failed: %d\n", Task->No, ErrorCode);
goto cleanup;
}
} while (TRUE);
ASSERT(RegisteredIdleTask);
UnregisterIdleTask(Task->ItHandle,
Task->StartEvent,
Task->StopEvent);
RegisteredIdleTask = FALSE;
}
cleanup:
if (RegisteredIdleTask) {
UnregisterIdleTask(Task->ItHandle,
Task->StartEvent,
Task->StopEvent);
}
if (WorkerThreadHandle) {
SetEvent(Work.StopEvent);
WaitForSingleObject(WorkerThreadHandle, INFINITE);
CloseHandle(WorkerThreadHandle);
}
if (Work.StopEvent) {
CloseHandle(Work.StopEvent);
}
return ErrorCode;
}
int
__cdecl
main(int argc, char* argv[])
{
DWORD ErrorCode;
ULONG TaskIdx;
IT_IDLE_DETECTION_PARAMETERS Parameters;
PTESTTASK Task;
INPUT MouseInput;
ULONG SleepTime;
//
// Initialize locals.
//
RtlZeroMemory(&MouseInput, sizeof(MouseInput));
MouseInput.type = INPUT_MOUSE;
MouseInput.mi.dwFlags = MOUSEEVENTF_MOVE;
//
// Initialize globals.
//
g_ProcessingIdleTasks = FALSE;
g_ProcessedIdleTasksEvent = NULL;
//
// Initialize random.
//
srand((unsigned)time(NULL));
//
// Create an manual reset event that will be signaled when we finish
// processing all tasks after telling the server to process all tasks.
//
g_ProcessedIdleTasksEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!g_ProcessedIdleTasksEvent) {
ErrorCode = GetLastError();
printf("Failed to create g_ProcessedIdleTasksEvent=%x\n",ErrorCode);
goto cleanup;
}
//
// Set idle detection parameters for stress.
//
Parameters.IdleDetectionPeriod = 1000;
Parameters.IdleVerificationPeriod = 500;
Parameters.NumVerifications = 2;
Parameters.IdleInputCheckPeriod = 100;
Parameters.IdleTaskRunningCheckPeriod = 1000;
Parameters.MinCpuIdlePercentage = 50;
Parameters.MinDiskIdlePercentage = 50;
Parameters.MaxNumRegisteredTasks = 500;
RpcTryExcept {
ErrorCode = ItSrvSetDetectionParameters(NULL, &Parameters);
}
RpcExcept(IT_RPC_EXCEPTION_HANDLER()) {
ErrorCode = RpcExceptionCode();
}
RpcEndExcept
if (ErrorCode != ERROR_SUCCESS) {
printf("Failed set idle detection params for stress.\n");
goto cleanup;
}
//
// Register and start tasks.
//
for (TaskIdx = 0; TaskIdx < NUM_TEST_TASKS; TaskIdx++) {
Task = &g_Tasks[TaskIdx];
Task->No = TaskIdx;
Task->Id = ItOptimalDiskLayoutTaskId;
Task->ThreadHandle = CreateThread(NULL,
0,
TaskThreadProc,
&g_Tasks[TaskIdx],
0,
0);
if (!Task->ThreadHandle) {
ErrorCode = GetLastError();
printf("Could not spawn task %d: %x\n", TaskIdx, ErrorCode);
goto cleanup;
}
}
//
// Loop forever sending input messages once in a while to stop
// idle tasks.
//
while (1) {
SleepTime = MAX_WAIT_FOR_START * (rand() % 64) / 64;
Sleep(SleepTime);
//
// Every so often, ask all idle tasks to be processed.
//
if ((rand() % 2) == 0) {
if ((rand() % 2) == 0) {
printf("MainThread: Sending user input before processing all tasks\n");
SendInput(1, &MouseInput, sizeof(MouseInput));
}
printf("MainThread: ProcessIdleTasks()\n");
ResetEvent(g_ProcessedIdleTasksEvent);
g_ProcessingIdleTasks = TRUE;
ErrorCode = ProcessIdleTasks();
printf("MainThread: ProcessIdleTasks()=%x\n",ErrorCode);
g_ProcessingIdleTasks = FALSE;
SetEvent(g_ProcessedIdleTasksEvent);
if (ErrorCode != ERROR_SUCCESS) {
goto cleanup;
}
}
if ((rand() % 2) == 0) {
printf("MainThread: Sending user input\n");
SendInput(1, &MouseInput, sizeof(MouseInput));
}
}
cleanup:
if (g_ProcessedIdleTasksEvent) {
CloseHandle(g_ProcessedIdleTasksEvent);
}
return ErrorCode;
}
/*********************************************************************/
/* MIDL allocate and free */
/*********************************************************************/
void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
{
return(HeapAlloc(GetProcessHeap(),0,(len)));
}
void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
{
HeapFree(GetProcessHeap(),0,(ptr));
}