cammemory.cpp

Go to the documentation of this file.
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 

Generated on Sat Nov 10 03:48:09 2007 for Camelot by  doxygen 1.4.4