|
|
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
nbtest.c
Abstract:
This module contains code to stress test the nonblocking queue functions.
Author:
David N. Cutler (davec) 19-May-2001
Environment:
Kernel mode only.
Revision History:
--*/
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "nt.h"
#include "ntrtl.h"
#include "nturtl.h"
#include "zwapi.h"
#include "windef.h"
#include "winbase.h"
//
// Define progress limit report value.
//
#define PROGRESS_LIMIT 1000000
ULONG Iteration = 0; LONG Progress = 0;
//
// Define processor yield for hyperthreaded systems.
//
#if defined(_X86_)
#define YieldProcessor() __asm {rep nop}
#else
#define YieldProcessor()
#endif
//
// Define locals constants.
//
#define TABLE_SIZE 2
#define THREAD_NUMBER 2
//
// Define external prototypes.
//
typedef struct _NBQUEUE_BLOCK { ULONG64 Next; ULONG64 Data; } NBQUEUE_BLOCK, *PNBQUEUE_BLOCK;
PVOID ExInitializeNBQueueHead ( IN PSLIST_HEADER SlistHead );
BOOLEAN ExInsertTailNBQueue ( IN PVOID Header, IN ULONG64 Value );
BOOLEAN ExRemoveHeadNBQueue ( IN PVOID Header, OUT PULONG64 Value );
//
// Define local routine prototypes.
//
NTSTATUS MyCreateThread ( OUT PHANDLE Handle, IN PUSER_THREAD_START_ROUTINE StartRoutine, PVOID Context
);
VOID StressNBQueueEven ( VOID );
VOID StressNBQueueOdd ( VOID );
NTSTATUS ThreadMain ( IN PVOID Context );
//
// Define static storage.
//
HANDLE Thread1Handle; HANDLE Thread2Handle;
//
// Define nonblocking queues
//
PVOID ClrQueue; PVOID SetQueue;
SLIST_HEADER SListHead;
LONG Table[TABLE_SIZE];
volatile ULONG StartSignal = 0; ULONG StopSignal = 0;
//
// Begin test code.
//
int __cdecl main( int argc, char *argv[] )
{
ULONG Index; PSLIST_ENTRY Entry; NTSTATUS Status;
//
// Initialize the SLIST headers and insert TABLE_SIZE + 2 entries.
//
RtlInitializeSListHead(&SListHead); for (Index = 0; Index < (TABLE_SIZE + 2); Index += 1) { Entry = (PSLIST_ENTRY)malloc(sizeof(NBQUEUE_BLOCK)); if (Entry == NULL) { printf("unable to allocate SLIST entry\n"); return 0; }
InterlockedPushEntrySList(&SListHead, Entry); }
//
// Initialize the clear entry nonblocking queue elements.
//
ClrQueue = ExInitializeNBQueueHead(&SListHead); if (ClrQueue == NULL) { printf("unable to initialize clr nonblock queue\n"); return 0; }
for (Index = 0; Index < (TABLE_SIZE / 2); Index += 1) { if (ExInsertTailNBQueue(ClrQueue, Index) == FALSE) { printf("unable to insert in clear nonblocking queue\n"); return 0; }
Table[Index] = 0; }
//
// Initialize the set entry nonblocking queue elements.
//
SetQueue = ExInitializeNBQueueHead(&SListHead); if (SetQueue == NULL) { printf("unable to initialize set nonblock queue\n"); return 0; }
for (Index = (TABLE_SIZE / 2); Index < TABLE_SIZE; Index += 1) { if (ExInsertTailNBQueue(SetQueue, Index) == FALSE) { printf("unable to insert in set nonblocking queue\n"); return 0; }
Table[Index] = 1; }
//
// Create and start second thread.
//
Status = MyCreateThread(&Thread1Handle, ThreadMain, (PVOID)1);
if (!NT_SUCCESS(Status)) { printf("Failed to create thread during initialization\n"); return 0;
} else { StartSignal = 1; StressNBQueueEven(); }
return 0; }
VOID StressNBQueueEven ( VOID )
{
ULONG64 Value;
do { do {
//
// Attempt to remove an entry from the clear queue.
//
// Entries in this list should be clear in the table array.
//
if (ExRemoveHeadNBQueue(ClrQueue, &Value) != FALSE) { if ((ULONG)Value > 63) { StopSignal = 1; DbgBreakPoint(); }
if (InterlockedExchange(&Table[(ULONG)Value], 1) != 0) { StopSignal = 1; DbgBreakPoint(); } if (ExInsertTailNBQueue(SetQueue, (ULONG)Value) == FALSE) { StopSignal = 1; DbgBreakPoint(); } } else { break; } if (InterlockedIncrement(&Progress) > PROGRESS_LIMIT) { InterlockedExchange(&Progress, 0); Iteration += 1; printf("progress report iteration %d\n", Iteration); } YieldProcessor(); } while (TRUE);
do { //
// Attempt to remove an entry from the set queue.
//
// Entries in this list should be set in the table array.
//
if (ExRemoveHeadNBQueue(SetQueue, &Value) != FALSE) { if ((ULONG)Value > 63) { StopSignal = 1; DbgBreakPoint(); }
if (InterlockedExchange(&Table[(ULONG)Value], 0) != 1) { StopSignal = 1; DbgBreakPoint(); } if (ExInsertTailNBQueue(ClrQueue, (ULONG)Value) == FALSE) { StopSignal = 1; DbgBreakPoint(); } } else { break; } if (InterlockedIncrement(&Progress) > PROGRESS_LIMIT) { InterlockedExchange(&Progress, 0); Iteration += 1; printf("progress report iteration %d\n", Iteration); } YieldProcessor(); } while (TRUE);
} while (TRUE);
return; }
VOID StressNBQueueOdd ( VOID )
{
ULONG64 Value;
do { do { //
// Attempt to remove an entry from the set queue.
//
// Entries in this list should be set in the table array.
//
if (ExRemoveHeadNBQueue(SetQueue, &Value) != FALSE) { if ((ULONG)Value > 63) { StopSignal = 1; DbgBreakPoint(); }
if (InterlockedExchange(&Table[(ULONG)Value], 0) != 1) { StopSignal = 1; DbgBreakPoint(); } if (ExInsertTailNBQueue(ClrQueue, (ULONG)Value) == FALSE) { StopSignal = 1; DbgBreakPoint(); } } else { break; }
InterlockedIncrement(&Progress); YieldProcessor(); } while (TRUE);
do { //
// Attempt to remove an entry from the clear queue.
//
// Entries in this list should be clear in the table array.
//
if (ExRemoveHeadNBQueue(ClrQueue, &Value) != FALSE) { if ((ULONG)Value > 63) { StopSignal = 1; DbgBreakPoint(); }
if (InterlockedExchange(&Table[(ULONG)Value], 1) != 0) { StopSignal = 1; DbgBreakPoint(); } if (ExInsertTailNBQueue(SetQueue, (ULONG)Value) == FALSE) { StopSignal = 1; DbgBreakPoint(); } } else { break; } InterlockedIncrement(&Progress); YieldProcessor(); } while (TRUE);
} while (TRUE);
return; }
NTSTATUS ThreadMain ( IN PVOID Context )
{
//
// Wait until start signal is given.
//
do { } while (StartSignal == 0);
StressNBQueueOdd(); return STATUS_SUCCESS; }
NTSTATUS MyCreateThread ( OUT PHANDLE Handle, IN PUSER_THREAD_START_ROUTINE StartRoutine, PVOID Context )
{
NTSTATUS Status;
//
// Create a thread and start its execution.
//
Status = RtlCreateUserThread(NtCurrentProcess(), NULL, FALSE, 0, 0, 0, StartRoutine, Context, Handle, NULL);
if (!NT_SUCCESS(Status)) { return Status; }
return Status; }
|