mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-02 23:43:40 +02:00
274 lines
7.4 KiB
ObjectPascal
274 lines
7.4 KiB
ObjectPascal
(*******************************************************************
|
|
*
|
|
* TTMemory.Pas 2.1
|
|
*
|
|
* Memory management component (specification)
|
|
*
|
|
* Copyright 1996 David Turner, Robert Wilhelm and Werner Lemberg
|
|
*
|
|
* This file is part of the FreeType project, and may only be used
|
|
* modified and distributed under the terms of the FreeType project
|
|
* license, LICENSE.TXT. By continuing to use, modify or distribute
|
|
* this file you indicate that you have read the license and
|
|
* understand and accept it fully.
|
|
*
|
|
* Differences between 2.1 and 2.0 :
|
|
*
|
|
* - Added a memory mutex to make the component thread-safe
|
|
*
|
|
* Differences between 2.0 and 1.1 :
|
|
*
|
|
* - The growing heap was completely removed in version 2.0
|
|
*
|
|
* - The support for small mini-heaps may be re-introduced later
|
|
* to allow the storage of several consecutive arrays in one
|
|
* single block.
|
|
*
|
|
* IMPORTANT NOTICE :
|
|
*
|
|
* The Alloc and Free functions mimic their C equivalent,
|
|
* however, some points must be noticed :
|
|
*
|
|
* - both functions return a boolean. As usual, True indicates
|
|
* success, while False indicates failure.
|
|
*
|
|
* - the Alloc function puts a small header on front of each
|
|
* allocated block. The header contains a magic cookie and
|
|
* the size of the allocated block. This allows calls to
|
|
* Free without passing a block size as an argument, and thus
|
|
* reduces the risks of memory leaks.
|
|
*
|
|
* - it is possible to call Free with a nil pointer, in which
|
|
* case nothing happens, and the result is set to True (success)
|
|
*
|
|
* The pointer is set to nil after a call to Free in all cases.
|
|
*
|
|
* This is done to clear the destructors code, allowing
|
|
*
|
|
* if (pointer) then
|
|
* begin
|
|
* Free(pointer);
|
|
* pointer := nil;
|
|
* end;
|
|
*
|
|
* to be replaced by a single line :
|
|
*
|
|
* Free(pointer);
|
|
*
|
|
*
|
|
******************************************************************)
|
|
|
|
unit TTMemory;
|
|
|
|
interface
|
|
|
|
uses TTTypes;
|
|
|
|
{$I TTCONFIG.INC}
|
|
{$R-}
|
|
|
|
type
|
|
TMarkRecord = record
|
|
Magic : longint;
|
|
Top : integer;
|
|
end;
|
|
|
|
const
|
|
Font_Pool_Allocated : boolean = False;
|
|
|
|
function Alloc( var P; size : Longint ) : TError;
|
|
(* Allocates a new memory block in the current heap of 'size' bytes *)
|
|
(* - returns failure if no memory is left in the heap *)
|
|
|
|
procedure Free ( var P );
|
|
(* Releases a block previously allocated through 'Alloc' *)
|
|
(* - returns True (success) of P is nil before the call *)
|
|
(* - sets P to nil before exit *)
|
|
|
|
function TTMemory_Init : TError;
|
|
procedure TTMemory_Done;
|
|
|
|
implementation
|
|
|
|
|
|
type
|
|
PBlock_Header = ^TBlock_Header;
|
|
TBlock_Header = record
|
|
magic : longword; (* magic cookie *)
|
|
size : Longint; (* allocated size, including header *)
|
|
end;
|
|
|
|
TBlock_Headers = array[0..1] of TBlock_Header;
|
|
PBlock_Headers = ^TBlock_Headers;
|
|
|
|
(* Note that the Turbo-Pascal GetMem/FreeMem functions use no block *)
|
|
(* headers. That's why a byte size is needed for FreeMem. Thus, we *)
|
|
(* do not waste space here compared to a C malloc implementation *)
|
|
|
|
const
|
|
Mark_Magic = $BABE0007;
|
|
(* This is the magic cookie used to recognize valide allocated blocks *)
|
|
|
|
Header_Size = sizeof(TBlock_Header);
|
|
|
|
(************************************************************************)
|
|
(* *)
|
|
(* MyHeapErr : *)
|
|
(* *)
|
|
(* By default, a call to GetMem with insufficient memory left will *)
|
|
(* generate a runtime error. We define here a function that is used *)
|
|
(* to allow GetMem to return nil in such cases. *)
|
|
(* *)
|
|
(************************************************************************)
|
|
|
|
function MyHeapErr( {%H-}Size: Integer ): Integer;
|
|
begin
|
|
MyHeapErr := 1;
|
|
end;
|
|
|
|
(*******************************************************************
|
|
*
|
|
* Function : Alloc
|
|
*
|
|
* Description : allocate a new block in the current heap
|
|
*
|
|
* Notes : If you want to replace this function with
|
|
* your own, please be sure to respect these
|
|
* simple rules :
|
|
*
|
|
* - P must be set to nil in case of failure
|
|
*
|
|
* - The allocated block must be zeroed !
|
|
*
|
|
*****************************************************************)
|
|
|
|
function Alloc( var P; size : Longint ) : TError;
|
|
var
|
|
L : Longint;
|
|
P2 : Pointer;
|
|
begin
|
|
// {$IFNDEF DELPHI32}
|
|
// OldHeapError := HeapError;
|
|
// HeapError := @MyHeapErr;
|
|
// {$ENDIF}
|
|
|
|
L := ( size + Header_Size + 3 ) and -4;
|
|
|
|
{$IFDEF MSDOS}
|
|
if L shr 16 <> 0 then
|
|
begin
|
|
Writeln('Sorry, but this font is too large to be handled by a 16-bit program' );
|
|
Alloc := Failure;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
GetMem( Pointer(P), L );
|
|
|
|
// {$IFNDEF DELPHI32}
|
|
// HeapError := OldHeapError;
|
|
// {$ENDIF}
|
|
|
|
if Pointer(P) <> nil then
|
|
begin
|
|
PBlock_Headers(P)^[0].magic := Mark_Magic;
|
|
PBlock_Headers(P)^[0].size := L;
|
|
|
|
P2 := Pointer( @(PBlock_Headers(P)^[1]) );
|
|
|
|
{$IFDEF MSDOS}
|
|
if (ofs(P2^) <> ofs(Pointer(P)^)+Header_Size) or
|
|
(seg(P2^) <> seg(Pointer(P)^)) then
|
|
begin
|
|
Writeln('AAARGH !!: Sorry, but I have problems with 64 Kb segments');
|
|
halt(1);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
Pointer(P) := P2;
|
|
fillchar( P2^, size, 0 );
|
|
(* zero block *)
|
|
|
|
Alloc := Success;
|
|
end
|
|
else
|
|
Alloc := Failure;
|
|
|
|
end;
|
|
|
|
|
|
(*******************************************************************
|
|
*
|
|
* Function : Free
|
|
*
|
|
* Description : frees a block that was previsouly allocated
|
|
* by the Alloc function
|
|
*
|
|
* Notes : Doesn't need any size parameter.
|
|
*
|
|
* If you want to replace this function with your own, please
|
|
* be sure to respect these two rules :
|
|
*
|
|
* - the argument pointer can be nil, in which case the function
|
|
* should return immediately, with a success report.
|
|
*
|
|
* - the pointer P should be set to nil when exiting the
|
|
* function, except in case of failure.
|
|
*
|
|
*****************************************************************)
|
|
|
|
procedure Free( var P );
|
|
var
|
|
head : PBlock_Header;
|
|
size : Longint;
|
|
begin
|
|
if Pointer(P) = nil then exit;
|
|
|
|
head:=PBlock_Header(P);
|
|
dec(head);
|
|
|
|
if head^.magic <> Mark_Magic then
|
|
begin
|
|
(* PANIC : An invalid Free call *)
|
|
Writeln('Invalid Free call');
|
|
halt(1);
|
|
end;
|
|
|
|
size := head^.size;
|
|
|
|
head^.magic := 0; (* cleans the header *)
|
|
head^.size := 0;
|
|
|
|
FreeMem( head, size );
|
|
|
|
Pointer(P) := nil;
|
|
end;
|
|
|
|
(*******************************************************************
|
|
*
|
|
* Function : TTMemory_Init
|
|
*
|
|
* Description : Initializes the Memory component
|
|
*
|
|
*****************************************************************)
|
|
|
|
function TTMemory_Init : TError;
|
|
begin
|
|
(* nothing to be done *)
|
|
TTMemory_Init := Success;
|
|
end;
|
|
|
|
(*******************************************************************
|
|
*
|
|
* Function : TTMemory_Done
|
|
*
|
|
* Description : Finalize the memory component
|
|
*
|
|
*****************************************************************)
|
|
|
|
procedure TTMemory_Done;
|
|
begin
|
|
(* nothing to be done *)
|
|
end;
|
|
|
|
end.
|