00001 // $Id: cammemory.cpp 1492 2006-07-20 19:19:48Z alex $ 00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00003 ================================XARAHEADERSTART=========================== 00004 00005 Xara LX, a vector drawing and manipulation program. 00006 Copyright (C) 1993-2006 Xara Group Ltd. 00007 Copyright on certain contributions may be held in joint with their 00008 respective authors. See AUTHORS file for details. 00009 00010 LICENSE TO USE AND MODIFY SOFTWARE 00011 ---------------------------------- 00012 00013 This file is part of Xara LX. 00014 00015 Xara LX is free software; you can redistribute it and/or modify it 00016 under the terms of the GNU General Public License version 2 as published 00017 by the Free Software Foundation. 00018 00019 Xara LX and its component source files are distributed in the hope 00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00022 See the GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with Xara LX (see the file GPL in the root directory of the 00026 distribution); if not, write to the Free Software Foundation, Inc., 51 00027 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00028 00029 00030 ADDITIONAL RIGHTS 00031 ----------------- 00032 00033 Conditional upon your continuing compliance with the GNU General Public 00034 License described above, Xara Group Ltd grants to you certain additional 00035 rights. 00036 00037 The additional rights are to use, modify, and distribute the software 00038 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00039 library and any other such library that any version of Xara LX relased 00040 by Xara Group Ltd requires in order to compile and execute, including 00041 the static linking of that library to XaraLX. In the case of the 00042 "CDraw" library, you may satisfy obligation under the GNU General Public 00043 License to provide source code by providing a binary copy of the library 00044 concerned and a copy of the license accompanying it. 00045 00046 Nothing in this section restricts any of the rights you have under 00047 the GNU General Public License. 00048 00049 00050 SCOPE OF LICENSE 00051 ---------------- 00052 00053 This license applies to this program (XaraLX) and its constituent source 00054 files only, and does not necessarily apply to other Xara products which may 00055 in part share the same code base, and are subject to their own licensing 00056 terms. 00057 00058 This license does not apply to files in the wxXtra directory, which 00059 are built into a separate library, and are subject to the wxWindows 00060 license contained within that directory in the file "WXXTRA-LICENSE". 00061 00062 This license does not apply to the binary libraries (if any) within 00063 the "libs" directory, which are subject to a separate license contained 00064 within that directory in the file "LIBS-LICENSE". 00065 00066 00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00068 ---------------------------------------------- 00069 00070 Subject to the terms of the GNU Public License (see above), you are 00071 free to do whatever you like with your modifications. However, you may 00072 (at your option) wish contribute them to Xara's source tree. You can 00073 find details of how to do this at: 00074 http://www.xaraxtreme.org/developers/ 00075 00076 Prior to contributing your modifications, you will need to complete our 00077 contributor agreement. This can be found at: 00078 http://www.xaraxtreme.org/developers/contribute/ 00079 00080 Please note that Xara will not accept modifications which modify any of 00081 the text between the start and end of this header (marked 00082 XARAHEADERSTART and XARAHEADEREND). 00083 00084 00085 MARKS 00086 ----- 00087 00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00089 designs are registered or unregistered trademarks, design-marks, and/or 00090 service marks of Xara Group Ltd. All rights in these marks are reserved. 00091 00092 00093 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00094 http://www.xara.com/ 00095 00096 =================================XARAHEADEREND============================ 00097 */ 00098 00099 // This is the Camelot Dynamic Memory Manager 00100 // This has been changed to use the normal Static heap now, as SmartHeap does a better job. 00101 // If you want to get back to any of the source code that was here before, you will want to check 00102 // out version 1.30 of this file. After that it is mostly missing. 00103 00104 00105 #include "camtypes.h" 00106 //#include "handles.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00107 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00108 //#include "cammemory.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00109 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00110 //#include "memblk.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00111 00112 #if defined(__WXGTK__) 00113 #include <stdio.h> 00114 #endif 00115 00116 #ifdef RALPH 00117 #include "ralphcri.h" 00118 #endif 00119 00120 DECLARE_SOURCE("$Revision: 1492 $"); 00121 00122 // Declare smart memory handling in Debug builds 00123 #define new CAM_DEBUG_NEW 00124 00125 00126 /******************************************************************************************** 00127 00128 00129 Technical Notes 00130 ~~~~~~~~~~~~~~~ 00131 00132 General 00133 ~~~~~~~ 00134 00135 At present, this module obtains a chunk of memory from Windows' Global heap, 00136 and uses this to satisfy client memory requests. The handle to this memory is 00137 resolved to a physical address, and the block is locked for the duration of the 00138 memory manager's use (i.e. until DeinitMemory() is called, when it is unlocked and 00139 returned to the global heap). The 'FreePoolPtr' variable points to the base of the 00140 block. Under 16bit Windows, the block is limited to 64k in size. 00141 00142 The handles used are managed by another module - the handle manager (see 00143 winoil\handles.{h,cpp}). 00144 00145 In order to cope with 'heavy' blocks (see ClaimBlock), two heaps are maintained. 00146 One is for heavy blocks, the other for normal blocks. This is the ideal solution 00147 under Windows, because we use a GlobalAlloc call for each, so when we need to add 00148 a new heavy block, we don't need to move all the non-heavy objects to do so. The OS 00149 will cope with it by remapping the memory controller - i.e. we don't move any 00150 memory - this is *good*. 00151 00152 Allocated blocks of memory are not always contiguous; there may be holes (unused 00153 blocks) in the heap. 00154 00155 The first word of a memory block contains its size in bytes, and a flag to indicate 00156 whether or not it is a hole (i.e. not in use). Therefore it is possible to step 00157 through the heap simply by reading the size of each block and using that to move on to 00158 the next block. A size of 0 indicates that the block containing the free space at the 00159 end of the heap has been reached. This block is also marked as _not_ being a 00160 hole - this (somewhat counter-intuitively) makes certain operations on the heap 00161 simpler. 00162 00163 The 'FreeOffset' variable is an offset to the start of any remaining memory in the 64k 00164 block (hence it is 0 initially - all memory is available). This memory does not 00165 include holes. When a request for memory fails, the holes are examined to see if one 00166 of them can accomodate the request. If no holes are big enough, the manager 00167 incrementally removes the holes until it can be satisfied, or until there are no more 00168 holes to free. ("When Alexander saw the size of his allocation, he wept, for there 00169 were no more holes to free...") 00170 00171 The memory manager uses the principle of lazy evaluation - expensive operations are 00172 defered until they are absolutely necessary, or when the CPU would otherwise be idle. 00173 This minimises response times for the user. 00174 00175 Holes 00176 ~~~~~ 00177 00178 Holes are intended to be transient - the idea is that when releasing a block it is 00179 simply marked as released. Then, when the application receives idle events, it should 00180 call TidyMemory(), which will move one block at a time to clean up the holes. 00181 00182 The upshot of all this is that when large allocations/deallocations are taking place, 00183 the user doesn't notice much (if any) degradation in response time, because the memory 00184 is not being moved. However, when the user next stops to think for a few seconds, the 00185 application will be 'covertly' tidying up its memory holes while the CPU is idle. Only 00186 one block is tidied at once so that control can be returned to the user quickly (when 00187 they stop thinking and start clicking). 00188 00189 The function RemoveBlockGaps() is also provided to force all holes to be purged from 00190 the heap (which may be desirable for events such as removing a document from memory, 00191 and so on). 00192 00193 When a block is released by its owner, the associated handle is also freed. The list of 00194 holes is maintained using the blocks themselves - as each block (either used or unused) 00195 has its size contained in the first word of its memory, the blocks effectively form 00196 a linked list which can be efficiently scanned for holes. Holes are not joined 00197 together unless this is necessary (usually when the heap is being compacted). 00198 00199 When tidying the memory, it is guaranteed (by calling JoinHoles() before doing 00200 anything else) that no two holes will be adjacent - any such holes will have been 00201 joined into one. Therefore when a hole is found, a block that is in use will be 00202 sitting above it in memory. These two blocks (the hole and the block in use) are 00203 then swapped around, so that the hole is above the used block, and the used block now 00204 starts where the hole used to. Any handles into the used block are updated using the 00205 handle manager. There are, of course, no handles into the hole as it is not a valid 00206 memory block anyway. The hole's first word is then set to contain its size, as before. 00207 (NB only the contents of the block in use are moved - the hole's contents are not moved 00208 because they are undefined anyway, so it would be unnecessary). Finally, if there is a 00209 hole directly above this hole, the two are joined together. 00210 00211 00212 For example: 00213 ------------ 00214 Dynamic Heap (X = Block In Use, . = Hole) 00215 00216 +-------+------+------------+-------+------+-----------------+ 00217 Before tidying: |XXXXXXX|......|XXXXXXXXXXXX|.......|XXXXXX| Free Space | 00218 +-------+------+------------+-------+------+-----------------+ 00219 00220 00221 +-------+------------+--------------+------+-----------------+ 00222 After tidying: |XXXXXXX|XXXXXXXXXXXX|..............|XXXXXX| Free Space | 00223 +-------+------------+--------------+------+-----------------+ 00224 00225 00226 00227 No special algorithms for reclaiming/joining blocks are required (as they would be 00228 in a normal malloc-style heap), because all the blocks in the heap can be moved at 00229 will. 00230 Therefore optimising allocations for FIFO schemes, buddy schemes etc., is pointless. 00231 Whenever the holes cause problems for allocation requests, they are gradually removed 00232 to free up memory - this is not possible for a static heap manager! 00233 00234 00235 Inter-block gaps 00236 ~~~~~~~~~~~~~~~~ 00237 00238 The 'EndOfBlockGap' is used to resolve the problem of not knowing whether an address 00239 refers to the end of one block or the start of the next (according to Jim). Blocks 00240 are simply separated by a 'dead zone' of 4 bytes. 00241 00242 Since the introduction of BlockHeader fields, I think this EndOfBlockGap can safely 00243 be dropped...must try it sometime. 00244 00245 00246 Resizing blocks 00247 ~~~~~~~~~~~~~~~ 00248 00249 Blocks can be either increased or decreased in size. There are two functions which 00250 perform simple resizing of blocks: IncreaseBlock() and DecreaseBlock(). They simply 00251 alter the size of the block's allocation, and do not move any memory. 00252 Two other functions, InsertMemory() and RemoveMemory(), are provided for inserting 00253 memory into the middle of a block, or removing it from the middle of a block. 00254 00255 Strategies used for resizing blocks 00256 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 00257 00258 When making blocks smaller, the excess is simply made into a hole for removal later 00259 on. 00260 00261 When increasing the size of the block, if a large enough hole exists above the block 00262 being resized, then it is used to expand the block into, and the hole is decreased 00263 in size accordingly. Note that no other blocks are moved in this case. 00264 00265 (Future optimisation: at this point, the manager should try to find any hole big 00266 enough to hold the block, and reposition the block into that). 00267 00268 If the hole isn't big enough to accommodate the request, then the manager compacts 00269 the heap and tries again. If there is still not enough room, then the heap itself 00270 is resized - if not enough memory is available, the request fails. 00271 00272 00273 SplitBlock() 00274 ~~~~~~~~~~~~ 00275 00276 NB. SplitBlock() has been replaced by the other function calls listed above, and 00277 should no longer be used. Please change any existing code that stil uses it. The 00278 function will be removed in the future. 00279 00280 SplitBlock() resizes blocks of memory. It can make blocks bigger or smaller. 00281 00282 00283 Releasing memory 00284 ~~~~~~~~~~~~~~~~ 00285 00286 At present, this module never returns memory to the OS until DeinitMemory() is called. 00287 In future, TidyMemory should return memory once the free memory in the heap reaches 00288 a certain threshold. 00289 00290 00291 The Invaders - Epilogue 00292 ~~~~~~~~~~~~~~~~~~~~~~~ 00293 00294 The addition of holes complicates this module somewhat, but not unduly. The worst 00295 affected functions are SplitBlock() and ClaimBlock(), which run rings around holes in 00296 order to do their job. However, what they're trying to do is avoid redundant memory 00297 transfers which can be VERY expensive, and hence the memory manager is faster at its 00298 job, which is the point of the exercise (TANSTAAFL). 00299 00300 00301 ********************************************************************************************/ 00302 00303 class DynamicHeap : public CC_CLASS_MEMDUMP 00304 { 00305 CC_DECLARE_MEMDUMP(DynamicHeap) 00306 00307 public: 00308 // Creation/initialisation/destruction 00309 DynamicHeap(); 00310 BOOL Init(); 00311 ~DynamicHeap(); 00312 00313 // Claiming and releasing memory 00314 MHANDLE ClaimBlock(size_t Size); 00315 BOOL ReleaseBlock(MHANDLE Handle); 00316 00317 // Resizing blocks 00318 BOOL IncreaseBlock(MHANDLE Handle, UINT32 NumBytes); 00319 BOOL DecreaseBlock(MHANDLE Handle, UINT32 NumBytes); 00320 }; 00321 00322 CC_IMPLEMENT_MEMDUMP(DynamicHeap, CCObject) 00323 00324 // Pointers to the heap objects. 00325 static DynamicHeap *NormalHeap = NULL; 00326 00327 00328 00329 /******************************************************************************************** 00330 00331 > DynamicHeap::DynamicHeap() 00332 00333 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00334 Created: 09/02/94 00335 Purpose: Sets up the heap variables, ready for Init() to be called. 00336 SeeAlso: DynamicHeap::Init; DynamicHeap::~DynamicHeap 00337 00338 ********************************************************************************************/ 00339 00340 DynamicHeap::DynamicHeap() 00341 { 00342 } 00343 00344 /******************************************************************************************** 00345 00346 > BOOL DynamicHeap::Init() 00347 00348 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00349 Created: 09/02/94 00350 Returns: TRUE if the initialisation was successful, FALSE if not (e.g. couldn't 00351 get any memory). 00352 Purpose: Initialise the heap object. This gets a chunk of memory from the operating 00353 system, which it will use to satsify allocation requests. 00354 Errors: If unable to claim memory. 00355 00356 ********************************************************************************************/ 00357 00358 BOOL DynamicHeap::Init() 00359 { 00360 // Everything went ok 00361 return TRUE; 00362 } 00363 00364 00365 00366 /******************************************************************************************** 00367 00368 > DynamicHeap::~DynamicHeap() 00369 00370 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00371 Created: 09/02/94 00372 Purpose: Deallocates any memory used by this heap object. 00373 In debug builds it checks the heap for objects which have not been 00374 deallocated, or for heap corruption, and complains if it finds any. 00375 SeeAlso: DynamicHeap::Init; DynamicHeap::DynamicHeap; InitMemory; DeinitMemory 00376 00377 ********************************************************************************************/ 00378 00379 DynamicHeap::~DynamicHeap() 00380 { 00381 } 00382 00383 00384 00385 /******************************************************************************************** 00386 00387 > MHANDLE DynamicHeap::ClaimBlock(UINT32 Size) 00388 00389 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00390 Created: 26/04/93 00391 Inputs: Size: The size in bytes of the block being requested 00392 Returns: The handle that refers to the newly allocated block. 00393 Purpose: Allocates a block of 'size' bytes from the free pool, and obtains a handle 00394 for it. Blocks which are zero bytes long are permitted, but blocks must 00395 be word-sized (i.e. a multiple of 4 bytes in size). 00396 00397 ********************************************************************************************/ 00398 00399 MHANDLE DynamicHeap::ClaimBlock(size_t Size) 00400 { 00401 #ifdef RALPH 00402 RalphCriticalSection RalphCS; 00403 #endif 00404 00405 // Get the memory 00406 ADDR pNewBlock = (ADDR) CCMalloc(Size); 00407 00408 // Check for NULL 00409 if (pNewBlock==NULL) 00410 return BAD_MHANDLE; 00411 00412 // Attempt to get a handle for a new block. 00413 MHANDLE NewHandle = ClaimHandle(pNewBlock); 00414 00415 // if we did not get the handle, throw away the allocation 00416 if (NewHandle==BAD_MHANDLE) 00417 { 00418 TRACE( wxT("ClaimBlock - got the memory, but not a handle\n") ); 00419 CCFree(pNewBlock); 00420 pNewBlock = NULL; 00421 } 00422 00423 // return the handle 00424 return NewHandle; 00425 } 00426 00427 00428 00429 00430 /******************************************************************************************** 00431 00432 > BOOL DynamicHeap::ReleaseBlock(MHANDLE Handle) 00433 00434 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00435 Created: 26/4/93 00436 Inputs: Handle: The handle of the block to be released. 00437 Returns: TRUE if the handle was valid 00438 Purpose: Given a handle to a memory block, releases this memory block from use, and 00439 returns the block to the free pool. Subsequent accesses via this handle 00440 or via the block's address cause undefined behaviour. 00441 00442 ********************************************************************************************/ 00443 00444 00445 BOOL DynamicHeap::ReleaseBlock(MHANDLE Handle) 00446 { 00447 #ifdef RALPH 00448 RalphCriticalSection RalphCS; 00449 #endif 00450 00451 // Get details for this handle 00452 ADDR Address = DescribeHandle(Handle); 00453 00454 // See if it was bad 00455 if (Address == BAD_MHANDLE) 00456 { 00457 // Invalid handle - return error 00458 TRACE( wxT("ReleaseBlock: Handle is invalid\n") ); 00459 return FALSE; 00460 } 00461 00462 // It was OK, so free the memory 00463 CCFree(Address); 00464 00465 // And release the handle or it never will be 00466 ReleaseHandle(Handle); 00467 00468 return TRUE; 00469 } 00470 00471 00472 00473 00474 00475 /******************************************************************************************** 00476 00477 > BOOL DynamicHeap::IncreaseBlock(MHANDLE Handle, UINT32 NumBytes) 00478 00479 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00480 Created: 06/12/93 00481 Inputs: Handle - the handle of the block to resize 00482 NumBytes - the number of bytes to add to this block's allocation (must 00483 be word-sized, and >=12 bytes). 00484 Returns: TRUE if the resize worked, FALSE if it failed. 00485 Purpose: See IncreaseBlock for a full description. 00486 SeeAlso: IncreaseBlock; DecreaseBlock; InsertMemory; RemoveMemory; DescribeHandle 00487 00488 ********************************************************************************************/ 00489 00490 BOOL DynamicHeap::IncreaseBlock(MHANDLE Handle, UINT32 NumBytes) 00491 { 00492 #ifdef RALPH 00493 RalphCriticalSection RalphCS; 00494 #endif 00495 00496 // Get details for this handle 00497 ADDR Address = DescribeHandle(Handle); 00498 00499 // See if it is bad 00500 if (Address == BAD_MHANDLE) 00501 { 00502 // Invalid handle - return error 00503 TRACE( wxT("IncreaseBlock: Handle is invalid\n") ); 00504 return FALSE; 00505 } 00506 00507 // Find out how big the old block was 00508 size_t Size = CCGetBlockSize(Address); 00509 Size += NumBytes; 00510 00511 // Reallocate the block to the new size 00512 ADDR pNewBlock = (ADDR)CCRealloc(Address, Size); 00513 if( pNewBlock==NULL ) 00514 { 00515 TRACE( wxT("realloc failed in IncreaseBlock\n") ); 00516 return FALSE; 00517 } 00518 00519 // Update the handle 00520 AlterHandle( Handle, pNewBlock ); 00521 return TRUE; 00522 } 00523 00524 00525 00526 /******************************************************************************************** 00527 00528 > BOOL DynamicHeap::DecreaseBlock(MHANDLE Handle, UINT32 NumBytes) 00529 00530 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00531 Created: 06/12/93 00532 Inputs: Handle - the handle of the block to resize 00533 NumBytes - the number of bytes to remove from this block's allocation (must 00534 be word-sized, and >=12 bytes). 00535 Returns: TRUE if the resize worked, FALSE if it failed. 00536 Purpose: See DecreaseBlock for a full description. 00537 SeeAlso: DecreaseBlock; IncreaseBlock; InsertMemory; RemoveMemory; DescribeHandle 00538 00539 ********************************************************************************************/ 00540 00541 BOOL DynamicHeap::DecreaseBlock(MHANDLE Handle, UINT32 NumBytes) 00542 { 00543 #ifdef RALPH 00544 RalphCriticalSection RalphCS; 00545 #endif 00546 00547 // Get details for this handle 00548 ADDR Address = DescribeHandle(Handle); 00549 00550 // See if it is bad 00551 if (Address == BAD_MHANDLE) 00552 { 00553 // Invalid handle - return error 00554 TRACE( wxT("IncreaseBlock: Handle is invalid\n") ); 00555 return FALSE; 00556 } 00557 00558 // Find out how big the old block was 00559 size_t Size = CCGetBlockSize(Address); 00560 Size -= NumBytes; 00561 00562 // Reallocate the block to the new size 00563 ADDR pNewBlock = (ADDR) CCRealloc(Address, Size); 00564 if (pNewBlock==NULL) 00565 { 00566 TRACE( wxT("realloc failed in IncreaseBlock\n") ); 00567 return FALSE; 00568 } 00569 00570 // Update the handle 00571 AlterHandle(Handle, pNewBlock); 00572 return TRUE; 00573 } 00574 00575 00576 00577 00578 /******************************************************************************************** 00579 00580 > DynamicHeap *FindHeap(MHANDLE Handle) 00581 00582 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00583 Created: 09/02/94 00584 Inputs: Handle - the handle of the block to look for. 00585 Returns: Pointer to the heap containing the block identified by 'Handle', or NULL 00586 if the block cannot be found. 00587 Purpose: This function works out which heap the block associated with the handle 00588 is in. 00589 00590 ********************************************************************************************/ 00591 00592 static inline DynamicHeap *FindHeap(MHANDLE Handle) 00593 { 00594 ADDR Address = DescribeHandle(Handle); 00595 00596 if (Address != BAD_MHANDLE) 00597 { 00598 // return the heap 00599 return NormalHeap; 00600 } 00601 00602 // Couldn't find the correct heap 00603 return NULL; 00604 } 00605 00606 00607 /******************************************************************************************** 00608 00609 > BOOL InitMemory(); 00610 00611 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00612 Created: 26/4/93 00613 Returns: TRUE if global memory was obtained and initialised successfully. 00614 Purpose: Initialises the dynamic memory manager. This involves obtaining 00615 a block of memory from the OS. This is then used as a pool to satisfy 00616 allocation requests from clients of this module. 00617 00618 ********************************************************************************************/ 00619 00620 BOOL InitMemory() 00621 { 00622 // Initialise the two heaps - one for normal objects, one for hevy objects (bitmaps etc) 00623 NormalHeap = new DynamicHeap; 00624 if (NormalHeap==NULL) 00625 return FALSE; 00626 00627 if (!NormalHeap->Init()) 00628 // report failure of heap initialisation 00629 return FALSE; 00630 00631 // Everything went ok 00632 return TRUE; 00633 } 00634 00635 00636 00637 /******************************************************************************************** 00638 00639 > void DeinitMemory(); 00640 00641 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00642 Created: 26/4/93 00643 Purpose: Returns the memory pool to the OS. 00644 00645 ********************************************************************************************/ 00646 00647 void DeinitMemory() 00648 { 00649 if (NormalHeap != NULL) 00650 delete NormalHeap; 00651 } 00652 00653 /******************************************************************************************** 00654 00655 > MHANDLE ClaimBlock(UINT32 Size, BOOL Heavy = FALSE) 00656 00657 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00658 Created: 26/4/93 00659 Inputs: Size: The size in bytes of the block being requested 00660 Heavy: If TRUE, then the block is treated differently to other (non-heavy) 00661 blocks, in that heavy blocks are the last to be moved. Large objects 00662 (e.g. bitmaps etc) should be declared heavy. 00663 Returns: The handle that refers to the newly allocated block. 00664 Purpose: Allocates a block of 'size' bytes from the free pool, and obtains a handle 00665 or it. Blocks which are zero bytes long are permitted, but blocks must 00666 be word-sized (i.e. a multiple of 4 bytes in size). 00667 00668 ********************************************************************************************/ 00669 00670 MHANDLE ClaimBlock(size_t Size, BOOL Heavy) 00671 { 00672 // Make sure we have a heap 00673 if (NormalHeap==NULL) 00674 { 00675 ERROR3("The Heap is not there!"); 00676 return BAD_MHANDLE; 00677 } 00678 00679 // claim some memory from it 00680 return NormalHeap->ClaimBlock(Size); 00681 } 00682 00683 /******************************************************************************************** 00684 00685 > BOOL ReleaseBlock(MHANDLE Handle); 00686 00687 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00688 Created: 26/4/93 00689 Inputs: Handle: The handle of the block to be released. 00690 Returns: TRUE if the handle was valid 00691 Purpose: Given a handle to a memory block, releases this memory block from use, and 00692 returns the block to the free pool. Subsequent accesses via this handle 00693 or via the block's address cause undefined behaviour. 00694 00695 ********************************************************************************************/ 00696 00697 BOOL ReleaseBlock(MHANDLE Handle) 00698 { 00699 // Make sure we have a heap 00700 if (NormalHeap==NULL) 00701 { 00702 ERROR3("The Heap is not there!"); 00703 return FALSE; 00704 } 00705 00706 // Release the memory 00707 return NormalHeap->ReleaseBlock(Handle); 00708 } 00709 00710 00711 00712 /******************************************************************************************** 00713 00714 > BOOL DescribeBlock(MHANDLE Handle, ADDR *Address, UINT32 *Size); 00715 00716 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00717 Created: 26/4/93 00718 Inputs: Handle: The handle of the block to describe 00719 Outputs: Address: The real address of the block 00720 Size: The size in bytes of the block 00721 Returns: TRUE if the handle was valid 00722 Purpose: Given a handle, returns the size and location of the associated block of 00723 memory. 00724 00725 ********************************************************************************************/ 00726 00727 BOOL DescribeBlock(MHANDLE Handle, ADDR *Address, size_t *Size) 00728 { 00729 // Get details associated with this handle 00730 *Address = DescribeHandle(Handle); 00731 00732 if (*Address == NULL) 00733 { 00734 // Handle was invalid - return error 00735 TRACE( wxT("DescribeBlock: Handle is invalid\n") ); 00736 *Address = NULL; 00737 *Size = 0; 00738 return FALSE; 00739 } 00740 00741 // Extract the size from the block 00742 *Size = CCGetBlockSize(*Address); 00743 00744 // Everything went ok 00745 return TRUE; 00746 } 00747 00748 /******************************************************************************************** 00749 00750 > BOOL SplitBlock(MHANDLE Handle, INT32 SplitSize, UINT32 Offset); 00751 00752 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00753 Created: 26/4/93 00754 Inputs: Handle: The handle of the block to be shrunk/enlarged. 00755 SplitSize: Amount of memory to insert/delete. 00756 Offset: The position to insert/delete memory at. 00757 Returns: FALSE 00758 Purpose: NB. Do not use this function! Use on of the following instead: 00759 IncreaseBlock, DecreaseBlock 00760 SeeAlso: IncreaseBlock; DecreaseBlock 00761 00762 ********************************************************************************************/ 00763 00764 00765 BOOL SplitBlock(MHANDLE Handle, INT32 SplitSize, UINT32 Offset) 00766 { 00767 ERROR3("SplitBlock function is now dead. Use IncreaseBlock or DecreaseBlock instead\n"); 00768 return FALSE; 00769 } 00770 00771 00772 00773 /******************************************************************************************** 00774 00775 > BOOL IncreaseBlock(MHANDLE Handle, UINT32 NumBytes) 00776 00777 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00778 Created: 06/12/93 00779 Inputs: Handle - the handle of the block to resize 00780 NumBytes - the number of bytes to add to this block's allocation (must 00781 be word-sized, and >=12 bytes). 00782 Returns: TRUE if the resize worked, FALSE if it failed. 00783 Purpose: Increase the size of the specified block by the specified amount. No memory 00784 is moved within the block - the block is simply extended. 00785 NB. This operation may cause the block to move, so the handle should be 00786 realised into an address again (via DescribeBlock()) after this function 00787 returns. 00788 SeeAlso: DecreaseBlock; InsertMemory; RemoveMemory; DescribeHandle 00789 00790 ********************************************************************************************/ 00791 00792 BOOL IncreaseBlock(MHANDLE Handle, UINT32 NumBytes) 00793 { 00794 // Make sure we have a heap 00795 if (NormalHeap==NULL) 00796 { 00797 ERROR3("The Heap is not there!"); 00798 return FALSE; 00799 } 00800 00801 // Increase the block 00802 return NormalHeap->IncreaseBlock(Handle, NumBytes); 00803 } 00804 00805 /******************************************************************************************** 00806 00807 > BOOL DecreaseBlock(MHANDLE Handle, UINT32 NumBytes) 00808 00809 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00810 Created: 06/12/93 00811 Inputs: Handle - the handle of the block to resize 00812 NumBytes - the number of bytes to remove from this block's allocation (must 00813 be word-sized, and >=12 bytes). 00814 Returns: TRUE if the resize worked, FALSE if it failed. 00815 Purpose: Decrease the size of the specified block by the specified amount. No memory 00816 is moved within the block - the block is simply reduced in size, and the 00817 memory is chopped off the end. 00818 NB. This operation may cause the block to move, so the handle should be 00819 realised into an address again (via DescribeBlock()) after this function 00820 returns. 00821 SeeAlso: IncreaseBlock; InsertMemory; RemoveMemory; DescribeHandle 00822 00823 ********************************************************************************************/ 00824 00825 BOOL DecreaseBlock(MHANDLE Handle, UINT32 NumBytes) 00826 { 00827 // Make sure we have a heap 00828 if (NormalHeap==NULL) 00829 { 00830 ERROR3("The Heap is not there!"); 00831 return FALSE; 00832 } 00833 00834 // Decrease the block 00835 return NormalHeap->DecreaseBlock(Handle, NumBytes); 00836 } 00837 00838 /******************************************************************************************** 00839 00840 > BOOL InsertMemory(MHANDLE Handle, UINT32 Offset, UINT32 NumBytes) 00841 00842 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00843 Created: 06/12/93 00844 Inputs: Handle - the handle of the block to resize. 00845 Offset - the position within the block to insert the memory at (must be 00846 word-aligned). 00847 NumBytes - the number of bytes to add to this block's allocation (must 00848 be word-sized, and >=12 bytes). 00849 Returns: TRUE, if the insertion was successful, FALSE if not. 00850 Purpose: Insert memory into the middle of a block at the position specified by 00851 the 'Offset' parameter. The memory above the offset is shuffled up (i.e. 00852 it is not overwritten). 00853 i.e. the 'B' block is moved up in order to insert the new memory. 00854 The new memory (the '?' block) is uninitialised, so you must initialise 00855 it yourself. 00856 00857 SeeAlso: IncreaseBlock; DecreaseBlock; RemoveMemory; DescribeHandle; 00858 DynamicHeap::InsertMemory 00859 00860 ********************************************************************************************/ 00861 00862 BOOL InsertMemory(MHANDLE Handle, UINT32 Offset, UINT32 NumBytes) 00863 { 00864 ERROR3("InsertMemory function is now dead. Use IncreaseBlock or DecreaseBlock instead\n"); 00865 return FALSE; 00866 } 00867 00868 /******************************************************************************************** 00869 00870 > BOOL RemoveMemory(MHANDLE Handle, UINT32 Offset, UINT32 NumBytes) 00871 00872 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00873 Created: 06/12/93 00874 Inputs: Handle - the handle of the block to resize. 00875 Offset - the position within the block to remove the memory at (must be 00876 word-aligned). 00877 NumBytes - the number of bytes to remove to this block's allocation (must 00878 be word-sized, and >=12 bytes). 00879 Returns: TRUE, if the removal was successful, FALSE if not. 00880 Purpose: Remove memory from the middle of a block at the position specified by 00881 the 'Offset' parameter. The memory contents above the offset is shuffled 00882 down (i.e. it is not lost). 00883 i.e. the 'B' block is moved down in order to preserve its contents. 00884 The 'A' block is truncated, and the last 'NumBytes' of it are lost. 00885 00886 SeeAlso: IncreaseBlock; DecreaseBlock; InsertMemory; DescribeHandle; 00887 DynamicHeap::RemoveMemory 00888 00889 ********************************************************************************************/ 00890 00891 BOOL RemoveMemory(MHANDLE Handle, UINT32 Offset, UINT32 NumBytes) 00892 { 00893 ERROR3("RemoveMemory function is now dead. Use IncreaseBlock or DecreaseBlock instead\n"); 00894 return FALSE; 00895 } 00896 00897 /******************************************************************************************** 00898 00899 > BOOL TidyMemory() 00900 00901 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00902 Created: 09/02/94 00903 Returns: TRUE if a hole was removed, FALSE if there were no holes left to remove. 00904 Purpose: Removes one hole from the heap (if any exist). It always removes the hole 00905 which is lowest in memory in an attempt to avoid redundant memory moves. 00906 Intended to be called on idle events to sanitise the heap when nothing 00907 much else is going on. 00908 00909 ********************************************************************************************/ 00910 00911 BOOL TidyMemory() 00912 { 00913 return FALSE; 00914 } 00915 00916 00917 00918 00919 #ifdef _DEBUG 00920 /******************************************************************************************** 00921 00922 > void DumpMemory(); 00923 00924 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00925 Created: 11/5/93 00926 Purpose: Displays size of blocks in the heap (including holes and the free pool 00927 at the end). Uses TRACE macro for output - for debugging purposes. 00928 00929 ********************************************************************************************/ 00930 00931 void DumpMemory() 00932 { 00933 // The memory is now allocated by smartHeap, so it will report leaks 00934 } 00935 00936 00937 00938 /******************************************************************************************** 00939 00940 > void SetMemoryFailFlag(BOOL DenyRequests) 00941 00942 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00943 Created: 17/11/93 00944 Inputs: DenyRequests - if TRUE, the dynamic heap pretends that it has no more free 00945 memory, and all future requests are denied. 00946 if FALSE, the heap will start to grant requests for memory 00947 again. 00948 Purpose: Used in debugging, to check how various subsystems cope with the dynamic 00949 heap becoming exhausted. 00950 00951 ********************************************************************************************/ 00952 00953 void SetMemoryFailFlag(BOOL DenyRequests) 00954 { 00955 // This function no longer has any effect. 00956 } 00957 00958 #endif // _DEBUG 00959 00960 00961 00962 00963 /******************************************************************************************** 00964 00965 > void GetMemoryStatus(UINT64* pPhysRam = NULL, UINT32* pLoadPercent = NULL) 00966 00967 Author: Phil_Martin (Xara Group Ltd) <camelotdev@xara.com> 00968 Created: 09/March/2006 00969 Inputs: - 00970 Ouputs: PhysRam - Amount of physical RAM (in bytes) 00971 CurrentLoadPercent - Percentage of physical RAM in use at the time of this call 00972 Returns: - 00973 Purpose: Read the current state of the memory environment for Camelot 00974 00975 ********************************************************************************************/ 00976 00977 #if defined(__WXMSW__) 00978 typedef BOOL (PASCAL *GETMEMORYSTATUSEX_FUNC)(LPMEMORYSTATUSEX lpBuffer); 00979 #endif 00980 00981 void GetMemoryStatus(UINT64* pPhysRam, UINT32* pLoadPercent) 00982 { 00983 #if defined(__WXMSW__) 00984 // Windows: 00985 // It's important to call GlobalMemoryStatusEX if it's available 00986 // because GlobalMemoryStatus has issues in older OSs that can cause it to return 00987 // duff information. 00988 GETMEMORYSTATUSEX_FUNC pExFunc; 00989 pExFunc = (GETMEMORYSTATUSEX_FUNC) GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "GlobalMemoryStatusEx"); 00990 00991 if (pExFunc) 00992 { 00993 MEMORYSTATUSEX memStatus; 00994 memStatus.dwLength=sizeof(MEMORYSTATUSEX); 00995 pExFunc(&memStatus); 00996 00997 if (pLoadPercent) *pLoadPercent = memStatus.dwMemoryLoad; 00998 if (pPhysRam) *pPhysRam = memStatus.ullTotalPhys; 00999 } 01000 else 01001 { 01002 MEMORYSTATUS memStatus; 01003 memStatus.dwLength=sizeof(MEMORYSTATUS); 01004 GlobalMemoryStatus(&memStatus); 01005 01006 if (pLoadPercent) *pLoadPercent = memStatus.dwMemoryLoad; 01007 if (pPhysRam) *pPhysRam = memStatus.dwTotalPhys; 01008 } 01009 #elsif defined(__WXGTK__) 01010 // Assume Linux - there should really be some FreeBSD code here 01011 01012 /* Linux: read memory information from the kernel's /proc/meminfo interface */ 01013 FILE *fp; 01014 unsigned long /*TYPENOTE: Correct*/ memTotalKb, memFreeKb; 01015 int /*TYPENOTE: Correct*/ haveMemTotal = 0, haveMemFree = 0; 01016 char lineBuf[256]; 01017 01018 fp = fopen("/proc/meminfo", "r"); 01019 01020 if (fp != NULL) 01021 { 01022 while (!haveMemTotal || !haveMemFree) 01023 { 01024 if (fgets(lineBuf, 256, fp) == NULL) 01025 break; 01026 01027 if (sscanf(lineBuf, "MemTotal: %lu", &memTotalKb) == 1) 01028 haveMemTotal = 1; 01029 if (sscanf(lineBuf, "MemFree: %lu", &memFreeKb) == 1) 01030 haveMemFree = 1; 01031 } 01032 fclose(fp); 01033 } 01034 01035 if (!haveMemTotal) 01036 memTotalKb = 512UL * 1024; /* guess 512MB */ 01037 if (!haveMemFree) 01038 memFreeKb = memTotalKb / 2; /* guess 50% free */ 01039 01040 if (pPhysRam != NULL) 01041 *pPhysRam = (UINT64)memTotalKb * 1024; 01042 if (pLoadPercent != NULL) 01043 *pLoadPercent = (UINT32)(100UL - ((memFreeKb * 100UL) / memTotalKb)); 01044 #else 01045 PORTNOTETRACE("other", "GetMemoryStatus is not implemented on this architecture"); 01046 if (pPhysRam) *pPhysRam = 512L * 1024 * 1024; // Guess 512M 01047 if (pLoadPercent) *pLoadPercent = 50; // Guess 50% free 01048 #endif 01049 } 01050 01051 01052