neverFreeMemory.cxx
00001 // Filename: neverFreeMemory.cxx
00002 // Created by:  drose (14Jun07)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "neverFreeMemory.h"
00016 #include "atomicAdjust.h"
00017 #include "memoryHook.h"
00018 
00019 NeverFreeMemory * TVOLATILE NeverFreeMemory::_global_ptr;
00020 
00021 // If a page has fewer than this many bytes remaining, never mind
00022 // about it.
00023 static const size_t min_page_remaining_size = 16;
00024 
00025 // We always allocate at least this many bytes at a time.
00026 static const size_t min_page_size = 128 * 1024;  // 128K
00027 
00028 ////////////////////////////////////////////////////////////////////
00029 //     Function: NeverFreeMemory::Constructor
00030 //       Access: Private
00031 //  Description: 
00032 ////////////////////////////////////////////////////////////////////
00033 NeverFreeMemory::
00034 NeverFreeMemory() {
00035   _total_alloc = 0;
00036   _total_used = 0;
00037 }
00038 
00039 ////////////////////////////////////////////////////////////////////
00040 //     Function: NeverFreeMemory::ns_alloc
00041 //       Access: Private
00042 //  Description: 
00043 ////////////////////////////////////////////////////////////////////
00044 void *NeverFreeMemory::
00045 ns_alloc(size_t size) {
00046   _lock.acquire();
00047 
00048   // We always allocate integer multiples of this many bytes, to
00049   // guarantee this minimum alignment.
00050   static const size_t alignment_size = MemoryHook::get_memory_alignment();
00051 
00052   // Round up to the next alignment_size.
00053   size = ((size + alignment_size - 1) / alignment_size) * alignment_size;
00054 
00055   _total_used += size;
00056   
00057   // Look for a page that has sufficient space remaining.
00058 
00059   Pages::iterator pi = _pages.lower_bound(Page(NULL, size));
00060   if (pi != _pages.end()) {
00061     // Here's a page with enough remaining space.
00062     Page page = (*pi);
00063     _pages.erase(pi);
00064     void *result = page.alloc(size);
00065     if (page._remaining >= min_page_remaining_size) {
00066       _pages.insert(page);
00067     }
00068     _lock.release();
00069     return result;
00070   }
00071 
00072   // We have to allocate a new page.  Allocate at least min_page_size
00073   // bytes, and then round that up to the next _page_size bytes.
00074   size_t needed_size = max(size, min_page_size);
00075   needed_size = memory_hook->round_up_to_page_size(needed_size);
00076   void *start = memory_hook->mmap_alloc(needed_size, false);
00077   _total_alloc += needed_size;
00078 
00079   Page page(start, needed_size);
00080   void *result = page.alloc(size);
00081   if (page._remaining >= min_page_remaining_size) {
00082     _pages.insert(page);
00083   }
00084   _lock.release();
00085   return result;
00086 }
00087 
00088 ////////////////////////////////////////////////////////////////////
00089 //     Function: NeverFreeMemory::make_global_ptr
00090 //       Access: Private, Static
00091 //  Description: 
00092 ////////////////////////////////////////////////////////////////////
00093 void NeverFreeMemory::
00094 make_global_ptr() {
00095   NeverFreeMemory *ptr = new NeverFreeMemory;
00096   void *result = AtomicAdjust::compare_and_exchange_ptr
00097     ((void * TVOLATILE &)_global_ptr, (void *)NULL, (void *)ptr);
00098   if (result != NULL) {
00099     // Someone else got there first.
00100     delete ptr;
00101   }
00102 }
00103