/*++ 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. --*/ { }