diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/mvdm/suballoc | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/mvdm/suballoc')
-rw-r--r-- | private/mvdm/suballoc/debug.c | 0 | ||||
-rw-r--r-- | private/mvdm/suballoc/foo.bar | 177 | ||||
-rw-r--r-- | private/mvdm/suballoc/makefile | 6 | ||||
-rw-r--r-- | private/mvdm/suballoc/sources | 45 | ||||
-rw-r--r-- | private/mvdm/suballoc/suballcp.h | 178 | ||||
-rw-r--r-- | private/mvdm/suballoc/suballoc.c | 931 | ||||
-rw-r--r-- | private/mvdm/suballoc/suballoc.txt | 276 | ||||
-rw-r--r-- | private/mvdm/suballoc/tsa.c | 879 |
8 files changed, 2492 insertions, 0 deletions
diff --git a/private/mvdm/suballoc/debug.c b/private/mvdm/suballoc/debug.c new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/private/mvdm/suballoc/debug.c diff --git a/private/mvdm/suballoc/foo.bar b/private/mvdm/suballoc/foo.bar new file mode 100644 index 000000000..3d869b8c9 --- /dev/null +++ b/private/mvdm/suballoc/foo.bar @@ -0,0 +1,177 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + suballcp.h + +Abstract: + + This is the private include file for the suballocation + package. + +Author: + + Dave Hastings (daveh) creation-date 25-Jan-1994 + +Revision History: + + +--*/ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +#include <malloc.h> +#include <suballoc.h> + + +// +// Constants +// + +// +// Smallest chunk that will be sub allocated +// 1024 was chosen currently, because that is the +// smallest chunk XMS will allocate. +// +#define SUBALLOC_GRANULARITY 1024 + +// +// Assertions and macros +// + +// +// Force code to be stepped through +// +#if 0 +#define ASSERT_STEPTHROUGH DbgBreakPoint() +#else +#define ASSERT_STEPTHROUGH +#endif + +// +// Signature macros for SUBALLOCATION +// +#if DBG +// +// signature is "SubA" +// +#define INIT_SUBALLOC_SIGNATURE(p) p->Signature = (ULONG)0x41627553 +#define ASSERT_SUBALLOC(p) ASSERT((p->Signature == (ULONG)0x41627553)) +#else +#define INIT_SUBALLOC_SIGNATURE(p) +#define ASSERT_SUBALLOC(p) +#endif + +// +// Macro for extracting a bit from a bitfield of type char +// +#define GET_BIT_FROM_CHAR_ARRAY(p, i) \ +((p[i/(sizeof(UCHAR) * 8)] >> (i % (sizeof(UCHAR) * 8))) & 1) + +// +// Macro for setting a bit in a bitfield of type char +// +#define SET_BIT_IN_CHAR_ARRAY(p, i) \ +(p[i/(sizeof(UCHAR) * 8)] |= (1 << (i % (sizeof(UCHAR) * 8)))) + +// +// Macro for clearing a bit in a bitfield of type char +// +#define CLEAR_BIT_IN_CHAR_ARRAY(p, i) \ +(p[i/(sizeof(UCHAR) * 8)] &= ~(1 << (i % (sizeof(UCHAR) * 8)))) + +// +// Generate a sub alloc block index from an address +// +#define ADDRESS_TO_BLOCK_INDEX(p, i) \ +((i - p->BaseAddress)/ SUBALLOC_GRANULARITY) + +// +// Generate an address from a block index +// +#define BLOCK_INDEX_TO_ADDRESS(p, i) \ +(p->BaseAddress + i * SUBALLOC_GRANULARITY) + +// Round the allocated size to next allocation +// granularity +// +#define ALLOC_ROUND(s) \ +(s + SUBALLOC_GRANULARITY - 1) / SUBALLOC_GRANULARITY + +// +// Types +// + +// +// Enum for commit acctions +// + +typedef enum { + SACommit, + SADecommit +} COMMIT_ACTION; + +// +// Structure for tracking the address space. Each chunk of +// memory of SUBALLOC_GRANULARITY in size is represented by +// a bit. Each chunk of memory of COMMIT_GRANULARITY is +// represented by one bit of the array Allocated. +// +// ?? Should we add a field to indicate whether the chunk is +// committed? We can always check for all allocated bits +// zero, and use that as an indication that the chunk is +// not committed. +// +// +typedef struct _SubAllocation { +#if DBG + ULONG Signature; +#endif + PSACOMMITROUTINE CommitRoutine; + PSACOMMITROUTINE DecommitRoutine; + PSAMEMORYMOVEROUTINE MoveMemRoutine; + ULONG BaseAddress; + ULONG Size; // size in SUBALLOC_GRANULARITY + ULONG FirstFree; // keeps block # of first free block + // cuts alloc time in half + // + // bitfield with one bit per chunk. Bit set indicates + // allocated. Bit clear indicates free. All bits + // clear indicates un committed + // + UCHAR Allocated[1]; +} SUBALLOCATIONDATA, *PSUBALLOCATIONDATA; + +// +// Internal Routines +// +BOOL +CommitChunk( + PSUBALLOCATIONDATA SubAllocation, + ULONG StartChunk, + ULONG Size, + COMMIT_ACTION Action + ); + +BOOL +IsBlockCommitted( + PSUBALLOCATIONDATA SubAlloc, + ULONG CurrentBlock + ); + +BOOL +AllocateChunkAt( + PSUBALLOCATIONDATA SubAlloc, + ULONG Size, + ULONG BlockIndex + ); + +BOOL +FreeChunk( + PSUBALLOCATIONDATA SubAlloc, + ULONG Size, + ULONG BlockIndex + ); diff --git a/private/mvdm/suballoc/makefile b/private/mvdm/suballoc/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/mvdm/suballoc/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/mvdm/suballoc/sources b/private/mvdm/suballoc/sources new file mode 100644 index 000000000..888018bdd --- /dev/null +++ b/private/mvdm/suballoc/sources @@ -0,0 +1,45 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Dave Hastings (daveh) 25-Jan-1994 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + + +MAJORCOMP=mvdm +MINORCOMP=suballoc + +TARGETNAME=suballoc + +TARGETPATH=\nt\public\sdk\lib + +TARGETTYPE=LIBRARY + + + +INCLUDES=..\inc + +SOURCES=suballoc.c + +C_DEFINES=-DDEV_DBG + +UMTYPE=console +UMTEST=tsa +UMLIBS=\nt\public\sdk\lib\*\suballoc.lib diff --git a/private/mvdm/suballoc/suballcp.h b/private/mvdm/suballoc/suballcp.h new file mode 100644 index 000000000..54c51fcb8 --- /dev/null +++ b/private/mvdm/suballoc/suballcp.h @@ -0,0 +1,178 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + suballcp.h + +Abstract: + + This is the private include file for the suballocation + package. + +Author: + + Dave Hastings (daveh) creation-date 25-Jan-1994 + +Revision History: + + +--*/ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +#include <malloc.h> +#include <suballoc.h> + + +// +// Constants +// + +// +// Smallest chunk that will be sub allocated +// 1024 was chosen currently, because that is the +// smallest chunk XMS will allocate. +// +#define SUBALLOC_GRANULARITY 1024 + +// +// Assertions and macros +// + +// +// Force code to be stepped through +// +#if 0 +#define ASSERT_STEPTHROUGH DbgBreakPoint() +#else +#define ASSERT_STEPTHROUGH +#endif + +// +// Signature macros for SUBALLOCATION +// +#if DBG +// +// signature is "SubA" +// +#define INIT_SUBALLOC_SIGNATURE(p) p->Signature = (ULONG)0x41627553 +#define ASSERT_SUBALLOC(p) ASSERT((p->Signature == (ULONG)0x41627553)) +#else +#define INIT_SUBALLOC_SIGNATURE(p) +#define ASSERT_SUBALLOC(p) +#endif + +// +// Macro for extracting a bit from a bitfield of type char +// +#define GET_BIT_FROM_CHAR_ARRAY(p, i) \ +((p[(i)/(sizeof(UCHAR) * 8)] >> ((i) % (sizeof(UCHAR) * 8))) & 1) + +// +// Macro for setting a bit in a bitfield of type char +// +#define SET_BIT_IN_CHAR_ARRAY(p, i) \ +(p[(i)/(sizeof(UCHAR) * 8)] |= (1 << ((i) % (sizeof(UCHAR) * 8)))) + +// +// Macro for clearing a bit in a bitfield of type char +// +#define CLEAR_BIT_IN_CHAR_ARRAY(p, i) \ +(p[(i)/(sizeof(UCHAR) * 8)] &= ~(1 << ((i) % (sizeof(UCHAR) * 8)))) + +// +// Generate a sub alloc block index from an address +// +#define ADDRESS_TO_BLOCK_INDEX(p, i) \ +((i - p->BaseAddress)/ SUBALLOC_GRANULARITY) + +// +// Generate an address from a block index +// +#define BLOCK_INDEX_TO_ADDRESS(p, i) \ +(p->BaseAddress + (i) * SUBALLOC_GRANULARITY) + +// Round the allocated size to next allocation +// granularity +// +#define ALLOC_ROUND(s) \ +(s + SUBALLOC_GRANULARITY - 1) / SUBALLOC_GRANULARITY + +// +// Types +// + +// +// Enum for commit acctions +// + +typedef enum { + SACommit, + SADecommit +} COMMIT_ACTION; + +// +// Structure for tracking the address space. Each chunk of +// memory of SUBALLOC_GRANULARITY in size is represented by +// a bit. Each chunk of memory of COMMIT_GRANULARITY is +// represented by one bit of the array Allocated. +// +// ?? Should we add a field to indicate whether the chunk is +// committed? We can always check for all allocated bits +// zero, and use that as an indication that the chunk is +// not committed. +// +// +typedef struct _SubAllocation { +#if DBG + ULONG Signature; +#endif + PSACOMMITROUTINE CommitRoutine; + PSACOMMITROUTINE DecommitRoutine; + PSAMEMORYMOVEROUTINE MoveMemRoutine; + ULONG BaseAddress; + ULONG Size; // size in SUBALLOC_GRANULARITY + ULONG FirstFree; // keeps block # of first free block + // cuts alloc time in half + // + // bitfield with one bit per chunk. Bit set indicates + // allocated. Bit clear indicates free. All bits + // clear indicates un committed + // + UCHAR Allocated[1]; +} SUBALLOCATIONDATA, *PSUBALLOCATIONDATA; + +// +// Internal Routines +// +BOOL +CommitChunk( + PSUBALLOCATIONDATA SubAllocation, + ULONG StartChunk, + ULONG Size, + COMMIT_ACTION Action + ); + +BOOL +IsBlockCommitted( + PSUBALLOCATIONDATA SubAlloc, + ULONG CurrentBlock + ); + +BOOL +AllocateChunkAt( + PSUBALLOCATIONDATA SubAlloc, + ULONG Size, + ULONG BlockIndex, + BOOLEAN CheckFree + ); + +BOOL +FreeChunk( + PSUBALLOCATIONDATA SubAlloc, + ULONG Size, + ULONG BlockIndex + ); diff --git a/private/mvdm/suballoc/suballoc.c b/private/mvdm/suballoc/suballoc.c new file mode 100644 index 000000000..c2021ec4c --- /dev/null +++ b/private/mvdm/suballoc/suballoc.c @@ -0,0 +1,931 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + suballoc.c + +Abstract: + + This module contains code for managing a paritially commited address + space. It handles allocation of chunks of memory smaller than the + commit granularity. It commits and decommits memory as needed using + the supplied function for committing and decommitting memory. The + structures used for tracking the address space are allocated outside + of the specified addresss space. + +Author: + + Dave Hastings (daveh) creation-date 21-Jan-1994 + +Notes: + + Since this package does not actually access memory in the address space + it is managing, it will work as well with real linear addresses or + "Intel Addresses" such as would be encountered with the Insignia Emulator + on risc. + +Revision History: + + +--*/ +#include "suballcp.h" + +PVOID +SAInitialize( + ULONG BaseAddress, + ULONG Size, + PSACOMMITROUTINE CommitRoutine, + PSACOMMITROUTINE DecommitRoutine, + PSAMEMORYMOVEROUTINE MemoryMoveRoutine + ) +/*++ + +Routine Description: + + This function performs initialization of the sub allocation package + for the specified addresss range. It allocates the data structures + necessary to track the allocations + +Arguments: + + BaseAddress -- Supplies the base address of the address space to + sub allocate. + Size -- Supplies the size in bytes of the address space to sub allocate. + CommitRoutine -- Supplies a pointer to the routine used to commit regions + of the address space. + +Return Value: + + If the function was successful it returns a pointer to the sub-allocation + data structures. Otherwise it returns NULL. + +--*/ +{ + PSUBALLOCATIONDATA SubAlloc; + ULONG SASize; + + ASSERT_STEPTHROUGH; + // + // Asserts to insure that everything is as we expect it to be + // + ASSERT(((COMMIT_GRANULARITY % SUBALLOC_GRANULARITY) == 0)); + + // + // Allocate the tracking structure + // + // SUBALLOCATIONDATA is declared with 1 uchar for the bitmap. + // this is the reason for subtracting one from the total size + // calculation. + // + SASize = sizeof(SUBALLOCATIONDATA) + + (Size / SUBALLOC_GRANULARITY) / sizeof(UCHAR) - 1; + + SubAlloc = malloc(SASize); + + if (SubAlloc == NULL) { + return NULL; + } + + // + // Initialize the structure + // + RtlZeroMemory(SubAlloc, SASize); + + INIT_SUBALLOC_SIGNATURE(SubAlloc); + SubAlloc->BaseAddress = BaseAddress; + SubAlloc->Size = Size / SUBALLOC_GRANULARITY; + SubAlloc->CommitRoutine = CommitRoutine; + SubAlloc->DecommitRoutine = DecommitRoutine; + SubAlloc->MoveMemRoutine = MemoryMoveRoutine; + + return SubAlloc; +} + +BOOL +SAQueryFree( + PVOID SubAllocation, + PULONG FreeBytes, + PULONG LargestFreeBlock + ) +/*++ + +Routine Description: + + This routine returns the number of free bytes in the + sub allocated address space. + +Arguments: + + SubAllocation -- Supplies the pointer returned by SAInitialize + FreeBytes -- Returns the number of free bytes + +Return Value: + + TRUE -- if successful, and FreeBytes contains the number of free bytes. + FALSE otherwise + +--*/ +{ + ULONG i, FreeCount; + PSUBALLOCATIONDATA SubAlloc; + ULONG TempLargest, LargestBlock; + + ASSERT_STEPTHROUGH; + + // + // Get a typed pointer + // + SubAlloc = SubAllocation; + + // + // Make sure that we have what we think we do + // + ASSERT_SUBALLOC(SubAlloc); + + // + // Count the free chunks and find largest block + // + FreeCount = 0; + LargestBlock = 0; + i = 0; + while (i < SubAlloc->Size) { + + TempLargest = 0; + while ( + (i < SubAlloc->Size) && + (GET_BIT_FROM_CHAR_ARRAY(SubAlloc->Allocated, i) == 0) + ){ + FreeCount++; + TempLargest++; + i++; + } + + if (TempLargest > LargestBlock) { + LargestBlock = TempLargest; + } + + // + // Skip allocated blocks + // + while ( + (i < SubAlloc->Size) && + (GET_BIT_FROM_CHAR_ARRAY(SubAlloc->Allocated, i) == 1) + ) { + i++; + } + } + + *FreeBytes = FreeCount * SUBALLOC_GRANULARITY; + *LargestFreeBlock = LargestBlock * SUBALLOC_GRANULARITY; + return TRUE; +} + +BOOL +SAAllocate( + PVOID SubAllocation, + ULONG Size, + PULONG Address + ) +/*++ + +Routine Description: + + This function allocates a portion of the address space described by + SubAllocation. If necessary, it will commit additional blocks. + Size is rounded up to the next higher multiple of SUBALLOC_GRANULARITY. + +Arguments: + + SubAllocation -- Supplies the pointer returned by SAInitialize. + Size -- Supplies the size in bytes of the region to allocate. + Address -- Returns the address of the region allocated. + +Return Value: + + TRUE if successful. If false is returned, no address is returned. + +Notes: + + Zero is a valid value for the returned address. + +--*/ +{ + ULONG AllocateSize, i, CurrentChunk; + BOOL Done = FALSE; + PSUBALLOCATIONDATA SubAlloc; + BOOL Success; + + ASSERT_STEPTHROUGH; + + // + // Get a typed pointer. This allows us to avoid + // casting every time we access the pointer. + // + SubAlloc = SubAllocation; + + ASSERT_SUBALLOC(SubAlloc); + + // + // Round size and make into number of blocks + // + AllocateSize = ALLOC_ROUND(Size); + + // + // Find a chunk that is free + // + // We need this loop in spite of the fact that we + // are keeping an index to the first free block. + // We update this pointer somewhat heuristically. + // If we allocate the first free block, we update + // the index to point past the block we allocated. + // We don't repeat the free scan however, so the + // index may actually point to an allocated block. + // + CurrentChunk = SubAlloc->FirstFree; + while (CurrentChunk < SubAlloc->Size) { + if (GET_BIT_FROM_CHAR_ARRAY(SubAlloc->Allocated, CurrentChunk) == 0) { + SubAlloc->FirstFree = CurrentChunk; + break; + } + CurrentChunk++; + } + + // + // Find a block that is big enough + // + while (!Done && (CurrentChunk < SubAlloc->Size)){ + + // + // Search for a contiguous block large enough + // + for (i = 0; i < AllocateSize; i++){ + // + // Insure we don't walk off the end of the data structure + // + if ((i + CurrentChunk) >= SubAlloc->Size){ + CurrentChunk += i; // Satisfy termination condition + break; + } + + // + // Check to see if this chunk is free + // + if ( + GET_BIT_FROM_CHAR_ARRAY( + SubAlloc->Allocated, + i + CurrentChunk + ) + == 0 + ){ + continue; + } else { + // + // Chunk is not free, so advance the search + // + CurrentChunk += i + 1; + break; + } + } + + // + // Check to see if we found a chunk + // + if (i == AllocateSize) { + Done = TRUE; + } + } + + // + // If we found the chunk, commit it (if necessary) and mark it allocated + // + // N.B. It is important to commit it first, and mark it allocated last, + // because we use the allocated bits to determine if the chunk is + // committed. If all of the allocated bits are clear, the chunk + // is not commited yet. + // + if (Done) { + + // + // Allocate and commit the memory + // + Success = AllocateChunkAt( + SubAlloc, + AllocateSize, + CurrentChunk, + FALSE + ); + + if (!Success) { + return FALSE; + } + + *Address = BLOCK_INDEX_TO_ADDRESS(SubAlloc, CurrentChunk); + + ASSERT((SubAlloc->BaseAddress <= *Address) && + ((SubAlloc->BaseAddress + SubAlloc->Size * SUBALLOC_GRANULARITY) + > *Address)); +#if 0 + { + char Buffer[80]; + + sprintf(Buffer, "SAAllocate: Allocating at address %lx\n", *Address); + OutputDebugString(Buffer); + } +#endif + return TRUE; + + } else { + return FALSE; + } +} + +BOOL +SAFree( + PVOID SubAllocation, + ULONG Size, + ULONG Address + ) +/*++ + +Routine Description: + + This routine frees a sub-allocated chunk of memory. If the + entire commited block (or blocks) that the specified chunk + belongs to are free, the chunks are decommitted. Address is + rounded down to the next lower SUBALLOC_GRANULARITY boundary. + size is rounded up to the next higher multiple of SUBALLOC_GRANULARITY. + +Arguments: + + SubAllocation -- Supplies the pointer returned by SAInitialize. + Size -- Supplies the size in bytes of the region to free. + Address -- Supplies the address of the region to free. + +Return Value: + + TRUE if successful. + +Notes: + + It is possible to free a different size at a particular + address than was allocated. This will not cause the + SubAllocation package any problems. + + BUGBUG decommit error handling? +--*/ +{ + PSUBALLOCATIONDATA SubAlloc; + ULONG AllocatedSize, BaseBlock; + + SubAlloc = SubAllocation; + ASSERT_SUBALLOC(SubAlloc); + + // + // Make sure that the space to free is really ours + // (Entire block within range, and correctly aligned) + if ( + (Address < SubAlloc->BaseAddress) || + (Address >= (SubAlloc->BaseAddress + SubAlloc->Size * SUBALLOC_GRANULARITY)) || + ((Address + Size) > (SubAlloc->BaseAddress + SubAlloc->Size * SUBALLOC_GRANULARITY)) || + (Address % SUBALLOC_GRANULARITY) + ) { + return FALSE; + } + + // + // Turn Address into Block # + // + BaseBlock = ADDRESS_TO_BLOCK_INDEX(SubAlloc, Address); + + // + // Round up the size + // + AllocatedSize = ALLOC_ROUND(Size); + + return FreeChunk( + SubAlloc, + AllocatedSize, + BaseBlock + ); +} + +BOOL +SAReallocate( + PVOID SubAllocation, + ULONG OriginalSize, + ULONG OriginalAddress, + ULONG NewSize, + PULONG NewAddress + ) +/*++ + +Routine Description: + + This routine reallocates a sub allocated block of memory. + The sizes are rounded up to the next SUBALLOC_GRANULARITY. + The Original address is rounded down to the next SUBALLOC_GRANULARITY + boundary. Only min(OriginalSize, NewSize) bytes of data are copied to + the new block. The block changed in place if possible. + + The following is an enumation of the possible successful reallocs. + + 1. NewSize < OriginalSize + free block tail + 2. NewSize > OriginalSize + a.) Sufficient freespace at OriginalAddress + OriginalSize + Allocate the space at the tail of the block + b.) Sufficient free space at OriginalAddress - size delta + Allocate the space at the beginning of the block, and + copy the data. + c.) Sufficient space elsewhere in the address space + Allocate the space, and copy the block. + + If none of the above is true, the realloc fails. The above are + in order of preference. + +Arguments: + + SubAllocation -- Supplies the pointer returned by SAInitialize. + OriginalSize -- Supplies the old size in bytes of the block. + OriginalAddress -- Supplies the old address of the block. + NewSize -- Supplies the new size in bytes of the block. + NewAddress -- Returns the new address of the block. + +Return Value: + + True if successful. If unsucessful, no allocation is changed. + +Notes: + + If the caller does not supply the correct original size for the block, + some memory may be lost, and the block may be moved unnecessarily. + +--*/ +{ + + ULONG OriginalSizeBlock, NewSizeBlock, OriginalIndex; + ULONG AdditionalBlocks, Address; + BOOL Success; + PSUBALLOCATIONDATA SubAlloc; + + SubAlloc = SubAllocation; + ASSERT_SUBALLOC(SubAlloc); + + // + // Convert Sizes and address to blocks + // + OriginalSizeBlock = ALLOC_ROUND(OriginalSize); + NewSizeBlock = ALLOC_ROUND(NewSize); + OriginalIndex = ADDRESS_TO_BLOCK_INDEX(SubAlloc, OriginalAddress); + + // + // Check to see if we are changing the size of the block + // + // N.B. Because we have rounded the numbers to an allocation + // boundary, the following test may succeed (correctly) + // even though OriginalSize != NewSize + // + if (OriginalSizeBlock == NewSizeBlock) { + *NewAddress = OriginalAddress; + return TRUE; + } + + // + // Check to see if the block is getting smaller + // + if (OriginalSizeBlock > NewSizeBlock) { + + // + // Free the tail of the block + // + Success = FreeChunk( + SubAlloc, + OriginalSizeBlock - NewSizeBlock, + OriginalIndex + NewSizeBlock + ); + + if (Success) { + *NewAddress = OriginalAddress; + return TRUE; + } else { + return FALSE; + } + } + + // + // Try to allocate the space at the end of the block + // + AdditionalBlocks = NewSizeBlock - OriginalSizeBlock; + + Success = AllocateChunkAt( + SubAlloc, + AdditionalBlocks, + OriginalIndex + OriginalSizeBlock, + TRUE + ); + + // + // If there was space, return success + // + if (Success) { + *NewAddress = OriginalAddress; + return TRUE; + } + + // + // Try to allocate space at the beginning of the block + // + Success = AllocateChunkAt( + SubAlloc, + AdditionalBlocks, + OriginalIndex - AdditionalBlocks, + TRUE + ); + + if (Success) { + // + // Move the data + // + // N.B. We can't just call RtlMoveMemory, + // because we don't know the correspondence + // between the address space we manage, and + // real linear addresses. In addition, for + // risc NTVDM, some additional work may have + // to be done (such as flushing caches). + // + SubAlloc->MoveMemRoutine( + BLOCK_INDEX_TO_ADDRESS( + SubAlloc, + (OriginalIndex - AdditionalBlocks) + ), + OriginalAddress, + OriginalSize + ); + + *NewAddress = BLOCK_INDEX_TO_ADDRESS( + SubAlloc, + (OriginalIndex - AdditionalBlocks) + ); + + return TRUE; + } + + // + // Attempt to allocate a new block + // + Success = SAAllocate( + SubAlloc, + NewSize, + &Address + ); + + if (Success) { + // + // Move the data + // + // N.B. We could copy the data, but it would + // require one more function pointer. + // + SubAlloc->MoveMemRoutine( + Address, + OriginalAddress, + OriginalSize + ); + + SAFree( + SubAlloc, + OriginalSize, + OriginalAddress + ); + + // + // Indicate success + // + *NewAddress = Address; + return TRUE; + } + + // + // All reallocation strategies failed. + // + return FALSE; +} + +BOOL +AllocateChunkAt( + PSUBALLOCATIONDATA SubAlloc, + ULONG Size, + ULONG BlockIndex, + BOOLEAN CheckFree + ) +/*++ + +Routine Description: + + This routine attempts to allocate the specified chunk + of memory. It first checks to make sure that it is + free. + +Arguments: + + SubAlloc -- Supplies a pointer to the suballocation data + Size -- Supplies the size of the chunk to allocate + BlockIndex -- Supplies the index of the beginning of the block + to allocate + CheckFree -- Supplies an indication of whether to check and see + if the memory is free. If this routine is called from + SAAllocate, we know the memory is free. + +Return Value: + + True if successful + +--*/ +{ + ULONG i; + + if (CheckFree) { + // + // Verify that the memory is free + // + for (i = 0; i < Size; i++){ + // + // Insure we don't walk off the end of the data structure + // + if ((i + BlockIndex) >= SubAlloc->Size){ + break; + } + + // + // Check to see if this chunk is free + // + if ( + GET_BIT_FROM_CHAR_ARRAY( + SubAlloc->Allocated, + i + BlockIndex + ) + == 0 + ){ + continue; + } else { + // + // Chunk is not free + // + break; + } + } + + // + // If the chunk is not free + // + if (i != Size) { + return FALSE; + } + } + + // + // Commit the chunk + // + if (!CommitChunk(SubAlloc, BlockIndex, Size, SACommit)) { + return FALSE; + } + + // + // Mark it as allocated + // + for (i = BlockIndex; i < BlockIndex + Size; i++) { + SET_BIT_IN_CHAR_ARRAY(SubAlloc->Allocated, i); + } + + // + // Update the pointer to the first free block + // + if (BlockIndex == SubAlloc->FirstFree) { + SubAlloc->FirstFree += Size; + } + + return TRUE; +} + + +BOOL +FreeChunk( + PSUBALLOCATIONDATA SubAlloc, + ULONG Size, + ULONG BlockIndex + ) +/*++ + +Routine Description: + + This routine actually marks the memory as free + and decommits it as necessary. + +Arguments: + + SubAlloc -- Supplies a pointer to the suballocation data + Size -- Supplies the size (in SUBALLOC_GRANULARITY) of the + region to free + BlockIndex -- Supplies the index of the begining of the region + (in SUBALLOC_GRANULARITY) + +Return Value: + + TRUE if successful. + +--*/ +{ + SUBALLOCATIONDATA LocalSubAlloc; + ULONG CurrentBlock; + BOOL Success; + + // + // Save a copy of the suballoc data + // + LocalSubAlloc = *SubAlloc; + + // + // reset free pointer + // + if (BlockIndex < SubAlloc->FirstFree) { + SubAlloc->FirstFree = BlockIndex; + } + // + // Mark the region as free + // + // N.B. We mark the block as free before decommitting it, because + // the decommit code will use the allocated bits to determine which + // parts can be decommitted. + // + for (CurrentBlock = BlockIndex; + CurrentBlock < BlockIndex + Size; + CurrentBlock++ + ) { + CLEAR_BIT_IN_CHAR_ARRAY(SubAlloc->Allocated, CurrentBlock); + } + + // + // Decommit the memory + // + Success = CommitChunk(SubAlloc, BlockIndex, Size, SADecommit); + + if (!Success) { + *SubAlloc = LocalSubAlloc; + } + + return Success; +} + +BOOL +CommitChunk( + PSUBALLOCATIONDATA SubAlloc, + ULONG StartChunk, + ULONG Size, + COMMIT_ACTION Action + ) +/*++ + +Routine Description: + + This routine commits a chunk of memory. Part or all + of the specified chunk may already be commited. + +Arguments: + + SubAllocation -- Supplies a pointer to the suballocation data + StartChunk -- Supplies the relative start of the region to be + committed (in SUBALLOCATION_GRANULARITY) + Size -- Supplies the size of the chunk to be commited + (in SUBALLOCATION_GRANULARITY) + +Return Value: + + TRUE -- If the block was successfully committed (or already committed) + FALSE -- Otherwise + +Notes: + + This routine depends on the allocated bits in SubAlloc to determine + whether memory is committed. When memory is to be committed, CommitBlock + must be called before the Allocated bits are modified. When memory is + decommitted, the Allocated bits must be modified before CommitBlock is + called. + +--*/ +{ + ULONG FirstBlock, LastBlock, CurrentBlock; + NTSTATUS Status; + + ASSERT_STEPTHROUGH; + + ASSERT_SUBALLOC(SubAlloc); + + // + // Round Start down to next COMMIT_GRANULARITY and convert to block # + // + FirstBlock = (StartChunk * SUBALLOC_GRANULARITY) / COMMIT_GRANULARITY; + + // + // Round StartChunk + size up to next COMMIT_GRANULARITY + // + LastBlock = ((StartChunk + Size) * SUBALLOC_GRANULARITY + + (COMMIT_GRANULARITY - 1)) / COMMIT_GRANULARITY; + + for ( + CurrentBlock = FirstBlock; + CurrentBlock < LastBlock; + CurrentBlock++ + ) { + + // + // If the block is not committed, either commit it or decommit it, + // depending on the value of Action. + // + if (!IsBlockCommitted(SubAlloc, CurrentBlock)) { + if (Action == SACommit) { + + Status = (SubAlloc->CommitRoutine)( + CurrentBlock * COMMIT_GRANULARITY + SubAlloc->BaseAddress, + COMMIT_GRANULARITY + ); + + } else if (Action == SADecommit) { + + Status = (SubAlloc->DecommitRoutine)( + CurrentBlock * COMMIT_GRANULARITY + SubAlloc->BaseAddress, + COMMIT_GRANULARITY + ); + + } + if (Status != STATUS_SUCCESS) { + // + // Bugbug -- decommit any blocks committed here + // + return FALSE; + } + } + } + return TRUE; +} + +BOOL +IsBlockCommitted( + PSUBALLOCATIONDATA SubAlloc, + ULONG Block + ) +/*++ + +Routine Description: + + This routine checks to see if a particular block of the + suballocation is committed. + +Arguments: + + SubAlloc -- Supplies a pointer to the suballocation data + Block -- Supplies the number of the block to check + +Return Value: + + TRUE -- if the block is committed + FALSE -- if the block is not committed + +Notes: + + The return value is based on the state of the bits in the + suballocation data, not on information from the NT memory + manager. + +--*/ +{ + BOOL Committed = FALSE; + ULONG i; + + ASSERT_STEPTHROUGH; + ASSERT_SUBALLOC(SubAlloc); + + // + // Check the bits for each of the suballoc blocks in the + // commit block + // + for (i = 0; i < COMMIT_GRANULARITY / SUBALLOC_GRANULARITY; i++) { + + // + // Check to see if this suballoc block is allocated + // + if ( + GET_BIT_FROM_CHAR_ARRAY( + SubAlloc->Allocated, + i + Block * COMMIT_GRANULARITY / SUBALLOC_GRANULARITY + ) + ) { + Committed = TRUE; + break; + } + } + + return Committed; +} + diff --git a/private/mvdm/suballoc/suballoc.txt b/private/mvdm/suballoc/suballoc.txt new file mode 100644 index 000000000..03dfc9813 --- /dev/null +++ b/private/mvdm/suballoc/suballoc.txt @@ -0,0 +1,276 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + suballoc.c + +Abstract: + + This module contains code for managing a paritially commited address + space. It handles allocation of chunks of memory smaller than the + commit granularity. It commits and decommits memory as needed using + the supplied function for committing and decommitting memory. The + structures used for tracking the address space are allocated outside + of the specified addresss space. + +Author: + + Dave Hastings (daveh) creation-date 21-Jan-1994 + +Notes: + + Since this package does not actually access memory in the address space + it is managing, it will work as well with real linear addresses or + "Intel Addresses" such as would be encountered with the Insignia Emulator + on risc. + +Revision History: + + +--*/ + +// +// Constants +// + +// +// Smallest chunk that will be sub allocated +// 1024 was chosen currently, because that is the +// smallest chunk XMS will allocate. +// +#define SUBALLOC_GRANULARITY 1024 + +// +// The size of the character array require to hold the +// bits defining whether the individual allocation entities +// in the commited chunk are allocated or free +// +// BUGBUG Assert that COMMIT_GRANULARITY is a multiple of SUBALLOC_GRANULARITY +// +#define SUBALLOC_BITFIELD_SIZE COMMIT_GRANULARITY / SUBALLOC_GRANULARITY + +// +// Types +// + +// +// Routine for committing a specific region of of the address +// space. Although the return type is NTSTATUS, the only value +// that is checked is 0 (for STATUS_SUCCESS). If STATUS_SUCCESS +// is returned, it is assumed that the function worked. If not, +// it is assumed that it failed. No special meaning is attached to +// particular non-zero values. +// +typedef +NTSTATUS +(*PSACOMMITROUTINE)( + ULONG BaseAddress, + ULONG Size + ); + +// +// Structure for tracking the address space. Each chunk of +// memory of SUBALLOC_GRANULARITY in size is represented by +// a bit. Each chunk of memory of COMMIT_GRANULARITY is +// represented by one element of the array of bitfields. +// The FreeCheck array half of the union allows us to check +// whether the entire committed chunk is free more quickly. +// +// ?? Should we add a field to indicate whether the chunk is +// committed? We can always check for all allocated bits +// zero, and use that as an indication that the chunk is +// not committed. +// +// BUGBUG Assert that the bits fit into memory the way we think +// they do. +// +typedef struct _SubAllocation { + PSACOMMITROUTINE CommitRoutine; + ULONG BaseAddress; + ULONG Size; + union { + // + // bitfield with one bit per chunk. Bit set indicates + // allocated. Bit clear indicates free. All bits + // clear indicates un committed + // + UINT Allocated[SUBALLOC_BITFIELD_SIZE] : 1; + // + // Hopefully a faster way to check all bits. + // + UINT FreeCheck[SUBALLOC_BITFIELD_SIZE / sizeof(UINT)]; + } CommitedChunk; +} SUBALLOCATIONDATA, *PSUBALLOCATIONDATA + + +PVOID +SAInitialize( + ULONG BaseAddress, + ULONG Size, + PSACOMMITROUTINE CommitRoutine + ) +/*++ + +Routine Description: + + This function performs initialization of the sub allocation package + for the specified addresss range. It allocates the data structures + necessary to track the allocations + +Arguments: + + BaseAddress -- Supplies the base address of the address space to + sub allocate. + Size -- Supplies the size in bytes of the address space to sub allocate. + CommitRoutine -- Supplies a pointer to the routine used to commit regions + of the address space. + +Return Value: + + If the function was successful it returns a pointer to the sub-allocation + data structures. Otherwise it returns NULL. + +--*/ +{ + +} + +BOOL +SAQueryFree( + PVOID SubAllocation, + PULONG FreeBytes + ) +/*++ + +Routine Description: + + This routine returns the number of free bytes in the + sub allocated address space. + +Arguments: + + SubAllocation -- Supplies the pointer returned by SAInitialize + FreeBytes -- Returns the number of free bytes + +Return Value: + + TRUE -- if successful, and FreeBytes contains the number of free bytes. + FALSE otherwise + +--*/ +{ + +} + +BOOL +SAAllocate( + PVOID SubAllocation, + ULONG Size, + PULONG Address + ) +/*++ + +Routine Description: + + This function allocates a portion of the address space described by + SubAllocation. If necessary, it will commit additional blocks. Address is + rounded down to the next lower SUBALLOC_GRANULARITY boundary. + size is rounded up to the next higher multiple of SUBALLOC_GRANULARITY. + +Arguments: + + SubAllocation -- Supplies the pointer returned by SAInitialize. + Size -- Supplies the size in bytes of the region to allocate. + Address -- Returns the address of the region allocated. + +Return Value: + + TRUE if successful. If false is returned, no address is returned. + +Notes: + + Zero is a valid value for the returned address. + +--*/ +{ + +} + +BOOL +SAFree( + PVOID SubAllocation, + ULONG Size, + ULONG Address + ) +/*++ + +Routine Description: + + This routine frees a sub-allocated chunk of memory. If the + entire commited block (or blocks) that the specified chunk + belongs to are free, the chunks are decommitted. Address is + rounded down to the next lower SUBALLOC_GRANULARITY boundary. + size is rounded up to the next higher multiple of SUBALLOC_GRANULARITY. + +Arguments: + + SubAllocation -- Supplies the pointer returned by SAInitialize. + Size -- Supplies the size in bytes of the region to free. + Address -- Supplies the address of the region to free. + +Return Value: + + TRUE if successful. + +Notes: + + It is possible to free a different size at a particular + address than was allocated. This will not cause the + SubAllocation package any problems. + +--*/ +{ + +} + +BOOL +SAReallocate( + PVOID SubAllocation, + ULONG OriginalSize, + ULONG OriginalAddress, + ULONG NewSize, + PULONG NewAddress + ) +/*++ + +Routine Description: + + This routine reallocates a sub allocated block of memory. + The sizes are rounded up to the next SUBALLOC_GRANULARITY. + The Original address is rounded down to the next SUBALLOC_GRANULARITY + boundary. Only min(OriginalSize, NewSize) bytes of data are copied to + the new block. The block changed in place if possible. + +Arguments: + + SubAllocation -- Supplies the pointer returned by SAInitialize. + OriginalSize -- Supplies the old size in bytes of the block. + OriginalAddress -- Supplies the old address of the block. + NewSize -- Supplies the new size in bytes of the block. + NewAddress -- Returns the new address of the block. + +Return Value: + + True if successful. If unsucessful, no allocation is changed. + +Notes: + + If the caller does not supply the correct original size for the block, + some memory may be lost, and the block may be moved unnecessarily. + +--*/ +{ + +} diff --git a/private/mvdm/suballoc/tsa.c b/private/mvdm/suballoc/tsa.c new file mode 100644 index 000000000..8e0cbe79b --- /dev/null +++ b/private/mvdm/suballoc/tsa.c @@ -0,0 +1,879 @@ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <windows.h> +#include <malloc.h> +#include <stdio.h> +#include <suballoc.h> + +typedef struct _MemTrack *PMEMTRACK; + +typedef struct _MemTrack { + PMEMTRACK Next; + ULONG Address; + ULONG Size; +} MEMTRACK; + +VOID +SimpleTest1( + PVOID SA + ); + +VOID +SimpleTest2( + PVOID SA + ); + +VOID +SimpleTest3( + PVOID SA + ); + +VOID +SimpleTest4( + PVOID + ); + +VOID +SimpleTest5( + PVOID + ); + +VOID +SimpleTest6( + PVOID + ); + +NTSTATUS +DecommitMem( + ULONG BaseAddress, + ULONG Size + ); + +NTSTATUS +CommitMem( + ULONG BaseAddress, + ULONG Size + ); + +VOID +MoveMem( + ULONG Destination, + ULONG Source, + ULONG Size + ); + +main(argv, argc) +char **argv; +int argc; +{ + NTSTATUS Status; + PVOID BaseAddress, SA; + ULONG Size; + ULONG TotalFree, LargestFree; + ULONG i,j; + BOOL Success; + + // + // Allocate a region of memory for SA to manage + // + BaseAddress = NULL; + Size = 15*1024*1024 - 64 * 1024; + Status = NtAllocateVirtualMemory( + NtCurrentProcess(), + &BaseAddress, + 0, + &Size, + MEM_RESERVE, + PAGE_READWRITE + ); + + if (!NT_SUCCESS(Status)) { + printf("Couldn't allocate memory, %lx\n", Status); + return(0); + } + + // + // Initialize the suballocation stuff + // + SA = SAInitialize( + (ULONG)BaseAddress, + Size, + CommitMem, + DecommitMem, + MoveMem + ); + if (SA == NULL) { + printf("SAInitialize Failed\n"); + } + + // + // Find out how much free memory we have + // + Success = SAQueryFree( + SA, + &TotalFree, + &LargestFree + ); + + if (!Success) { + printf("Could not query free\n"); + return; + } + // + // Run some tests + // + SimpleTest1(SA); + + // + // Allocate blocks spanning two commit blocks + // + SimpleTest2(SA); + + // + // Allocate and free all of memory (twice) + // + SimpleTest3(SA); + + // + // More complex alloc and free test + // + SimpleTest4(SA); + + // + // Test realloc + // + SimpleTest5(SA); + + // + // Test Queryfree + // + SimpleTest6(SA); + + // + // Make sure we didn't leak + // + Success = SAQueryFree( + SA, + &i, + &j + ); + + if (!Success){ + printf("Couldn't requery free\n"); + return; + } + + if ((i != TotalFree) || (j != LargestFree)) { + printf("We leaked\n"); + } +} + +VOID +SimpleTest1( + PVOID SA + ) +{ + ULONG Address; + BOOL Success; + + Success = SAAllocate( + SA, + 50, + &Address + ); + + if (!Success) { + printf("SimpleTest1: Failed to allocate\n"); + return; + } + + try { + *((PULONG)(Address + 4)) = 1; + } except (EXCEPTION_EXECUTE_HANDLER) { + printf("SimpleTest1: Faulted accessing memory\n"); + return; + } + + Success = SAFree( + SA, + 50, + Address + ); + + if (!Success) { + printf("SimpleTest1: Failed to free\n"); + return; + } + + Success = TRUE; + + try { + *((PULONG)Address + 4) = 1; + } except (EXCEPTION_EXECUTE_HANDLER) { + Success = FALSE; + } + + if (Success) { + printf("SimpleTest1: memory not decommited\n"); + } +} + +VOID +SimpleTest2( + PVOID SA + ) +{ + ULONG SmallAddress, LargeAddress; + BOOL Success; + + Success = SAAllocate( + SA, + 50, + &SmallAddress + ); + + if (!Success) { + printf("SimpleTest2: Could not alloc small block\n"); + return; + } + + try { + *((PULONG)(SmallAddress + 4)) = 1; + } except (EXCEPTION_EXECUTE_HANDLER) { + printf("SimpleTest2: small block not committed\n"); + return; + } + + Success = SAAllocate( + SA, + COMMIT_GRANULARITY + 50, + &LargeAddress + ); + + if (!Success) { + printf("SimpleTest2: Could not alloc large block\n"); + return; + } + + try { + *((PULONG)(LargeAddress + 4)) = 1; + *((PULONG)(LargeAddress + COMMIT_GRANULARITY)) = 1; + } except (EXCEPTION_EXECUTE_HANDLER) { + printf("SimpleTest2: Large block not committed\n"); + return; + } + + Success = SAFree( + SA, + 50, + SmallAddress + ); + + if (!Success) { + printf("SimpleTest2: failed to free small block\n"); + return; + } + + try { + *((PULONG)(LargeAddress + 4)) = 1; + } except (EXCEPTION_EXECUTE_HANDLER) { + printf("SimpleTest2: LargeBlock decommited!!\n"); + return; + } + + Success = SAFree( + SA, + COMMIT_GRANULARITY + 50, + LargeAddress + ); + + if (!Success) { + printf("SimpleTest2: failed to free Large block\n"); + return; + } + + Success = FALSE; + try { + *((PULONG)(LargeAddress + 4)) = 1; + } except (EXCEPTION_EXECUTE_HANDLER) { + Success = TRUE; + } + + if (!Success) { + printf("SimpleTest2: First block not decommited\n"); + } + + Success = FALSE; + try { + *((PULONG)(LargeAddress + COMMIT_GRANULARITY + 4)) = 1; + } except (EXCEPTION_EXECUTE_HANDLER) { + Success = TRUE; + } + + if (!Success) { + printf("SimpleTest2: Last block not decommited\n"); + } + +} + +VOID +SimpleTest3( + PVOID SA + ) +{ + ULONG BlockCount, i, Address; + PMEMTRACK p, Head, f; + BOOL Success; + + Head = NULL; + BlockCount = 0; + do { + + Success = SAAllocate( + SA, + 3072, + &Address + ); + + if (Success) { + p = malloc(sizeof(MEMTRACK)); + if (p == NULL) { + printf("SimpleTest3: malloc error\n"); + return; + } + p->Next = Head; + p->Size = 3072; + p->Address = Address; + Head = p; + BlockCount++; + } + } while (Success); + + try { + p = Head; + while (p != NULL) { + *((PULONG)(p->Address + 100)) = 1; + p = p->Next; + } + } except (EXCEPTION_EXECUTE_HANDLER) { + printf("SimpleTest3: failed first access test\n"); + return; + } + + p = Head; + while (p != NULL) { + + Success = SAFree( + SA, + 3072, + p->Address + ); + + if (!Success) { + printf("SimpleTest3: Failed first free test\n"); + return; + } + f = p; + p = p->Next; + free(f); + } + + Head = NULL; + + for (i = 0; i < BlockCount; i++) { + + Success = SAAllocate( + SA, + 3072, + &Address + ); + + if (!Success) { + printf("SimpleTest3: Failed second alloc test\n"); + return; + } + + p = malloc(sizeof(MEMTRACK)); + if (p == NULL) { + printf("SimpleTest3: malloc error\n"); + return; + } + + p->Next = Head; + p->Size = 3072; + p->Address = Address; + Head = p; + } + + try { + p = Head; + while (p != NULL) { + *((PULONG)(p->Address + 100)) = 1; + p = p->Next; + } + } except (EXCEPTION_EXECUTE_HANDLER) { + printf("SimpleTest3: failed second access test\n"); + return; + } + + p = Head; + while (p != NULL) { + + Success = SAFree( + SA, + 3072, + p->Address + ); + + if (!Success) { + printf("SimpleTest3: Failed second free test\n"); + return; + } + f = p; + p = p->Next; + free(f); + } +} + +VOID +SimpleTest4( + PVOID SA + ) +{ + ULONG i, Address; + PMEMTRACK p, Head, f; + BOOL Success; + + Head = NULL; + do { + + Success = SAAllocate( + SA, + 3072, + &Address + ); + + if (Success) { + p = malloc(sizeof(MEMTRACK)); + if (p == NULL) { + printf("SimpleTest4: malloc error\n"); + return; + } + p->Next = Head; + p->Size = 3072; + p->Address = Address; + Head = p; + } + } while (Success); + + p = Head; + p = p->Next; + p = p->Next; + + Success = SAFree( + SA, + 3072, + p->Next->Address + ); + + if (!Success) { + printf("SimpleTest4: could not free\n"); + return; + } + + f = p->Next; + p->Next = p->Next->Next; + free (f); + + p = p->Next; + p = p->Next; + + Success = SAFree( + SA, + 3072, + p->Next->Address + ); + + if (!Success) { + printf("SimpleTest4: could not free\n"); + return; + } + + f = p->Next; + p->Next = p->Next->Next; + free (f); + + Success = SAFree( + SA, + 3072, + p->Next->Address + ); + if (!Success) { + printf("SimpleTest4: could not free\n"); + return; + } + + f = p->Next; + p->Next = p->Next->Next; + free (f); + + Success = SAAllocate( + SA, + 3072, + &Address + ); + + try { + *((PULONG)(Address + 4)) = 1; + } except (EXCEPTION_EXECUTE_HANDLER) { + printf("SimpleTest4: failed to access\n"); + return; + } + + if (!Success) { + printf("SimpleTest4: could not allocate\n"); + return; + } + + p = malloc(sizeof(MEMTRACK)); + if (!p) { + printf("SimpleTest4: could not malloc\n"); + return; + } + + p->Next = Head; + p->Size = 3072; + p->Address = Address; + Head = p; + + Success = SAAllocate( + SA, + 3072, + &Address + ); + + try { + *((PULONG)(Address + 4)) = 1; + } except (EXCEPTION_EXECUTE_HANDLER) { + printf("SimpleTest4: failed to access\n"); + return; + } + + if (!Success) { + printf("SimpleTest4: could not allocate\n"); + return; + } + + p = malloc(sizeof(MEMTRACK)); + if (!p) { + printf("SimpleTest4: could not malloc\n"); + return; + } + + p->Next = Head; + p->Size = 3072; + p->Address = Address; + Head = p; + + p = Head; + while (p != NULL) { + + Success = SAFree( + SA, + 3072, + p->Address + ); + + if (!Success) { + printf("SimpleTest3: Failed second free test\n"); + return; + } + f = p; + p = p->Next; + free(f); + } +} + +VOID +SimpleTest5( + PVOID SA + ) +{ + ULONG Address, NewAddress; + ULONG Address1, Address2, Address3; + ULONG Size1, Size2, Size3; + BOOL Success; + + Success = SAAllocate( + SA, + 3072, + &Address + ); + + if (!Success) { + printf("SimpleTest5: failed to allocate\n"); + return; + } + + Success = SAReallocate( + SA, + 3072, + Address, + 3000, + &NewAddress + ); + + if (!Success) { + printf("SimpleTest5: failed to reallocate\n"); + return; + } + + if (NewAddress != Address) { + printf("SimpleTest5: Realloc in place failed\n"); + } + + Success = SAReallocate( + SA, + 3072, + Address, + 200, + &NewAddress + ); + + if (!Success) { + printf("SimpleTest5: failed to reallocate\n"); + return; + } + + if (NewAddress != Address) { + printf("SimpleTest5: Realloc in place failed\n"); + return; + } + + Success = SAReallocate( + SA, + 200, + Address, + 6000, + &NewAddress + ); + + if (!Success) { + printf("SimpleTest5: failed to reallocate\n"); + return; + } + + if (NewAddress != Address) { + printf("SimpleTest5: realloc in place failed\n"); + return; + } + + Success = SAAllocate( + SA, + 1500, + &Address + ); + + if (!Success) { + printf("SimpleTest5: failed to allocate\n"); + return; + } + + Address1 = NewAddress; + Size1 = 6000; + Address2 = Address; + Size2 = 1500; + + Success = SAReallocate( + SA, + Size1, + Address1, + 3000, + &NewAddress + ); + + if (!Success) { + printf("SimpleTest5: failed to reallocate\n"); + return; + } + + if (Address1 != NewAddress) { + printf("SimpleTest5: realloc in place failed\n"); + return; + } + Size1= 3000; + + Success = SAAllocate( + SA, + 2000, + &Address + ); + + if (!Success) { + printf("SimpleTest5: failed to allocate\n"); + return; + } + + Address3 = Address; + Size3 = 2000; + + Success = SAFree( + SA, + Size1, + Address1 + ); + + if (!Success) { + printf("SimpleTest5: failed to free\n"); + return; + } + + Success = SAReallocate( + SA, + Size3, + Address3, + 5000, + &Address + ); + + if (!Success) { + printf("SimpleTest5: failed to reallocate\n"); + return; + } + + Address3 = Address; + Size3 = 5000; + + Success = SAReallocate( + SA, + Size3, + Address3, + 10000, + &Address + ); + + if (!Success) { + printf("SimpleTest5: failed to reallocate\n"); + return; + } + Address3 = Address; + Size3 = 10000; + + Success = SAFree( + SA, + Size2, + Address2 + ); + + if (!Success) { + printf("SimpleTest5: failed to free\n"); + return; + } + + Success = SAFree( + SA, + Size3, + Address3 + ); + + if (!Success) { + printf("SimpleTest5: failed to free\n"); + return; + } +} + +VOID +SimpleTest6( + PVOID SA + ) +{ + ULONG LargestFree, TotalFree; + BOOL Success; + + Success = SAQueryFree( + SA, + &TotalFree, + &LargestFree + ); + +} + + +NTSTATUS +CommitMem( + ULONG BaseAddress, + ULONG Size + ) +{ + NTSTATUS Status; + PVOID Address; + ULONG size; + + Address = (PVOID)BaseAddress; + size = Size; + Status = NtAllocateVirtualMemory( + NtCurrentProcess(), + &Address, + 0L, + &size, + MEM_COMMIT, + PAGE_READWRITE + ); + + if (!NT_SUCCESS(Status)) { + printf( + "CommitMem failed to commit %lx, %lx, error %lx\n", + Address, + size, + Status + ); + } + + return Status; +} + +NTSTATUS +DecommitMem( + ULONG BaseAddress, + ULONG Size + ) +{ + NTSTATUS Status; + PVOID Address; + ULONG size; + + Address = (PVOID)BaseAddress; + size = Size; + Status = NtFreeVirtualMemory( + NtCurrentProcess(), + &Address, + &size, + MEM_DECOMMIT + ); + + if (!NT_SUCCESS(Status)) { + printf( + "DecommitMem failed to decommit %lx, %lx, error %lx\n", + Address, + size, + Status + ); + } + + return Status; +} + +VOID +MoveMem( + ULONG Destination, + ULONG Source, + ULONG Size + ) +{ + RtlMoveMemory( + (PVOID)Destination, + (PVOID)Source, + Size + ); +} |