home *** CD-ROM | disk | FTP | other *** search
- // Listing 6
- // mobject.cpp
- //
- // Copyright Singleton Systems Ltd 1994
-
- #include "stdafx.h"
- #include <new.h>
- #include "farheapb.h"
- #include "mobject.h"
- #include <iomanip.h>
- #include "newtest.h"
-
- #if defined (_DEBUG)
- char MemoryObject::validity_tag_value [4] = "DfK";
- #endif
-
- #if defined (_DEBUG)
- // For file name and line number tracking during debug
- void FAR * MemoryObject::operator new
- (size_t size, const char FAR * FileName, int Line)
- {
- MemoryObject * p_allocated = new (size) MemoryObject;
- #if defined (_DEBUG)
- if(p_allocated != NULL)
- {
- ASSERT (p_allocated->Lno == 0);
- ASSERT (p_allocated->Fname == 0);
- p_allocated->Lno = Line;
- p_allocated->Fname = (char FAR *) FileName;
- }
- #endif
- return p_allocated;
- }
- #endif
-
- void FAR * MemoryObject::operator new (size_t size)
- // standard operator new, used for derived classes.
- {return new (size) MemoryObject;}
-
- void FAR * MemoryObject::operator new
- (size_t /*std_size */, size_t size)
- // Extended operator new, used by AllocateBlock and
- // standard operator new
- {
- FP_FHB allocated_block;
- FP_MOBJECT first_fit = FindFreeSpace (size,
- allocated_block);
- if (first_fit == NULL)
- {
- // Unable to satisfy request, raise memory
- // exception
- _PNH handler = _set_new_handler (0);
- // Get current new handler and restore it
- _set_new_handler (handler);
- (* handler) (size); // call the handler
- // Fail regardless of value returned by the handler
- return NULL;
- }
-
- __segment cur_seg = (__segment) SELECTOROF (first_fit);
-
- // We now have a pointer to a free object which
- // satisfies our request. We need to split it so
- // that we get the amount we want, and the rest
- // stays in the free list
- ASSERT (AfxIsValidAddress (first_fit,
- sizeof (MemoryObject)));
- ASSERT (first_fit->flags == unallocated);
- unsigned int total_block_size = size;
- // Allocate in units of DWORDs
- total_block_size = ((total_block_size + 3) >> 2) << 2;
- if (first_fit->mo_block_size <
- total_block_size + sizeof (MemoryObject))
- {
- // We need to have space for this block plus at
- // least another MemoryObject. Not enough space
- // to split the block, so do not, just unchain
- // from free list
- if (first_fit->prev_mo != NULL)
- (cur_seg:>first_fit->prev_mo)->next_mo =
- first_fit->next_mo;
- else
- // This is the first block in the free list
- allocated_block->free_list =
- first_fit->next_mo;
- if (first_fit->next_mo != NULL)
- (cur_seg:>first_fit->next_mo)->prev_mo =
- first_fit->prev_mo;
- else // This is the last block in the list
- allocated_block->end_free_list =
- first_fit->prev_mo;
- }
- else
- {
- FP_MOBJECT new_free =
- (FP_MOBJECT) ((DWORD) first_fit +
- total_block_size);
- // Convert first_fit to DWORD, to increment by
- // units of bytes rather then MemoryObjects
- ASSERT (AfxIsValidAddress (new_free,
- sizeof (MemoryObject)));
- new_free->my_heap_block = first_fit->my_heap_block;
- new_free->prev_mo = first_fit->prev_mo;
- new_free->next_mo = first_fit->next_mo;
- new_free->mo_block_size =
- first_fit->mo_block_size - total_block_size;
- new_free->SetAllocationFlag (unallocated);
- first_fit->mo_block_size = total_block_size;
- if (first_fit->prev_mo != NULL)
- (cur_seg:>first_fit->prev_mo)->next_mo =
- MO_BASED_VOID_FROM_LP (new_free);
- else // This is the first block in the list
- allocated_block->free_list =
- MO_BASED_VOID_FROM_LP (new_free);
- if (first_fit->next_mo != NULL)
- (cur_seg:>first_fit->next_mo)->prev_mo =
- MO_BASED_VOID_FROM_LP (new_free);
- else //This is the last block in the list
- allocated_block->end_free_list =
- MO_BASED_VOID_FROM_LP (new_free);
- }
-
- // We have removed the allocated block from the free
- // list, so we need to add it to the in-use list
- if (allocated_block->in_use_list == NULL)
- // This is the first block to be allocated
- {
- allocated_block->in_use_list =
- allocated_block->end_in_use_list =
- MO_BASED_VOID_FROM_LP (first_fit);
- }
- else
- // Scan through the in-use list to insert the
- // block in address order
- {
- FP_MOBJECT p_mo =
- cur_seg:>allocated_block->in_use_list;
- while (OFFSETOF (p_mo) != NULL)
- if (first_fit > p_mo) p_mo =
- cur_seg:>p_mo->next_mo;
- else break;
- // Now insert first_fit before p_mo
- first_fit->next_mo = MO_BASED_VOID_FROM_LP (p_mo);
- if (OFFSETOF (p_mo) == NULL)
- {
- // We have reached the end of the list, so
- // insert here
- #if defined (_DEBUG)
- // For easy display in the MSVC Debugger
- // Locals window
- FP_MOBJECT trace1 =
- cur_seg:>allocated_block->end_in_use_list;
- #endif
- (cur_seg:>allocated_block->end_in_use_list)
- ->next_mo
- = MO_BASED_VOID_FROM_LP (first_fit);
- first_fit->prev_mo =
- allocated_block->end_in_use_list;
- allocated_block->end_in_use_list =
- MO_BASED_VOID_FROM_LP (first_fit);
- }
- else
- {
- ASSERT (AfxIsValidAddress (p_mo,
- sizeof (MemoryObject)));
- first_fit->prev_mo = p_mo->prev_mo;
- if (p_mo->prev_mo == NULL)
- // This is the first block
- allocated_block->in_use_list =
- MO_BASED_VOID_FROM_LP (first_fit);
- else
- (cur_seg:>p_mo->prev_mo)->next_mo =
- MO_BASED_VOID_FROM_LP (first_fit);
- p_mo->prev_mo =
- MO_BASED_VOID_FROM_LP (first_fit);
- }
- }
- #if defined (_DEBUG)
- first_fit->Lno = 0;
- first_fit->Fname = NULL;
- #endif
- return first_fit;
- }
-
- void MemoryObject::operator delete (void FAR * p_void)
- {
- FP_MOBJECT p_mo = (FP_MOBJECT) p_void;
- ASSERT (AfxIsValidAddress (p_mo,
- sizeof (MemoryObject)));
- FP_FHB this_block = FarHeapBlock::GetHbFromHandle
- (p_mo->my_heap_block);
- if (this_block == NULL)
- {
- // Unable to access block, raise memory exception
- // in non-debug build
- AfxThrowMemoryException();
- return;
- }
-
- __segment cur_seg = (__segment) SELECTOROF (p_void);
-
- #if defined (_DEBUG)
- // For debugging purposes only. Makes it much
- // easier to watch variables if we use full
- // addressing rather than segment-based
- // addressing
- FP_MOBJECT p_prev_object = cur_seg:>p_mo->prev_mo;
- FP_MOBJECT p_next_object = cur_seg:>p_mo->next_mo;
- #endif
-
- // First, unlink this block from the in-use list
- if (p_mo->prev_mo != NULL)
- // Point the previous block at the next block
- (cur_seg:>p_mo->prev_mo)->next_mo = p_mo->next_mo;
- else
- {
- // This is the first block in the list
- // Check that the management structures also
- // think that it is the first block in the list
- ASSERT (OFFSETOF (p_mo) ==
- (WORD) (this_block->in_use_list));
- // The first block will now be the next block
- this_block->in_use_list = p_mo->next_mo;
- }
-
- if (p_mo->next_mo != NULL)
- // Set the next block to point to the previous
- // block
- (cur_seg:>p_mo->next_mo)->prev_mo = p_mo->prev_mo;
- else
- {
- // This is the last block in the list
- // Check that the management structures also
- // think that it is the last block in the list
- ASSERT (OFFSETOF (p_mo) ==
- (WORD) (this_block->end_in_use_list));
- this_block->end_in_use_list = p_mo->prev_mo;
- }
-
- // Now chain the block back into the list of free
- // blocks,
- if (this_block->free_list == NULL)
- {
- // The free list is currently empty
- // Check that the management structures also
- // think that it is free
- ASSERT (this_block->end_free_list == NULL);
- this_block->free_list =
- this_block->end_free_list =
- MO_BASED_VOID_FROM_LP (p_mo);
- p_mo->next_mo = p_mo->prev_mo = NULL;
- }
- else
- {
- FP_MOBJECT insert_point =
- cur_seg:>this_block->free_list;
- // Starting at the beginning, scan through
- // the free list to find the insertion point.
- // Insert in memory order
- while (OFFSETOF (insert_point) != NULL &&
- insert_point < p_mo)
- insert_point = cur_seg:>insert_point->next_mo;
-
- if (OFFSETOF (insert_point) == NULL)
- { // insert at the end of the list
- ASSERT ((cur_seg:>this_block->end_free_list)
- ->next_mo == NULL);
- (cur_seg:>this_block->end_free_list)->next_mo
- = MO_BASED_VOID_FROM_LP (p_mo);
- p_mo->prev_mo = this_block->end_free_list;
- p_mo->next_mo = NULL;
- this_block->end_free_list =
- MO_BASED_VOID_FROM_LP (p_mo);
- }
- else
- {
- // Insert the block before insert_point
- ASSERT (AfxIsValidAddress (insert_point,
- sizeof (MemoryObject)));
- ASSERT (AfxIsValidAddress (p_mo,
- sizeof (MemoryObject)));
- p_mo->next_mo =
- MO_BASED_VOID_FROM_LP (insert_point);
- p_mo->prev_mo = insert_point->prev_mo;
- if (insert_point->prev_mo == NULL)
- {
- // p_mo to be the new first free block
- ASSERT (insert_point ==
- cur_seg:>this_block->free_list);
- this_block->free_list =
- MO_BASED_VOID_FROM_LP (p_mo);
- }
- else
- (cur_seg:>insert_point->prev_mo)->next_mo
- = MO_BASED_VOID_FROM_LP (p_mo);
- insert_point->prev_mo =
- MO_BASED_VOID_FROM_LP (p_mo);
- }
- }
-
- // Now see whether it is possible to compact the
- // inserted block with either (or both) of the
- // adjacent blocks. First, can we combine it with
- // the previous block?
- if (p_mo->prev_mo != NULL)
- {
- if ((DWORD) p_mo == (DWORD)(cur_seg:>p_mo->prev_mo)
- + (cur_seg:>p_mo->prev_mo)->mo_block_size)
- { // Compact with the previous block
- (cur_seg:>p_mo->prev_mo)->next_mo =
- p_mo->next_mo;
- if (p_mo->next_mo == NULL)
- { // This was the last block in the list
- ASSERT (cur_seg:>this_block->end_free_list
- == p_mo);
- this_block->end_free_list = p_mo->prev_mo;
- }
- else
- (cur_seg:>p_mo->next_mo)->prev_mo =
- p_mo->prev_mo;
- (cur_seg:>p_mo->prev_mo)->mo_block_size +=
- p_mo->mo_block_size;
- // Finally, as the block has been combined
- // with the one before, set the pointer to
- // that block
- p_mo = cur_seg:>p_mo->prev_mo;
- }
- }
- // Can we combine it with the next block
- if (p_mo->next_mo != NULL)
- {
- if ((DWORD) p_mo + p_mo->mo_block_size ==
- (DWORD) (cur_seg:>p_mo->next_mo))
- { // Compact with the next block
- p_mo->mo_block_size +=
- (cur_seg:>p_mo->next_mo)->mo_block_size;
- if ((cur_seg:>p_mo->next_mo)->next_mo == NULL)
- {
- // Next block is the last block in list
- ASSERT (this_block->end_free_list ==
- p_mo->next_mo);
- this_block->end_free_list =
- MO_BASED_VOID_FROM_LP (p_mo);
- }
- else
- (cur_seg:>(cur_seg:>p_mo->next_mo)
- ->next_mo)->prev_mo =
- MO_BASED_VOID_FROM_LP (p_mo);
- p_mo->next_mo =
- (cur_seg:>p_mo->next_mo)->next_mo;
- }
- }
-
- // Finally, see if the FarHeapBlock is empty.
- // If so, return it to Windows
- if (this_block->in_use_list == NULL)
- { // The block is empty, return it to Windows
- ASSERT (this_block->end_in_use_list == NULL);
- delete this_block;
- }
- }
-
- MemoryObject::MemoryObject ()
- {
- #if defined (_DEBUG)
- flags = allocated;
- _fstrcpy (validity_tag, validity_tag_value);
- #endif
- }
-
- MemoryObject::~MemoryObject ()
- {
- #if defined (_DEBUG)
- if (_fstrcmp (validity_tag, validity_tag_value)
- != 0)
- {
- TRACE0 ("MemoryObject::~MemoryObject() "
- "attempting to delete an object with "
- "an invalid tag!\n");
- ASSERT (FALSE);
- }
- flags = unallocated;
- #endif
- }
-
- inline FP_MOBJECT MemoryObject::FindFreeSpace
- (size_t size, FP_FHB & block_allocated)
- {
- // As this routine is only called once, from
- // MemoryObject::new, it is declared as 'inline' for
- // efficiency and speed
-
- // First check that the requested size is within
- // limits. We cannot allocate a block that is bigger
- // that a FarHeapBlock less overheads.
- ASSERT (block_allocated->DefaultSize () >
- sizeof (FarHeapBlock) + sizeof(MemoryObject));
- if (size + sizeof (FarHeapBlock) +
- sizeof (MemoryObject) > block_allocated->DefaultSize ())
- {
- TRACE ("MemoryObject::FindFreeSpace cannot "
- "allocate requested space\n");
- ASSERT (FALSE);
- return NULL;
- }
-
- if (FarHeapBlock::IsEmpty ())
- {
- // No FarHeapBlocks in existance at the moment,
- // so create one.
- FarHeapBlock FAR * p_fhb = new FarHeapBlock;
- // We do not need to keep this pointer, as it is
- // automatically inserted into the list of
- // FarHeapBlocks
- }
-
- FHB_POSITION p = FarHeapBlock::GetHeadPosition ();
- BOOL free_space_found = FALSE;
- do {
- FP_FHB p_fhb = FarHeapBlock::GetNext (p);
- __segment cur_seg = (__segment) SELECTOROF (p_fhb);
- FP_MOBJECT current_free =
- cur_seg:>p_fhb->free_list;
- while (OFFSETOF (current_free) != NULL)
- {
- ASSERT (AfxIsValidAddress (current_free,
- sizeof (MemoryObject)));
- if(current_free->mo_block_size >
- size + sizeof (MemoryObject))
- {
- block_allocated = p_fhb;
- return current_free;
- }
- else
- current_free =
- cur_seg:>current_free->next_mo;
- }
- // If we come out of the bottom of this while
- // loop, we did not find a large-enough
- // MemoryObject block in this FarHeapBlock.
- // So try the next block
- }
- while (p != NULL);
- // If we fall out of the bottom of this loop, then
- // we did not find anything in the current list of
- // blocks, so create a new one (new will
- // automatically chain it into the list of existing
- // FarHeapBlocks
-
- block_allocated = new FarHeapBlock;
- __segment new_seg =
- (__segment) SELECTOROF (block_allocated);
- return new_seg:>block_allocated->free_list;
- }
-
- void FAR * MemoryObject::AllocateBlock
- (int required_size)
- {
- MemoryObject * p_new_obj
- = new (required_size +
- sizeof(MemoryObject)) MemoryObject;
- // We need to return a pointer to the required block,
- // so step over the CMemoryObject header provided it
- // is not NULL (ie no error has occurred)
- return p_new_obj != NULL
- ? ++p_new_obj
- : NULL;
- }
-
- void MemoryObject::ReturnBlock (void FAR * p_block)
- {
- MemoryObject * p_old_obj = (MemoryObject *) p_block;
- // Get the MemoryObject header and delete it.
- delete --p_old_obj;
- }
-
- void MemoryObject::PrintHeapReport (ostream & fout,
- char * msg)
- {
- #pragma warning (disable: 4270)
- // Stop unwanted warning from iomanip.h
- fout << hex;
- fout << "Singleton's Heap Reporter";
- if (msg != NULL)
- fout << " - " << msg;
- fout << endl << endl;
-
- fout << "FarHeapBlock::first_fhb = "
- << FarHeapBlock::first_fhb
- << ", last_fhb = " << FarHeapBlock::last_fhb
- << endl;
-
- if (!FarHeapBlock::IsEmpty ())
- { // Summarise heap details
- FHB_POSITION p = FarHeapBlock::GetHeadPosition ();
- int heap_block_count = 0;
- fout << endl << "Heap Block Summary" << endl
- << endl;
- char * titles [] = {"MY_HG", "PREV_HG", "NEXT_HG",
- "SIZE", "FST_FR", "LST_FR",
- "FST_USE", "LST_USE"};
- int col_widths [] = {6, 8, 8, 6, 9, 9, 9, 9};
- int no_of_cols = sizeof (col_widths) /
- sizeof (col_widths [1]);
- for (int i = 0; i < no_of_cols; i++)
- fout << setiosflags (ios::right)
- << setw (col_widths [i])
- << titles [i];
- fout << endl;
- while (p != NULL)
- {
- FP_FHB p_fhb = FarHeapBlock::GetNext (p);
- for (int i = 0; i < no_of_cols; i++)
- {
- fout << setiosflags (ios::right)
- << setw (col_widths [i]);
- switch (i)
- {
- case 0: fout << p_fhb->my_hglobal; break;
- case 1:
- fout << p_fhb->previous_hglobal;
- break;
- case 2:
- fout << p_fhb->next_hglobal; break;
- case 3:
- fout << p_fhb->Size (); break;
- case 4:
- fout << (WORD) p_fhb->free_list;
- break;
- case 5:
- fout << (WORD) p_fhb->end_free_list;
- break;
- case 6:
- fout << (WORD) p_fhb->in_use_list;
- break;
- case 7:
- fout << (WORD) p_fhb->end_in_use_list;
- break;
- default: ASSERT (FALSE);
- }
- }
- fout << endl;
- heap_block_count++;
- }
-
- // Now output the details for the individual
- // heap blocks
- p = FarHeapBlock::GetHeadPosition ();
- for (int block_count = 0;
- block_count < heap_block_count;
- block_count++)
- {
- FP_FHB p_fhb = FarHeapBlock::GetNext (p);
- fout << endl
- << "Heap Block Details for block "
- << block_count << ", HGLOB = " << p
- << ", base = " << (DWORD) p_fhb
- << endl << endl;
- char * btitles [] = {"BASE", "SIZE", "FLAGS",
- "PREV", "NEXT"};
- int bwidths [] = {8, 8, 8, 9, 9};
- int no_of_bcols = sizeof(bwidths) /
- sizeof (bwidths [0]);
- for (int i = 0; i < no_of_bcols; i++)
- fout << setiosflags (ios::right)
- << setw (bwidths [i])
- << btitles [i];
- fout << endl;
- // First print the free list
- if (p_fhb->free_list != NULL)
- {
- __segment cur_seg =
- (__segment) SELECTOROF (p_fhb);
- FP_MOBJECT p_mo =
- cur_seg:>p_fhb->free_list;
- while (OFFSETOF (p_mo) != NULL)
- {
- ASSERT (AfxIsValidAddress (p_mo,
- sizeof (MemoryObject)));
- for (int i = 0; i < no_of_bcols; i++)
- {
- fout << setiosflags (ios::right)
- << setw (bwidths [i]);
- switch (i)
- {
- case 0:
- fout << (DWORD) p_mo; break;
- case 1:
- fout << p_mo->mo_block_size;
- break;
- case 2:
- #if defined (_DEBUG)
- fout << p_mo->flags;
- #else
- fout << 0;
- #endif
- break;
- case 3:
- fout << (WORD) p_mo->prev_mo;
- break;
- case 4:
- fout << (WORD) p_mo->next_mo;
- break;
- case 5: break;
- default: ASSERT (FALSE);
- }
- }
- fout << endl;
- p_mo = cur_seg:>p_mo->next_mo;
- }
- }
- else fout << "Free list is empty" << endl;
-
- // Now print the in-use list
- if (p_fhb->in_use_list != NULL)
- {
- __segment cur_seg =
- (__segment) SELECTOROF (p_fhb);
- FP_MOBJECT p_mo =
- cur_seg:>p_fhb->in_use_list;
- while (OFFSETOF (p_mo) != NULL)
- {
- ASSERT (AfxIsValidAddress (p_mo,
- sizeof (MemoryObject)));
- for (int i = 0; i < no_of_bcols; i++)
- {
- fout << setiosflags (ios::right)
- << setw (bwidths [i]);
- switch (i)
- {
- case 0:
- fout << (DWORD) p_mo; break;
- case 1:
- fout << p_mo->mo_block_size;
- break;
- case 2:
- #if defined (_DEBUG)
- fout << p_mo->flags;
- #else
- fout << 0;
- #endif
- break;
- case 3:
- fout << (WORD) p_mo->prev_mo;
- break;
- case 4:
- fout << (WORD) p_mo->next_mo;
- break;
- case 5: break;
- default: ASSERT (FALSE);
- }
- }
- fout << endl;
- p_mo = cur_seg:>p_mo->next_mo;
- }
- }
- else fout << "In use list is empty" << endl;
-
- fout << endl;
- }
- }
- #pragma warning (default: 4270)
- }
-
- BOOL MemoryObject::MemoryHeapIsEmpty ()
- {return FarHeapBlock::IsEmpty ();}
-
- int MemoryObject::MemoryHeapInUseCount ()
- {
- if (FarHeapBlock::IsEmpty ())
- return 0;
-
- int usage_count = 0;;
- FHB_POSITION p = FarHeapBlock::GetHeadPosition ();
- while (p != NULL)
- {
- FP_FHB p_fhb = FarHeapBlock::GetNext (p);
- ASSERT(p_fhb->in_use_list != NULL);
- // NULL blocks should have been returned to
- // Windows
- __segment cur_seg = (__segment) SELECTOROF (p_fhb);
- FP_MOBJECT p_mo = cur_seg:>p_fhb->in_use_list;
- while (OFFSETOF (p_mo) != NULL)
- {
- ASSERT (AfxIsValidAddress (p_mo,
- sizeof (MemoryObject)));
- usage_count++;
- p_mo = cur_seg:>p_mo->next_mo;
- }
- }
- return usage_count;
- }
-
- int MemoryObject::HeapBlockInUseCount ()
- {return FarHeapBlock::GetCount ();}
-
- void MemoryObject::SetAllocationFlag (int flag_val)
- {
- #if defined (_DEBUG)
- flags = flag_val;
- #endif
- }
-
- void MemoryObject::SetFirstMemoryObject(HGLOBAL hglob,
- unsigned size)
- {
- my_heap_block = hglob;
- prev_mo = NULL;
- next_mo = NULL;
- mo_block_size = size;
- SetAllocationFlag (unallocated);
- }
-
- #if defined (_DEBUG)
- void MemoryObject::DumpAllObjects ()
- {
- if (FarHeapBlock::IsEmpty ())
- return;
-
- FHB_POSITION p = FarHeapBlock::GetHeadPosition ();
- while (p != NULL)
- {
- FP_FHB p_fhb = FarHeapBlock::GetNext (p);
- ASSERT(p_fhb->in_use_list != NULL);
- // NULL blocks should have been returned to
- // Windows
- __segment cur_seg = (__segment) SELECTOROF (p_fhb);
- FP_MOBJECT p_mo = cur_seg:>p_fhb->in_use_list;
- while (OFFSETOF (p_mo) != NULL)
- {
- ASSERT (AfxIsValidAddress (p_mo,
- sizeof (MemoryObject)));
- TRACE1 ("MemoryObject, size %d, ",
- p_mo->mo_block_size);
- if (p_mo->Lno == 0)
- TRACE0 ("no location details\n");
- else
- TRACE2 ("allocated at line %d of %s\n",
- p_mo->Lno, p_mo->Fname);
- p_mo = cur_seg:>p_mo->next_mo;
- }
- }
-
- }
- #endif
-