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.
 
 
 
 
 
 

638 lines
11 KiB

//
// Test/simulation program for the extended device queue
//
#include "raidport.h"
#include "exqueue.h"
#define SECONDS (1000)
typedef struct _TQ_ITEM {
ULONG Thread;
ULONG64 Data;
ULONG64 Sequence;
KDEVICE_QUEUE_ENTRY DeviceEntry;
LIST_ENTRY DpcEntry;
} TQ_ITEM, *PTQ_ITEM;
typedef struct _DPC_QUEUE {
HANDLE Available;
HANDLE Mutex;
LIST_ENTRY Queue;
ULONG Count;
} DPC_QUEUE, *PDPC_QUEUE;
BOOL Verbose = FALSE;
BOOL Cerbose = TRUE;
DPC_QUEUE DpcQueue;
EXTENDED_DEVICE_QUEUE DeviceQueue;
BOOLEAN Pause = FALSE;
BOOLEAN PauseProducer = FALSE;
ULONG64 GlobalSequence = 0;
DWORD Owner = 0;
BOOL Available = FALSE;
VOID
GetNext(
OUT PULONG64 Sequence,
OUT PULONG Data
)
{
*Sequence = ++GlobalSequence;
*Data = (ULONG)rand();
}
#pragma warning (disable:4715)
BOOL
WINAPI
UpdateThread(
PVOID Unused
)
{
for (;;) {
while (Pause) {
Sleep (500);
}
printf ("Seq: %I64d, dev %d bypass %d dpc %d \r",
GlobalSequence,
DeviceQueue.DeviceRequests,
DeviceQueue.ByPassRequests,
DpcQueue.Count);
Sleep (2000);
}
return FALSE;
}
VOID
CreateDpcQueue(
PDPC_QUEUE DpcQueue
)
{
DpcQueue->Available = CreateEvent (NULL, FALSE, FALSE, NULL);
DpcQueue->Mutex = CreateMutex (NULL, FALSE, NULL);
InitializeListHead (&DpcQueue->Queue);
DpcQueue->Count = 0;
}
VOID
InsertDpcItem(
IN PDPC_QUEUE DpcQueue,
IN PLIST_ENTRY Entry
)
{
WaitForSingleObject (DpcQueue->Mutex, INFINITE);
InsertTailList (&DpcQueue->Queue, Entry);
DpcQueue->Count++;
Owner = GetCurrentThreadId ();
Available = TRUE;
SetEvent (DpcQueue->Available);
ReleaseMutex (DpcQueue->Mutex);
}
PLIST_ENTRY
RemoveDpcItem(
IN PDPC_QUEUE DpcQueue
)
{
PLIST_ENTRY Entry;
HANDLE Tuple[2];
Tuple[0] = DpcQueue->Mutex;
Tuple[1] = DpcQueue->Available;
WaitForMultipleObjects (2, Tuple, TRUE, INFINITE);
Available = FALSE;
Owner = GetCurrentThreadId ();
ASSERT (!IsListEmpty (&DpcQueue->Queue));
Entry = RemoveHeadList (&DpcQueue->Queue);
DpcQueue->Count--;
if (!IsListEmpty (&DpcQueue->Queue)) {
Available = TRUE;
SetEvent (DpcQueue->Available);
}
ReleaseMutex (DpcQueue->Mutex);
return Entry;
}
BOOL
WINAPI
ProducerThread(
PVOID Unused
)
{
BOOLEAN Inserted;
PTQ_ITEM Item;
ULONG Data;
ULONG64 Sequence;
srand (GetCurrentThreadId());
for (;;) {
Sleep (10);
while (Pause) {
Sleep (100);
}
while (PauseProducer) {
Sleep (100);
}
Item = malloc (sizeof (TQ_ITEM));
ZeroMemory (Item, sizeof (*Item));
GetNext (&Sequence, &Data);
Item->Thread = GetCurrentThreadId ();
Item->Sequence = Sequence;
Item->Data = Data;
Inserted = RaidInsertExDeviceQueue (&DeviceQueue,
&Item->DeviceEntry,
FALSE,
(ULONG)Item->Data);
if (!Inserted) {
if (Verbose) {
printf ("started %x.%I64d\n", Item->Thread, Item->Data);
}
InsertDpcItem (&DpcQueue, &Item->DpcEntry);
} else {
if (Verbose) {
printf ("queued %x.%I64d\n", Item->Thread, Item->Data);
}
}
}
return FALSE;
}
BOOL
WINAPI
ProducerThread100(
PVOID Unused
)
{
BOOLEAN Inserted;
PTQ_ITEM Item;
ULONG Data;
ULONG64 Sequence;
srand (GetCurrentThreadId());
for (;;) {
Sleep (0);
while (Pause) {
Sleep (100);
}
while (PauseProducer) {
Sleep (100);
}
Item = malloc (sizeof (TQ_ITEM));
ZeroMemory (Item, sizeof (*Item));
GetNext (&Sequence, &Data);
Item->Thread = GetCurrentThreadId ();
Item->Sequence = Sequence;
Item->Data = 100;
Inserted = RaidInsertExDeviceQueue (&DeviceQueue,
&Item->DeviceEntry,
FALSE,
(ULONG)Item->Data);
if (!Inserted) {
if (Verbose) {
printf ("started %x.%I64d\n", Item->Thread, Item->Data);
}
InsertDpcItem (&DpcQueue, &Item->DpcEntry);
} else {
if (Verbose) {
printf ("queued %x.%I64d\n", Item->Thread, Item->Data);
}
}
}
return FALSE;
}
BOOL
WINAPI
ErrorProducerThread(
PVOID Unused
)
{
BOOLEAN Inserted;
PTQ_ITEM Item;
ULONG64 Sequence;
ULONG Data;
for (;;) {
Sleep (500);
while (Pause) {
Sleep (10);
}
Item = malloc (sizeof (TQ_ITEM));
ZeroMemory (Item, sizeof (*Item));
GetNext (&Sequence, &Data);
Item->Thread = GetCurrentThreadId ();
Item->Sequence = Sequence;
Item->Data = Data;
Inserted = RaidInsertExDeviceQueue (&DeviceQueue,
&Item->DeviceEntry,
TRUE,
(ULONG)Item->Data);
if (!Inserted) {
if (Verbose) {
printf ("started %x.%I64d\n", Item->Thread, Item->Data);
}
InsertDpcItem (&DpcQueue, &Item->DpcEntry);
} else {
if (Verbose) {
printf ("queued %x.%I64d\n", Item->Thread, Item->Data);
}
}
}
return FALSE;
}
VOID
DpcRoutine(
IN PTQ_ITEM Item
)
{
BOOLEAN RestartQueue;
PKDEVICE_QUEUE_ENTRY Entry;
if (Verbose || Cerbose) {
printf ("completed %x.%I64d\n", Item->Thread, Item->Data);
}
free (Item);
Entry = RaidRemoveExDeviceQueue (&DeviceQueue, &RestartQueue);
if (Entry) {
Item = CONTAINING_RECORD (Entry, TQ_ITEM, DeviceEntry);
InsertDpcItem (&DpcQueue, &Item->DpcEntry);
if (Verbose) {
printf ("dpc started %x.%I64d\n", Item->Thread, Item->Data);
}
//
// NB: in the port driver, we actually only do this when necessary.
// The only problem with doing this always is a speed issue, and
// we're not measuring speed in the simulation program.
//
for (Entry = RaidNormalizeExDeviceQueue (&DeviceQueue);
Entry != NULL;
Entry = RaidNormalizeExDeviceQueue (&DeviceQueue)) {
Item = CONTAINING_RECORD (Entry, TQ_ITEM, DeviceEntry);
InsertDpcItem (&DpcQueue, &Item->DpcEntry);
}
}
}
BOOL
WINAPI
DpcThread(
PVOID Unused
)
{
PLIST_ENTRY Entry;
PTQ_ITEM Item;
#if 1
SetThreadPriority (GetCurrentThread (),
THREAD_PRIORITY_ABOVE_NORMAL);
#endif
for (;;) {
while (Pause) {
Sleep (10);
}
//
// Wait for DPC queue to have an item in it
//
Entry = RemoveDpcItem (&DpcQueue);
Item = CONTAINING_RECORD (Entry, TQ_ITEM, DpcEntry);
DpcRoutine (Item);
}
return FALSE;
}
enum {
NoControl = 0,
FreezeQueue,
ResumeQueue
};
volatile ULONG Control = NoControl;
BOOL
WINAPI
ControlThread(
PVOID Unused
)
{
for (;;) {
Sleep (500);
switch (Control) {
case FreezeQueue:
RaidFreezeExDeviceQueue (&DeviceQueue);
Control = NoControl;
break;
case ResumeQueue:
RaidResumeExDeviceQueue (&DeviceQueue);
Control = NoControl;
break;
case NoControl:
break;
default:
ASSERT (FALSE);
}
}
return FALSE;
}
BOOL
WINAPI
ControlHandler(
DWORD Val
)
{
PLIST_ENTRY NextEntry;
PTQ_ITEM Item;
int ch;
if (Val != CTRL_C_EVENT) {
return FALSE;
}
Pause = TRUE;
Sleep (1000);
printf ("\n");
do {
printf ("tq> ");
ch = getchar ();
printf (" %c\n", ch);
switch (tolower (ch)) {
case 'd':
printf ("Dump of DeviceQueue: %p\n", &DeviceQueue);
printf (" Depth %d\n", DeviceQueue.Depth);
printf (" Outstanding %d\n", DeviceQueue.OutstandingRequests);
printf (" Device %d\n", DeviceQueue.DeviceRequests);
printf (" ByPass %d\n", DeviceQueue.ByPassRequests);
printf (" Frozen %d\n", DeviceQueue.Frozen);
break;
case 'l':
__try {
ULONG Count;
Count = 0;
for ( NextEntry = DeviceQueue.DeviceListHead.Flink;
NextEntry != &DeviceQueue.DeviceListHead;
NextEntry = NextEntry->Flink ) {
Count++;
Item = CONTAINING_RECORD (NextEntry, TQ_ITEM, DeviceEntry);
printf (" item %d.%I64d [seq=%d]\n",
Item->Thread,
Item->Data,
Item->Sequence);
}
printf ("DeviceList: %d entries\n", Count);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
printf ("ERROR: Inconsistent device list!\n");
}
break;
case 'r':
Control = ResumeQueue;
break;
case 'f':
Control = FreezeQueue;
break;
case 'q':
exit (0);
break;
case 'c':
case 'g':
break;
case 'p':
if (PauseProducer) {
printf ("unpausing producers\n");
PauseProducer = FALSE;
} else {
printf ("unpausing producers\n");
PauseProducer = TRUE;
}
break;
case 'v':
if (Verbose) {
Verbose = FALSE;
printf ("verbose mode off\n");
} else {
Verbose = TRUE;
printf ("verbose mode enabled\n");
}
case 'x': {
ULONG NewDepth;
printf ("depth> ");
scanf ("%d", &NewDepth);
RaidSetExDeviceQueueDepth (&DeviceQueue, NewDepth);
printf ("stack depth set to %d\n", NewDepth);
break;
}
case '?':
printf (" d - dump queue\n");
printf (" f - freeze queue\n");
printf (" r - resume queue\n");
printf (" p - toggle pause of producer threads\n");
printf (" u - resume producer threads\n");
printf (" g - go\n");
printf (" x - set stack depth to new value\n");
printf (" v - toggle verbose mode\n");
printf (" q - stop\n");
break;
default:
printf ("unrecognized operation '%c'\n", ch);
}
} while (ch != 'c' && ch != 'g');
Pause = FALSE;
return TRUE;
}
VOID
__cdecl
main(
)
{
DWORD ThreadId;
ULONG Depth;
ULONG ProducerThreads;
ULONG DpcThreads;
ULONG i;
SCHEDULING_ALGORITHM SchedulingAlgorithm;
RAID_ADAPTER_QUEUE AdapterQueue;
QUEUING_MODEL QueuingModel;
//
// Generic adapter queue.
//
QueuingModel.Algorithm = BackOffFullQueue;
QueuingModel.BackOff.HighWaterPercent = 120;
QueuingModel.BackOff.LowWaterPercent = 40;
RaidCreateAdapterQueue (&AdapterQueue, &QueuingModel);
//
// NB: these should all be parameters
//
Depth = 1;
ProducerThreads = 8;
DpcThreads = 1;
SchedulingAlgorithm = CScanScheduling;
printf ("DeviceQueue Test: Depth %d Producers %d DPC Threads %d\n",
Depth,
ProducerThreads,
DpcThreads);
if (Verbose) {
printf ("Verbose\n");
}
printf ("\n");
CreateDpcQueue (&DpcQueue);
RaidInitializeExDeviceQueue (&DeviceQueue,
&AdapterQueue,
Depth,
SchedulingAlgorithm);
SetConsoleCtrlHandler (ControlHandler, TRUE);
for (i = 0; i < DpcThreads; i++) {
CreateThread (NULL,
0,
DpcThread,
0,
0,
&ThreadId);
}
for (i = 0; i < ProducerThreads; i++) {
CreateThread (NULL,
0,
ProducerThread,
0,
0,
&ThreadId);
}
CreateThread (NULL,
0,
ControlThread,
0,
0,
&ThreadId);
CreateThread (NULL,
0,
ProducerThread100,
0,
0,
&ThreadId);
#if 0
CreateThread (NULL,
0,
ErrorProducerThread,
0,
0,
&ThreadId);
CreateThread (NULL,
0,
UpdateThread,
0,
0,
&ThreadId);
#endif
Sleep (INFINITE);
}