Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

456 lines
8.6 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
stack.c
Abstract:
This provides a generic stack handler to push/pop things onto it
Author:
Stephane Plante (splante)
Environment:
User, Kernel
--*/
#include "pch.h"
NTSTATUS
StackAllocate(
OUT PSTACK *Stack,
IN ULONG StackElementSize
)
/*++
Routine Description:
This routine allocates memory and returns a stack object
Arguments:
Stack - Where to store a pointer to the stack
StackElementSize - How much space on the stack a single element takes
up
Return Value:
NTSTATUS
--*/
{
PSTACK tempStack;
NTSTATUS status = STATUS_SUCCESS;
//
// Make sure that we have some place to store the stack pointer
//
ASSERT( Stack != NULL );
ASSERT( StackElementSize != 0 );
//
// Allocate a block of memory for the stack
//
tempStack = MEMORY_ALLOCATE(
sizeof(STACK) + ( (STACK_GROWTH_RATE * StackElementSize) - 1)
);
if (tempStack == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto StackAllocateExit;
}
//
// Setup the control block of the stack
//
tempStack->Signature = (ULONG) STACK_SIGNATURE;
tempStack->StackSize = STACK_GROWTH_RATE * StackElementSize;
tempStack->StackElementSize = StackElementSize;
tempStack->TopOfStack = 0;
//
// Zero out the current elements on the stack
//
MEMORY_ZERO(
&(tempStack->Stack[0]),
STACK_GROWTH_RATE * StackElementSize
);
//
// Return the stack pointer
//
StackAllocateExit:
*Stack = tempStack;
return status;
}
NTSTATUS
StackFree(
IN OUT PSTACK *Stack
)
/*++
Routine Description:
This routine frees the stack
Arguments:
Stack - Where to find a pointer to the stack
Return Value:
NTSTATUS
--*/
{
//
// Make sure that we point to something
//
ASSERT( Stack != NULL );
ASSERT( (*Stack)->Signature == STACK_SIGNATURE );
//
// Free the stack
//
MEMORY_FREE( *Stack );
//
// Point the stack to nowhere
//
*Stack = NULL;
return STATUS_SUCCESS;
}
NTSTATUS
StackParent(
IN OUT PSTACK *Stack,
IN PVOID Child,
OUT PVOID Parent
)
/*++
Routine Description:
This routine returns a pointer to the stack location that is before
the given Child.
Arguments:
Stack - The stack to operate on
Child - This is the node whose parent we want
Parent - This is where we store a pointer to the parent stack loc
Return Value:
NTSTATUS
--*/
{
PSTACK localStack;
ULONG Addr = (ULONG) Child;
//
// Make sure that we point to something
//
ASSERT( Stack != NULL );
ASSERT( (*Stack)->Signature == STACK_SIGNATURE );
ASSERT( Parent != NULL );
//
// make sure that the child node actually lies on the stack
//
localStack = *Stack;
if ( Addr < (ULONG) localStack->Stack ||
Addr > (ULONG) &(localStack->Stack[localStack->TopOfStack + 1]) -
localStack->StackElementSize ) {
*( (PULONG *)Parent) = NULL;
return STATUS_FAIL_CHECK;
}
//
// Make sure that the child node isn't the first element
//
if (Addr < (ULONG) &(localStack->Stack[localStack->StackElementSize]) ) {
*( (PULONG *)Parent) = NULL;
return STATUS_SUCCESS;
}
//
// Set the parent to be one before the child
//
*( (PULONG *)Parent) = (PULONG) (Addr - localStack->StackElementSize);
//
// Done
//
return STATUS_SUCCESS;
}
NTSTATUS
StackPop(
IN OUT PSTACK *Stack
)
/*++
Routine Description:
This routine reclaims the memory used for a stack location
and wipes out whatever data existed in the reclaimed area
Arguments:
Stack - Where to find a pointer to the stack
Return Value:
NTSTATUS
--*/
{
PSTACK localStack;
//
// Make sure that we point to something
//
ASSERT( Stack != NULL );
ASSERT( (*Stack)->Signature == STACK_SIGNATURE );
//
// Is there an item that we can remove from the stack?
//
localStack = *Stack;
if ( localStack->TopOfStack == 0) {
return STATUS_FAIL_CHECK;
}
//
// Wipe out the top-most element on the stack
//
localStack->TopOfStack -= localStack->StackElementSize;
MEMORY_ZERO(
&( localStack->Stack[ localStack->TopOfStack ] ),
localStack->StackElementSize
);
return STATUS_SUCCESS;
}
NTSTATUS
StackPush(
IN OUT PSTACK *Stack,
OUT PVOID StackElement
)
/*++
Routine Description:
This routine obtains a pointer for an object on the top of the stack
and increments the top to point to something that can be then be used
again.
Arguments:
Stack - Where to find a pointer to the stack
StackElement - Pointer to the element to be added to the stack
Return Value:
NTSTATUS
--*/
{
PSTACK localStack;
PSTACK tempStack;
ULONG newSize;
ULONG deltaSize;
//
// Make sure that we point to something
//
ASSERT( Stack != NULL );
ASSERT( StackElement != NULL );
//
// Find the stack pointer and make sure that the signature is still
// valid
//
localStack = *Stack;
ASSERT( localStack->Signature == STACK_SIGNATURE );
//
// Do we have enough space on the stack?
//
if ( localStack->TopOfStack >= localStack->StackSize ) {
//
// Figure out how many bytes by which to grow the stack and how
// large the total stack should be
//
deltaSize = (STACK_GROWTH_RATE * localStack->StackElementSize);
newSize = sizeof(STACK) + localStack->StackSize + deltaSize - 1;
//
// Grow the stack
//
tempStack = MEMORY_ALLOCATE( newSize );
if (tempStack == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Empty the new stack and copy the old one to it
//
MEMORY_ZERO( &(tempStack->Stack[0]), newSize - sizeof(STACK) + 1);
MEMORY_COPY( tempStack, localStack , newSize - deltaSize);
//
// Make sure that the new stack has the correct size
//
tempStack->StackSize += deltaSize;
//
// Free the old stack
//
StackFree( Stack );
//
// Set the stack to point to the new one
//
*Stack = localStack = tempStack;
}
//
// Grab a pointer to the part that we will return to the caller
//
*( (PUCHAR *)StackElement) = &(localStack->Stack[ localStack->TopOfStack ]);
//
// Find the new Top of Stack
//
localStack->TopOfStack += localStack->StackElementSize;
//
// Done
//
return STATUS_SUCCESS;
}
NTSTATUS
StackRoot(
IN OUT PSTACK *Stack,
OUT PVOID RootElement
)
/*++
Routine Description:
This routine returns the first element on the stack
Arguments:
Stack - Where the stack is located
RootElement - Where to store the pointer to the root stack element
Return Value:
NTSTATUS
--*/
{
PSTACK localStack;
ASSERT( Stack != NULL && *Stack != NULL );
ASSERT( (*Stack)->Signature == STACK_SIGNATURE );
localStack = *Stack;
if (localStack->TopOfStack < localStack->StackElementSize) {
//
// There is no stack location we can use
//
*( (PUCHAR *)RootElement) = NULL;
return STATUS_UNSUCCESSFUL;
}
//
// Grab the root element
//
*( (PUCHAR *)RootElement) = localStack->Stack;
//
// Done
//
return STATUS_SUCCESS;
}
NTSTATUS
StackTop(
IN OUT PSTACK *Stack,
OUT PVOID TopElement
)
/*++
Routine Description:
This routine returns the topmost stack location that is in current use
Arguments:
Stack - Where the stack is located
TopElement - Where to store the pointer to the top stack element
Return Value:
NTSTATUS
--*/
{
PSTACK localStack;
ULONG offset;
ASSERT( Stack != NULL );
ASSERT( (*Stack)->Signature == STACK_SIGNATURE );
localStack = *Stack;
if (localStack->TopOfStack < localStack->StackElementSize) {
//
// No stack locations are in current use
//
*( (PUCHAR *)TopElement) = NULL;
return STATUS_UNSUCCESSFUL;
} else {
offset = localStack->TopOfStack - localStack->StackElementSize;
}
//
// Grab the top stack location
//
*( (PUCHAR *)TopElement) = &(localStack->Stack[ offset ]);
//
// Done
//
return STATUS_SUCCESS;
}