{ Basic heap handling for windows platforms This file is part of the Free Pascal run time library. Copyright (c) 2001-2005 by Free Pascal development team See the file COPYING.FPC, included in this distribution, for details about the copyright. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************} {***************************************************************************** OS Memory allocation / deallocation ****************************************************************************} { In kernel mode we can either use FPC's build in memory manager or we use a custom non-chunking manager. The problem with the build in one is that the driver developer has far less control of the allocated memory blocks. } { memory functions } {$ifdef KMODE} function ExAllocatePoolWithTag(PoolType: LongInt; NumberOfBytes: PtrUInt; Tag: LongWord): Pointer; stdcall; external ntdll name 'ExAllocatePoolWithTag'; procedure ExFreePoolWithTag(P: Pointer; Tag: LongWord); stdcall; external ntdll name 'ExFreePoolWithTag'; {$else KMODE} function RtlAllocateHeap(hHeap : THandle; dwFlags : LongWord; Size : PtrUInt): Pointer; stdcall; external ntdll name 'RtlAllocateHeap'; function RtlFreeHeap(hHeap : THandle; dwFlags : LongWord; MemoryPointer : Pointer): Boolean; stdcall; external ntdll name 'RtlFreeHeap'; function RtlCreateHeap(Flags: LongWord; Base: Pointer; SizeToReserve: PtrUInt; SizeToCommit: PtrUInt; Lock: Pointer; Parameters: Pointer): THandle; stdcall; external ntdll name 'RtlCreateHeap'; var SysHeap: THandle = 0; procedure PrepareSysHeap; begin if IsLibrary then // create a new heap (flag is HEAP_GROWABLE) SysHeap := RtlCreateHeap(2, Nil, 65534, 65534, Nil, Nil) else // use the heap passed on startup SysHeap := THandle(PSimplePEB(CurrentPEB)^.ProcessHeap); end; {$endif KMODE} {$ifndef KMODE} // default memory manager function SysOSAlloc(size: ptruint): pointer; begin if SysHeap = 0 then PrepareSysHeap; SysOSAlloc := RtlAllocateHeap(SysHeap, 0, size); end; {$define HAS_SYSOSFREE} procedure SysOSFree(p: pointer; size: ptruint); begin // if heap isn't set, then nothing was allocated if SysHeap <> 0 then RtlFreeHeap(SysHeap, 0, p); end; {$else KMODE} // custom non-chunking memory manager for kernel mode // memory layout: // : Size of reserved chunk // : Tag that was used in ExAllocateFromPoolWithTag (needed in free) // <...>: Userdata function SysGetMem(Size: PtrUInt): Pointer; var tag: LongWord; pooltype: LongInt; begin if HeapUsePagedPool then pooltype := 1 else pooltype := 0; tag := Ord(HeapPoolTag[1]) + Ord(HeapPoolTag[2]) shl 8 + Ord(HeapPoolTag[3]) shl 16 + Ord(HeapPoolTag[4]) shl 24; // the kernel keeps track of our memory, but there's no way to ask it // so we need to track the size by ourself SysGetMem := ExAllocatePoolWithTag(pooltype, Size + SizeOf(PtrUInt) + SizeOf(LongWord), tag); // save the size PPtrUInt(SysGetMem)^ := Size; SysGetMem := SysGetMem + SizeOf(PtrUInt); // save the tag PLongWord(SysGetMem)^ := tag; SysGetMem := SysGetMem + SizeOf(LongWord); end; function SysFreeMem(p: Pointer): PtrUInt; var tag: PLongWord; begin tag := p - SizeOf(LongWord); // we need to pass the tag we used to allocate the memory (else: BSOD) ExFreePoolWithTag(p - SizeOf(PtrUInt) - SizeOf(LongWord), tag^); SysFreeMem := 0; end; function SysFreeMemSize(p: Pointer; Size: PtrUInt): PtrUInt; begin SysFreeMemSize := 0; if (Size > 0) and (p <> nil) then Result := SysFreeMem(p); end; Function SysAllocMem(Size: PtrUInt): Pointer; begin SysAllocMem := SysGetMem(Size); if SysAllocMem <> nil then FillChar(SysAllocMem^, Size, 0); end; Function SysReAllocMem (var p: pointer; Size: PtrUInt): Pointer; begin SysReAllocMem := SysGetMem(Size); Move(p^, SysReAllocMem^, Size); p := SysReAllocMem; end; function SysTryResizeMem(var p: Pointer; size: PtrUInt): Boolean; var res: pointer; begin res := SysGetMem(Size); SysTryResizeMem := (res <> Nil) or (Size = 0); if SysTryResizeMem then p := res; end; function SysMemSize(P : pointer): PtrUInt; begin SysMemSize := PPtrUInt(P - SizeOf(PtrUInt) - SizeOf(LongWord))^; end; function SysGetHeapStatus: THeapStatus; begin FillChar(SysGetHeapStatus, SizeOf(SysGetHeapStatus), 0); end; function SysGetFPCHeapStatus: TFPCHeapStatus; begin FillChar(SysGetFPCHeapStatus, SizeOf(SysGetHeapStatus), 0); end; {$endif KMODE}