Bugfix : Zooming works correct, no more errors on screen.
[xara-cairo.git] / wxOil / cammemory.cpp
blobfd79a95975def6e42b5722585fc3f95d54c9cf7f
1 // $Id: cammemory.cpp 1492 2006-07-20 19:19:48Z alex $
2 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
3 ================================XARAHEADERSTART===========================
5 Xara LX, a vector drawing and manipulation program.
6 Copyright (C) 1993-2006 Xara Group Ltd.
7 Copyright on certain contributions may be held in joint with their
8 respective authors. See AUTHORS file for details.
10 LICENSE TO USE AND MODIFY SOFTWARE
11 ----------------------------------
13 This file is part of Xara LX.
15 Xara LX is free software; you can redistribute it and/or modify it
16 under the terms of the GNU General Public License version 2 as published
17 by the Free Software Foundation.
19 Xara LX and its component source files are distributed in the hope
20 that it will be useful, but WITHOUT ANY WARRANTY; without even the
21 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22 See the GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License along
25 with Xara LX (see the file GPL in the root directory of the
26 distribution); if not, write to the Free Software Foundation, Inc., 51
27 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 ADDITIONAL RIGHTS
31 -----------------
33 Conditional upon your continuing compliance with the GNU General Public
34 License described above, Xara Group Ltd grants to you certain additional
35 rights.
37 The additional rights are to use, modify, and distribute the software
38 together with the wxWidgets library, the wxXtra library, and the "CDraw"
39 library and any other such library that any version of Xara LX relased
40 by Xara Group Ltd requires in order to compile and execute, including
41 the static linking of that library to XaraLX. In the case of the
42 "CDraw" library, you may satisfy obligation under the GNU General Public
43 License to provide source code by providing a binary copy of the library
44 concerned and a copy of the license accompanying it.
46 Nothing in this section restricts any of the rights you have under
47 the GNU General Public License.
50 SCOPE OF LICENSE
51 ----------------
53 This license applies to this program (XaraLX) and its constituent source
54 files only, and does not necessarily apply to other Xara products which may
55 in part share the same code base, and are subject to their own licensing
56 terms.
58 This license does not apply to files in the wxXtra directory, which
59 are built into a separate library, and are subject to the wxWindows
60 license contained within that directory in the file "WXXTRA-LICENSE".
62 This license does not apply to the binary libraries (if any) within
63 the "libs" directory, which are subject to a separate license contained
64 within that directory in the file "LIBS-LICENSE".
67 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
68 ----------------------------------------------
70 Subject to the terms of the GNU Public License (see above), you are
71 free to do whatever you like with your modifications. However, you may
72 (at your option) wish contribute them to Xara's source tree. You can
73 find details of how to do this at:
74 http://www.xaraxtreme.org/developers/
76 Prior to contributing your modifications, you will need to complete our
77 contributor agreement. This can be found at:
78 http://www.xaraxtreme.org/developers/contribute/
80 Please note that Xara will not accept modifications which modify any of
81 the text between the start and end of this header (marked
82 XARAHEADERSTART and XARAHEADEREND).
85 MARKS
86 -----
88 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
89 designs are registered or unregistered trademarks, design-marks, and/or
90 service marks of Xara Group Ltd. All rights in these marks are reserved.
93 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
94 http://www.xara.com/
96 =================================XARAHEADEREND============================
99 // This is the Camelot Dynamic Memory Manager
100 // This has been changed to use the normal Static heap now, as SmartHeap does a better job.
101 // If you want to get back to any of the source code that was here before, you will want to check
102 // out version 1.30 of this file. After that it is mostly missing.
105 #include "camtypes.h"
106 //#include "handles.h" - in camtypes.h [AUTOMATICALLY REMOVED]
107 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED]
108 //#include "cammemory.h" - in camtypes.h [AUTOMATICALLY REMOVED]
109 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
110 //#include "memblk.h" - in camtypes.h [AUTOMATICALLY REMOVED]
112 #if defined(__WXGTK__)
113 #include <stdio.h>
114 #endif
116 #ifdef RALPH
117 #include "ralphcri.h"
118 #endif
120 DECLARE_SOURCE("$Revision: 1492 $");
122 // Declare smart memory handling in Debug builds
123 #define new CAM_DEBUG_NEW
126 /********************************************************************************************
129 Technical Notes
130 ~~~~~~~~~~~~~~~
132 General
133 ~~~~~~~
135 At present, this module obtains a chunk of memory from Windows' Global heap,
136 and uses this to satisfy client memory requests. The handle to this memory is
137 resolved to a physical address, and the block is locked for the duration of the
138 memory manager's use (i.e. until DeinitMemory() is called, when it is unlocked and
139 returned to the global heap). The 'FreePoolPtr' variable points to the base of the
140 block. Under 16bit Windows, the block is limited to 64k in size.
142 The handles used are managed by another module - the handle manager (see
143 winoil\handles.{h,cpp}).
145 In order to cope with 'heavy' blocks (see ClaimBlock), two heaps are maintained.
146 One is for heavy blocks, the other for normal blocks. This is the ideal solution
147 under Windows, because we use a GlobalAlloc call for each, so when we need to add
148 a new heavy block, we don't need to move all the non-heavy objects to do so. The OS
149 will cope with it by remapping the memory controller - i.e. we don't move any
150 memory - this is *good*.
152 Allocated blocks of memory are not always contiguous; there may be holes (unused
153 blocks) in the heap.
155 The first word of a memory block contains its size in bytes, and a flag to indicate
156 whether or not it is a hole (i.e. not in use). Therefore it is possible to step
157 through the heap simply by reading the size of each block and using that to move on to
158 the next block. A size of 0 indicates that the block containing the free space at the
159 end of the heap has been reached. This block is also marked as _not_ being a
160 hole - this (somewhat counter-intuitively) makes certain operations on the heap
161 simpler.
163 The 'FreeOffset' variable is an offset to the start of any remaining memory in the 64k
164 block (hence it is 0 initially - all memory is available). This memory does not
165 include holes. When a request for memory fails, the holes are examined to see if one
166 of them can accomodate the request. If no holes are big enough, the manager
167 incrementally removes the holes until it can be satisfied, or until there are no more
168 holes to free. ("When Alexander saw the size of his allocation, he wept, for there
169 were no more holes to free...")
171 The memory manager uses the principle of lazy evaluation - expensive operations are
172 defered until they are absolutely necessary, or when the CPU would otherwise be idle.
173 This minimises response times for the user.
175 Holes
176 ~~~~~
178 Holes are intended to be transient - the idea is that when releasing a block it is
179 simply marked as released. Then, when the application receives idle events, it should
180 call TidyMemory(), which will move one block at a time to clean up the holes.
182 The upshot of all this is that when large allocations/deallocations are taking place,
183 the user doesn't notice much (if any) degradation in response time, because the memory
184 is not being moved. However, when the user next stops to think for a few seconds, the
185 application will be 'covertly' tidying up its memory holes while the CPU is idle. Only
186 one block is tidied at once so that control can be returned to the user quickly (when
187 they stop thinking and start clicking).
189 The function RemoveBlockGaps() is also provided to force all holes to be purged from
190 the heap (which may be desirable for events such as removing a document from memory,
191 and so on).
193 When a block is released by its owner, the associated handle is also freed. The list of
194 holes is maintained using the blocks themselves - as each block (either used or unused)
195 has its size contained in the first word of its memory, the blocks effectively form
196 a linked list which can be efficiently scanned for holes. Holes are not joined
197 together unless this is necessary (usually when the heap is being compacted).
199 When tidying the memory, it is guaranteed (by calling JoinHoles() before doing
200 anything else) that no two holes will be adjacent - any such holes will have been
201 joined into one. Therefore when a hole is found, a block that is in use will be
202 sitting above it in memory. These two blocks (the hole and the block in use) are
203 then swapped around, so that the hole is above the used block, and the used block now
204 starts where the hole used to. Any handles into the used block are updated using the
205 handle manager. There are, of course, no handles into the hole as it is not a valid
206 memory block anyway. The hole's first word is then set to contain its size, as before.
207 (NB only the contents of the block in use are moved - the hole's contents are not moved
208 because they are undefined anyway, so it would be unnecessary). Finally, if there is a
209 hole directly above this hole, the two are joined together.
212 For example:
213 ------------
214 Dynamic Heap (X = Block In Use, . = Hole)
216 +-------+------+------------+-------+------+-----------------+
217 Before tidying: |XXXXXXX|......|XXXXXXXXXXXX|.......|XXXXXX| Free Space |
218 +-------+------+------------+-------+------+-----------------+
221 +-------+------------+--------------+------+-----------------+
222 After tidying: |XXXXXXX|XXXXXXXXXXXX|..............|XXXXXX| Free Space |
223 +-------+------------+--------------+------+-----------------+
227 No special algorithms for reclaiming/joining blocks are required (as they would be
228 in a normal malloc-style heap), because all the blocks in the heap can be moved at
229 will.
230 Therefore optimising allocations for FIFO schemes, buddy schemes etc., is pointless.
231 Whenever the holes cause problems for allocation requests, they are gradually removed
232 to free up memory - this is not possible for a static heap manager!
235 Inter-block gaps
236 ~~~~~~~~~~~~~~~~
238 The 'EndOfBlockGap' is used to resolve the problem of not knowing whether an address
239 refers to the end of one block or the start of the next (according to Jim). Blocks
240 are simply separated by a 'dead zone' of 4 bytes.
242 Since the introduction of BlockHeader fields, I think this EndOfBlockGap can safely
243 be dropped...must try it sometime.
246 Resizing blocks
247 ~~~~~~~~~~~~~~~
249 Blocks can be either increased or decreased in size. There are two functions which
250 perform simple resizing of blocks: IncreaseBlock() and DecreaseBlock(). They simply
251 alter the size of the block's allocation, and do not move any memory.
252 Two other functions, InsertMemory() and RemoveMemory(), are provided for inserting
253 memory into the middle of a block, or removing it from the middle of a block.
255 Strategies used for resizing blocks
256 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
258 When making blocks smaller, the excess is simply made into a hole for removal later
261 When increasing the size of the block, if a large enough hole exists above the block
262 being resized, then it is used to expand the block into, and the hole is decreased
263 in size accordingly. Note that no other blocks are moved in this case.
265 (Future optimisation: at this point, the manager should try to find any hole big
266 enough to hold the block, and reposition the block into that).
268 If the hole isn't big enough to accommodate the request, then the manager compacts
269 the heap and tries again. If there is still not enough room, then the heap itself
270 is resized - if not enough memory is available, the request fails.
273 SplitBlock()
274 ~~~~~~~~~~~~
276 NB. SplitBlock() has been replaced by the other function calls listed above, and
277 should no longer be used. Please change any existing code that stil uses it. The
278 function will be removed in the future.
280 SplitBlock() resizes blocks of memory. It can make blocks bigger or smaller.
283 Releasing memory
284 ~~~~~~~~~~~~~~~~
286 At present, this module never returns memory to the OS until DeinitMemory() is called.
287 In future, TidyMemory should return memory once the free memory in the heap reaches
288 a certain threshold.
291 The Invaders - Epilogue
292 ~~~~~~~~~~~~~~~~~~~~~~~
294 The addition of holes complicates this module somewhat, but not unduly. The worst
295 affected functions are SplitBlock() and ClaimBlock(), which run rings around holes in
296 order to do their job. However, what they're trying to do is avoid redundant memory
297 transfers which can be VERY expensive, and hence the memory manager is faster at its
298 job, which is the point of the exercise (TANSTAAFL).
301 ********************************************************************************************/
303 class DynamicHeap : public CC_CLASS_MEMDUMP
305 CC_DECLARE_MEMDUMP(DynamicHeap)
307 public:
308 // Creation/initialisation/destruction
309 DynamicHeap();
310 BOOL Init();
311 ~DynamicHeap();
313 // Claiming and releasing memory
314 MHANDLE ClaimBlock(size_t Size);
315 BOOL ReleaseBlock(MHANDLE Handle);
317 // Resizing blocks
318 BOOL IncreaseBlock(MHANDLE Handle, UINT32 NumBytes);
319 BOOL DecreaseBlock(MHANDLE Handle, UINT32 NumBytes);
322 CC_IMPLEMENT_MEMDUMP(DynamicHeap, CCObject)
324 // Pointers to the heap objects.
325 static DynamicHeap *NormalHeap = NULL;
329 /********************************************************************************************
331 > DynamicHeap::DynamicHeap()
333 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
334 Created: 09/02/94
335 Purpose: Sets up the heap variables, ready for Init() to be called.
336 SeeAlso: DynamicHeap::Init; DynamicHeap::~DynamicHeap
338 ********************************************************************************************/
340 DynamicHeap::DynamicHeap()
344 /********************************************************************************************
346 > BOOL DynamicHeap::Init()
348 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
349 Created: 09/02/94
350 Returns: TRUE if the initialisation was successful, FALSE if not (e.g. couldn't
351 get any memory).
352 Purpose: Initialise the heap object. This gets a chunk of memory from the operating
353 system, which it will use to satsify allocation requests.
354 Errors: If unable to claim memory.
356 ********************************************************************************************/
358 BOOL DynamicHeap::Init()
360 // Everything went ok
361 return TRUE;
366 /********************************************************************************************
368 > DynamicHeap::~DynamicHeap()
370 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
371 Created: 09/02/94
372 Purpose: Deallocates any memory used by this heap object.
373 In debug builds it checks the heap for objects which have not been
374 deallocated, or for heap corruption, and complains if it finds any.
375 SeeAlso: DynamicHeap::Init; DynamicHeap::DynamicHeap; InitMemory; DeinitMemory
377 ********************************************************************************************/
379 DynamicHeap::~DynamicHeap()
385 /********************************************************************************************
387 > MHANDLE DynamicHeap::ClaimBlock(UINT32 Size)
389 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
390 Created: 26/04/93
391 Inputs: Size: The size in bytes of the block being requested
392 Returns: The handle that refers to the newly allocated block.
393 Purpose: Allocates a block of 'size' bytes from the free pool, and obtains a handle
394 for it. Blocks which are zero bytes long are permitted, but blocks must
395 be word-sized (i.e. a multiple of 4 bytes in size).
397 ********************************************************************************************/
399 MHANDLE DynamicHeap::ClaimBlock(size_t Size)
401 #ifdef RALPH
402 RalphCriticalSection RalphCS;
403 #endif
405 // Get the memory
406 ADDR pNewBlock = (ADDR) CCMalloc(Size);
408 // Check for NULL
409 if (pNewBlock==NULL)
410 return BAD_MHANDLE;
412 // Attempt to get a handle for a new block.
413 MHANDLE NewHandle = ClaimHandle(pNewBlock);
415 // if we did not get the handle, throw away the allocation
416 if (NewHandle==BAD_MHANDLE)
418 TRACE( wxT("ClaimBlock - got the memory, but not a handle\n") );
419 CCFree(pNewBlock);
420 pNewBlock = NULL;
423 // return the handle
424 return NewHandle;
430 /********************************************************************************************
432 > BOOL DynamicHeap::ReleaseBlock(MHANDLE Handle)
434 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
435 Created: 26/4/93
436 Inputs: Handle: The handle of the block to be released.
437 Returns: TRUE if the handle was valid
438 Purpose: Given a handle to a memory block, releases this memory block from use, and
439 returns the block to the free pool. Subsequent accesses via this handle
440 or via the block's address cause undefined behaviour.
442 ********************************************************************************************/
445 BOOL DynamicHeap::ReleaseBlock(MHANDLE Handle)
447 #ifdef RALPH
448 RalphCriticalSection RalphCS;
449 #endif
451 // Get details for this handle
452 ADDR Address = DescribeHandle(Handle);
454 // See if it was bad
455 if (Address == BAD_MHANDLE)
457 // Invalid handle - return error
458 TRACE( wxT("ReleaseBlock: Handle is invalid\n") );
459 return FALSE;
462 // It was OK, so free the memory
463 CCFree(Address);
465 // And release the handle or it never will be
466 ReleaseHandle(Handle);
468 return TRUE;
475 /********************************************************************************************
477 > BOOL DynamicHeap::IncreaseBlock(MHANDLE Handle, UINT32 NumBytes)
479 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
480 Created: 06/12/93
481 Inputs: Handle - the handle of the block to resize
482 NumBytes - the number of bytes to add to this block's allocation (must
483 be word-sized, and >=12 bytes).
484 Returns: TRUE if the resize worked, FALSE if it failed.
485 Purpose: See IncreaseBlock for a full description.
486 SeeAlso: IncreaseBlock; DecreaseBlock; InsertMemory; RemoveMemory; DescribeHandle
488 ********************************************************************************************/
490 BOOL DynamicHeap::IncreaseBlock(MHANDLE Handle, UINT32 NumBytes)
492 #ifdef RALPH
493 RalphCriticalSection RalphCS;
494 #endif
496 // Get details for this handle
497 ADDR Address = DescribeHandle(Handle);
499 // See if it is bad
500 if (Address == BAD_MHANDLE)
502 // Invalid handle - return error
503 TRACE( wxT("IncreaseBlock: Handle is invalid\n") );
504 return FALSE;
507 // Find out how big the old block was
508 size_t Size = CCGetBlockSize(Address);
509 Size += NumBytes;
511 // Reallocate the block to the new size
512 ADDR pNewBlock = (ADDR)CCRealloc(Address, Size);
513 if( pNewBlock==NULL )
515 TRACE( wxT("realloc failed in IncreaseBlock\n") );
516 return FALSE;
519 // Update the handle
520 AlterHandle( Handle, pNewBlock );
521 return TRUE;
526 /********************************************************************************************
528 > BOOL DynamicHeap::DecreaseBlock(MHANDLE Handle, UINT32 NumBytes)
530 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
531 Created: 06/12/93
532 Inputs: Handle - the handle of the block to resize
533 NumBytes - the number of bytes to remove from this block's allocation (must
534 be word-sized, and >=12 bytes).
535 Returns: TRUE if the resize worked, FALSE if it failed.
536 Purpose: See DecreaseBlock for a full description.
537 SeeAlso: DecreaseBlock; IncreaseBlock; InsertMemory; RemoveMemory; DescribeHandle
539 ********************************************************************************************/
541 BOOL DynamicHeap::DecreaseBlock(MHANDLE Handle, UINT32 NumBytes)
543 #ifdef RALPH
544 RalphCriticalSection RalphCS;
545 #endif
547 // Get details for this handle
548 ADDR Address = DescribeHandle(Handle);
550 // See if it is bad
551 if (Address == BAD_MHANDLE)
553 // Invalid handle - return error
554 TRACE( wxT("IncreaseBlock: Handle is invalid\n") );
555 return FALSE;
558 // Find out how big the old block was
559 size_t Size = CCGetBlockSize(Address);
560 Size -= NumBytes;
562 // Reallocate the block to the new size
563 ADDR pNewBlock = (ADDR) CCRealloc(Address, Size);
564 if (pNewBlock==NULL)
566 TRACE( wxT("realloc failed in IncreaseBlock\n") );
567 return FALSE;
570 // Update the handle
571 AlterHandle(Handle, pNewBlock);
572 return TRUE;
578 /********************************************************************************************
580 > DynamicHeap *FindHeap(MHANDLE Handle)
582 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
583 Created: 09/02/94
584 Inputs: Handle - the handle of the block to look for.
585 Returns: Pointer to the heap containing the block identified by 'Handle', or NULL
586 if the block cannot be found.
587 Purpose: This function works out which heap the block associated with the handle
588 is in.
590 ********************************************************************************************/
592 static inline DynamicHeap *FindHeap(MHANDLE Handle)
594 ADDR Address = DescribeHandle(Handle);
596 if (Address != BAD_MHANDLE)
598 // return the heap
599 return NormalHeap;
602 // Couldn't find the correct heap
603 return NULL;
607 /********************************************************************************************
609 > BOOL InitMemory();
611 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
612 Created: 26/4/93
613 Returns: TRUE if global memory was obtained and initialised successfully.
614 Purpose: Initialises the dynamic memory manager. This involves obtaining
615 a block of memory from the OS. This is then used as a pool to satisfy
616 allocation requests from clients of this module.
618 ********************************************************************************************/
620 BOOL InitMemory()
622 // Initialise the two heaps - one for normal objects, one for hevy objects (bitmaps etc)
623 NormalHeap = new DynamicHeap;
624 if (NormalHeap==NULL)
625 return FALSE;
627 if (!NormalHeap->Init())
628 // report failure of heap initialisation
629 return FALSE;
631 // Everything went ok
632 return TRUE;
637 /********************************************************************************************
639 > void DeinitMemory();
641 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
642 Created: 26/4/93
643 Purpose: Returns the memory pool to the OS.
645 ********************************************************************************************/
647 void DeinitMemory()
649 if (NormalHeap != NULL)
650 delete NormalHeap;
653 /********************************************************************************************
655 > MHANDLE ClaimBlock(UINT32 Size, BOOL Heavy = FALSE)
657 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
658 Created: 26/4/93
659 Inputs: Size: The size in bytes of the block being requested
660 Heavy: If TRUE, then the block is treated differently to other (non-heavy)
661 blocks, in that heavy blocks are the last to be moved. Large objects
662 (e.g. bitmaps etc) should be declared heavy.
663 Returns: The handle that refers to the newly allocated block.
664 Purpose: Allocates a block of 'size' bytes from the free pool, and obtains a handle
665 or it. Blocks which are zero bytes long are permitted, but blocks must
666 be word-sized (i.e. a multiple of 4 bytes in size).
668 ********************************************************************************************/
670 MHANDLE ClaimBlock(size_t Size, BOOL Heavy)
672 // Make sure we have a heap
673 if (NormalHeap==NULL)
675 ERROR3("The Heap is not there!");
676 return BAD_MHANDLE;
679 // claim some memory from it
680 return NormalHeap->ClaimBlock(Size);
683 /********************************************************************************************
685 > BOOL ReleaseBlock(MHANDLE Handle);
687 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
688 Created: 26/4/93
689 Inputs: Handle: The handle of the block to be released.
690 Returns: TRUE if the handle was valid
691 Purpose: Given a handle to a memory block, releases this memory block from use, and
692 returns the block to the free pool. Subsequent accesses via this handle
693 or via the block's address cause undefined behaviour.
695 ********************************************************************************************/
697 BOOL ReleaseBlock(MHANDLE Handle)
699 // Make sure we have a heap
700 if (NormalHeap==NULL)
702 ERROR3("The Heap is not there!");
703 return FALSE;
706 // Release the memory
707 return NormalHeap->ReleaseBlock(Handle);
712 /********************************************************************************************
714 > BOOL DescribeBlock(MHANDLE Handle, ADDR *Address, UINT32 *Size);
716 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
717 Created: 26/4/93
718 Inputs: Handle: The handle of the block to describe
719 Outputs: Address: The real address of the block
720 Size: The size in bytes of the block
721 Returns: TRUE if the handle was valid
722 Purpose: Given a handle, returns the size and location of the associated block of
723 memory.
725 ********************************************************************************************/
727 BOOL DescribeBlock(MHANDLE Handle, ADDR *Address, size_t *Size)
729 // Get details associated with this handle
730 *Address = DescribeHandle(Handle);
732 if (*Address == NULL)
734 // Handle was invalid - return error
735 TRACE( wxT("DescribeBlock: Handle is invalid\n") );
736 *Address = NULL;
737 *Size = 0;
738 return FALSE;
741 // Extract the size from the block
742 *Size = CCGetBlockSize(*Address);
744 // Everything went ok
745 return TRUE;
748 /********************************************************************************************
750 > BOOL SplitBlock(MHANDLE Handle, INT32 SplitSize, UINT32 Offset);
752 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
753 Created: 26/4/93
754 Inputs: Handle: The handle of the block to be shrunk/enlarged.
755 SplitSize: Amount of memory to insert/delete.
756 Offset: The position to insert/delete memory at.
757 Returns: FALSE
758 Purpose: NB. Do not use this function! Use on of the following instead:
759 IncreaseBlock, DecreaseBlock
760 SeeAlso: IncreaseBlock; DecreaseBlock
762 ********************************************************************************************/
765 BOOL SplitBlock(MHANDLE Handle, INT32 SplitSize, UINT32 Offset)
767 ERROR3("SplitBlock function is now dead. Use IncreaseBlock or DecreaseBlock instead\n");
768 return FALSE;
773 /********************************************************************************************
775 > BOOL IncreaseBlock(MHANDLE Handle, UINT32 NumBytes)
777 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
778 Created: 06/12/93
779 Inputs: Handle - the handle of the block to resize
780 NumBytes - the number of bytes to add to this block's allocation (must
781 be word-sized, and >=12 bytes).
782 Returns: TRUE if the resize worked, FALSE if it failed.
783 Purpose: Increase the size of the specified block by the specified amount. No memory
784 is moved within the block - the block is simply extended.
785 NB. This operation may cause the block to move, so the handle should be
786 realised into an address again (via DescribeBlock()) after this function
787 returns.
788 SeeAlso: DecreaseBlock; InsertMemory; RemoveMemory; DescribeHandle
790 ********************************************************************************************/
792 BOOL IncreaseBlock(MHANDLE Handle, UINT32 NumBytes)
794 // Make sure we have a heap
795 if (NormalHeap==NULL)
797 ERROR3("The Heap is not there!");
798 return FALSE;
801 // Increase the block
802 return NormalHeap->IncreaseBlock(Handle, NumBytes);
805 /********************************************************************************************
807 > BOOL DecreaseBlock(MHANDLE Handle, UINT32 NumBytes)
809 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
810 Created: 06/12/93
811 Inputs: Handle - the handle of the block to resize
812 NumBytes - the number of bytes to remove from this block's allocation (must
813 be word-sized, and >=12 bytes).
814 Returns: TRUE if the resize worked, FALSE if it failed.
815 Purpose: Decrease the size of the specified block by the specified amount. No memory
816 is moved within the block - the block is simply reduced in size, and the
817 memory is chopped off the end.
818 NB. This operation may cause the block to move, so the handle should be
819 realised into an address again (via DescribeBlock()) after this function
820 returns.
821 SeeAlso: IncreaseBlock; InsertMemory; RemoveMemory; DescribeHandle
823 ********************************************************************************************/
825 BOOL DecreaseBlock(MHANDLE Handle, UINT32 NumBytes)
827 // Make sure we have a heap
828 if (NormalHeap==NULL)
830 ERROR3("The Heap is not there!");
831 return FALSE;
834 // Decrease the block
835 return NormalHeap->DecreaseBlock(Handle, NumBytes);
838 /********************************************************************************************
840 > BOOL InsertMemory(MHANDLE Handle, UINT32 Offset, UINT32 NumBytes)
842 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
843 Created: 06/12/93
844 Inputs: Handle - the handle of the block to resize.
845 Offset - the position within the block to insert the memory at (must be
846 word-aligned).
847 NumBytes - the number of bytes to add to this block's allocation (must
848 be word-sized, and >=12 bytes).
849 Returns: TRUE, if the insertion was successful, FALSE if not.
850 Purpose: Insert memory into the middle of a block at the position specified by
851 the 'Offset' parameter. The memory above the offset is shuffled up (i.e.
852 it is not overwritten).
853 i.e. the 'B' block is moved up in order to insert the new memory.
854 The new memory (the '?' block) is uninitialised, so you must initialise
855 it yourself.
857 SeeAlso: IncreaseBlock; DecreaseBlock; RemoveMemory; DescribeHandle;
858 DynamicHeap::InsertMemory
860 ********************************************************************************************/
862 BOOL InsertMemory(MHANDLE Handle, UINT32 Offset, UINT32 NumBytes)
864 ERROR3("InsertMemory function is now dead. Use IncreaseBlock or DecreaseBlock instead\n");
865 return FALSE;
868 /********************************************************************************************
870 > BOOL RemoveMemory(MHANDLE Handle, UINT32 Offset, UINT32 NumBytes)
872 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
873 Created: 06/12/93
874 Inputs: Handle - the handle of the block to resize.
875 Offset - the position within the block to remove the memory at (must be
876 word-aligned).
877 NumBytes - the number of bytes to remove to this block's allocation (must
878 be word-sized, and >=12 bytes).
879 Returns: TRUE, if the removal was successful, FALSE if not.
880 Purpose: Remove memory from the middle of a block at the position specified by
881 the 'Offset' parameter. The memory contents above the offset is shuffled
882 down (i.e. it is not lost).
883 i.e. the 'B' block is moved down in order to preserve its contents.
884 The 'A' block is truncated, and the last 'NumBytes' of it are lost.
886 SeeAlso: IncreaseBlock; DecreaseBlock; InsertMemory; DescribeHandle;
887 DynamicHeap::RemoveMemory
889 ********************************************************************************************/
891 BOOL RemoveMemory(MHANDLE Handle, UINT32 Offset, UINT32 NumBytes)
893 ERROR3("RemoveMemory function is now dead. Use IncreaseBlock or DecreaseBlock instead\n");
894 return FALSE;
897 /********************************************************************************************
899 > BOOL TidyMemory()
901 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
902 Created: 09/02/94
903 Returns: TRUE if a hole was removed, FALSE if there were no holes left to remove.
904 Purpose: Removes one hole from the heap (if any exist). It always removes the hole
905 which is lowest in memory in an attempt to avoid redundant memory moves.
906 Intended to be called on idle events to sanitise the heap when nothing
907 much else is going on.
909 ********************************************************************************************/
911 BOOL TidyMemory()
913 return FALSE;
919 #ifdef _DEBUG
920 /********************************************************************************************
922 > void DumpMemory();
924 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
925 Created: 11/5/93
926 Purpose: Displays size of blocks in the heap (including holes and the free pool
927 at the end). Uses TRACE macro for output - for debugging purposes.
929 ********************************************************************************************/
931 void DumpMemory()
933 // The memory is now allocated by smartHeap, so it will report leaks
938 /********************************************************************************************
940 > void SetMemoryFailFlag(BOOL DenyRequests)
942 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
943 Created: 17/11/93
944 Inputs: DenyRequests - if TRUE, the dynamic heap pretends that it has no more free
945 memory, and all future requests are denied.
946 if FALSE, the heap will start to grant requests for memory
947 again.
948 Purpose: Used in debugging, to check how various subsystems cope with the dynamic
949 heap becoming exhausted.
951 ********************************************************************************************/
953 void SetMemoryFailFlag(BOOL DenyRequests)
955 // This function no longer has any effect.
958 #endif // _DEBUG
963 /********************************************************************************************
965 > void GetMemoryStatus(UINT64* pPhysRam = NULL, UINT32* pLoadPercent = NULL)
967 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
968 Created: 09/March/2006
969 Inputs: -
970 Ouputs: PhysRam - Amount of physical RAM (in bytes)
971 CurrentLoadPercent - Percentage of physical RAM in use at the time of this call
972 Returns: -
973 Purpose: Read the current state of the memory environment for Camelot
975 ********************************************************************************************/
977 #if defined(__WXMSW__)
978 typedef BOOL (PASCAL *GETMEMORYSTATUSEX_FUNC)(LPMEMORYSTATUSEX lpBuffer);
979 #endif
981 void GetMemoryStatus(UINT64* pPhysRam, UINT32* pLoadPercent)
983 #if defined(__WXMSW__)
984 // Windows:
985 // It's important to call GlobalMemoryStatusEX if it's available
986 // because GlobalMemoryStatus has issues in older OSs that can cause it to return
987 // duff information.
988 GETMEMORYSTATUSEX_FUNC pExFunc;
989 pExFunc = (GETMEMORYSTATUSEX_FUNC) GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "GlobalMemoryStatusEx");
991 if (pExFunc)
993 MEMORYSTATUSEX memStatus;
994 memStatus.dwLength=sizeof(MEMORYSTATUSEX);
995 pExFunc(&memStatus);
997 if (pLoadPercent) *pLoadPercent = memStatus.dwMemoryLoad;
998 if (pPhysRam) *pPhysRam = memStatus.ullTotalPhys;
1000 else
1002 MEMORYSTATUS memStatus;
1003 memStatus.dwLength=sizeof(MEMORYSTATUS);
1004 GlobalMemoryStatus(&memStatus);
1006 if (pLoadPercent) *pLoadPercent = memStatus.dwMemoryLoad;
1007 if (pPhysRam) *pPhysRam = memStatus.dwTotalPhys;
1009 #elsif defined(__WXGTK__)
1010 // Assume Linux - there should really be some FreeBSD code here
1012 /* Linux: read memory information from the kernel's /proc/meminfo interface */
1013 FILE *fp;
1014 unsigned long /*TYPENOTE: Correct*/ memTotalKb, memFreeKb;
1015 int /*TYPENOTE: Correct*/ haveMemTotal = 0, haveMemFree = 0;
1016 char lineBuf[256];
1018 fp = fopen("/proc/meminfo", "r");
1020 if (fp != NULL)
1022 while (!haveMemTotal || !haveMemFree)
1024 if (fgets(lineBuf, 256, fp) == NULL)
1025 break;
1027 if (sscanf(lineBuf, "MemTotal: %lu", &memTotalKb) == 1)
1028 haveMemTotal = 1;
1029 if (sscanf(lineBuf, "MemFree: %lu", &memFreeKb) == 1)
1030 haveMemFree = 1;
1032 fclose(fp);
1035 if (!haveMemTotal)
1036 memTotalKb = 512UL * 1024; /* guess 512MB */
1037 if (!haveMemFree)
1038 memFreeKb = memTotalKb / 2; /* guess 50% free */
1040 if (pPhysRam != NULL)
1041 *pPhysRam = (UINT64)memTotalKb * 1024;
1042 if (pLoadPercent != NULL)
1043 *pLoadPercent = (UINT32)(100UL - ((memFreeKb * 100UL) / memTotalKb));
1044 #else
1045 PORTNOTETRACE("other", "GetMemoryStatus is not implemented on this architecture");
1046 if (pPhysRam) *pPhysRam = 512L * 1024 * 1024; // Guess 512M
1047 if (pLoadPercent) *pLoadPercent = 50; // Guess 50% free
1048 #endif