00001 #include <memory_manager.hpp>
00002 #include <gc++.hpp>
00003 #include <common.hpp>
00004 #include <VERSION>
00005 #include <algorithm>
00006 #include <cassert>
00007 #include <cstdlib>
00008 #include <numeric>
00009 #include <detail/gc++.hpp>
00010 #include <boost/bind.hpp>
00011
00012 using namespace GCpp;
00013 using namespace std;
00014
00015 namespace
00016 {
00017
00018 GCPP_MUTEX global_gc_mutex;
00019
00020 struct BlockHeader
00021 {
00022 MemoryAllocatorBase* allocator;
00023 BlockHeader* next;
00024 bool mark;
00025
00026 BlockHeader (MemoryAllocatorBase* p_allocator)
00027 : allocator (p_allocator),
00028 mark (true)
00029 {}
00030 };
00031
00032 inline
00033 BlockHeader* EXTRACT_HEADER (void* p_data)
00034 {
00035 return reinterpret_cast<BlockHeader*> (static_cast<Byte*> (p_data) - sizeof (BlockHeader));
00036 }
00037
00038 inline
00039 void* OBJECT (void* p_data)
00040 {
00041 return static_cast<Byte*>(p_data) + sizeof (BlockHeader);
00042 }
00043
00044 inline
00045 GCBasePointer* CALC_POINTER (void* p_data, size_t p_offset)
00046 {
00047 return reinterpret_cast<GCBasePointer*> (static_cast<Byte*> (p_data) + p_offset);
00048 }
00049
00050 typedef size_t (MemoryAllocatorBase::*SumMember) ();
00051
00052 struct Sum : binary_function<size_t, MemoryAllocatorBase*, size_t>
00053 {
00054 SumMember f_sum;
00055
00056 Sum (SumMember p_sum)
00057 : f_sum (p_sum)
00058 {}
00059
00060 size_t operator() (size_t p_value, MemoryAllocatorBase* p_item)
00061 {
00062 return p_value + (p_item->*f_sum) ();
00063 }
00064 };
00065
00066 const Byte analyzed_tag = 0x01;
00067 const Byte assured_tag = 0x02;
00068
00069 }
00070
00071 MemoryAllocatorBase::MemoryAllocatorBase (size_t p_block_size)
00072 : FixedSizeAllocator (p_block_size + sizeof (BlockHeader)),
00073 f_status (0),
00074 f_destroyed (0),
00075 f_allocated (0),
00076 f_blocks (0)
00077 {
00078 GC::f_allocators.push_back (this);
00079 }
00080
00081 MemoryAllocatorBase::~MemoryAllocatorBase ()
00082 {
00083 GC::f_allocators.remove (this);
00084 }
00085
00086 void MemoryAllocatorBase::analyze (void* p_block)
00087 {
00088 Byte* org (static_cast<Byte*> (p_block));
00089 Byte* ptr (org);
00090 int lmt (block_size () - sizeof (void*) - sizeof (BlockHeader));
00091
00092 while (ptr - org < lmt)
00093 {
00094 if (GCPointerManager::is_pointer (ptr))
00095 {
00096 f_offsets.push_back (ptr - org);
00097 ptr += sizeof (void*);
00098 }
00099 else
00100 ++ptr;
00101 }
00102
00103 f_status |= analyzed_tag;
00104 }
00105
00106 void MemoryAllocatorBase::mark_contained_pointers (void* p_block)
00107 {
00108 if (f_status % 2 == 0)
00109 analyze (p_block);
00110
00111 vector<size_t>::iterator itr (f_offsets.begin ());
00112 vector<size_t>::iterator end (f_offsets.end ());
00113
00114 vector<size_t> err;
00115
00116 for (; itr != end; ++itr)
00117 {
00118 GCBasePointer* ptr (CALC_POINTER (p_block, *itr));
00119
00120
00121
00122
00123 if (f_status & assured_tag or GCPointerManager::is_pointer (ptr))
00124 static_cast<GCBasePointer*> (ptr)->mark ();
00125 else
00126 err.push_back (*itr);
00127 }
00128
00129 if (not err.empty ())
00130 {
00131 vector<size_t>::iterator rtr (err.begin ());
00132 vector<size_t>::iterator rnd (err.end ());
00133
00134 for (; rtr != rnd; ++rtr)
00135 f_offsets.erase (remove (f_offsets.begin (), f_offsets.end (), *rtr), f_offsets.end ());
00136 }
00137 }
00138
00139 void MemoryAllocatorBase::sweep ()
00140 {
00141 BlockHeader* hdr (static_cast<BlockHeader*>(f_blocks));
00142 f_blocks = 0;
00143 size_t dst (0);
00144
00145 while (hdr)
00146 {
00147 assert (hdr->allocator == this);
00148 BlockHeader* del (hdr);
00149
00150 if (not hdr->mark)
00151 {
00152 hdr = hdr->next;
00153 f_destroy_item (OBJECT (del));
00154 del->allocator = 0;
00155 free (del);
00156 ++dst;
00157 }
00158 else
00159 {
00160 hdr->mark = false;
00161 hdr = hdr->next;
00162 del->next = static_cast<BlockHeader*>(f_blocks);
00163 f_blocks = del;
00164 }
00165 }
00166
00167 f_destroyed += dst;
00168 f_status |= assured_tag;
00169 }
00170
00171 void MemoryAllocatorBase::unmark ()
00172 {
00173 BlockHeader* hdr (static_cast<BlockHeader*>(f_blocks));
00174
00175 while (hdr)
00176 {
00177 assert (hdr->allocator == this);
00178 hdr->mark = false;
00179 hdr = hdr->next;
00180 }
00181 }
00182
00183 void* MemoryAllocatorBase::malloc ()
00184 {
00185 GCPP_LOCK mlc (global_gc_mutex);
00186
00187 Byte* dat (GC::stopped () ? static_cast<Byte*> (FixedSizeAllocator::malloc ()) : static_cast<Byte*> (internal_malloc ()));
00188
00189 if (dat == 0)
00190 {
00191 size_t old (f_destroyed);
00192
00193 GC::internal_collect ();
00194
00195 if (old != f_destroyed)
00196 dat = static_cast<Byte*> (internal_malloc ());
00197 else
00198 {
00199 dat = static_cast<Byte*> (internal_add_block ());
00200 GC::f_threshold += GC::f_threshold / 4;
00201 }
00202 }
00203
00204 BlockHeader* blk (new (dat) BlockHeader (this));
00205 blk->next = static_cast<BlockHeader*> (f_blocks);
00206 f_blocks = blk;
00207
00208 ++f_allocated;
00209
00210 return OBJECT (dat);
00211 }
00212
00213 void* MemoryAllocatorBase::confirm (void* p_storage)
00214 {
00215 BlockHeader* hdr (EXTRACT_HEADER (p_storage));
00216
00217 if (hdr->allocator == this)
00218 return p_storage;
00219
00220 return 0;
00221 }
00222
00223 bool GC::f_stop (false);
00224 size_t GC::f_allocated (0);
00225 size_t GC::f_threshold (50000000);
00226 IntrusiveList<MemoryAllocatorBase> GC::f_allocators;
00227
00228 void GC::start ()
00229 {
00230 f_stop = false;
00231 }
00232
00233 void GC::stop ()
00234 {
00235 f_stop = true;
00236 }
00237
00238 void GC::mark (void* p_block)
00239 {
00240 if (not static_cast<GCBasePointer*> (p_block)->is_contained ())
00241 static_cast<GCBasePointer*> (p_block)->mark ();
00242 }
00243
00244 void GC::mark_recursively (void* p_pointer)
00245 {
00246 GCBasePointer* ptr (static_cast<GCBasePointer*> (p_pointer));
00247
00248 if (ptr->storage ())
00249 {
00250 BlockHeader* hdr (EXTRACT_HEADER (ptr->storage ()));
00251
00252
00253 if (hdr->mark)
00254 return;
00255
00256 hdr->mark = true;
00257 hdr->allocator->mark_contained_pointers (ptr->storage ());
00258 }
00259 }
00260
00261 void GC::internal_collect ()
00262 {
00263 if (f_allocated < f_threshold)
00264 return;
00265
00266 if (not f_stop)
00267 {
00268 for_each (GCPointerManager::begin (), GCPointerManager::end (), mark);
00269 for_each (f_allocators.begin (), f_allocators.end (), boost::bind (&MemoryAllocatorBase::sweep, _1));
00270 }
00271 }
00272
00273 void GC::collect ()
00274 {
00275 GCPP_LOCK lck (global_gc_mutex);
00276
00277 bool old (f_stop);
00278 f_stop = false;
00279 size_t alc (f_allocated);
00280 f_allocated = f_threshold;
00281
00282 for_each (f_allocators.begin (), f_allocators.end (), boost::bind (&MemoryAllocatorBase::unmark, _1));
00283 internal_collect ();
00284
00285 f_stop = old;
00286 f_allocated = alc;
00287 }
00288
00289 bool GC::stopped ()
00290 {
00291 return f_stop;
00292 }
00293
00294 size_t GC::destroyed ()
00295 {
00296 Sum sum (&MemoryAllocatorBase::destroyed);
00297 return accumulate (f_allocators.begin (), f_allocators.end (), 0, sum);
00298 }
00299
00300 size_t GC::allocated ()
00301 {
00302 Sum sum (&MemoryAllocatorBase::allocated);
00303 return accumulate (f_allocators.begin (), f_allocators.end (), 0, sum);
00304 }
00305
00306 string GC::version ()
00307 {
00308 return string (VERSION_STRING);
00309 }
00310
00311 size_t GC::in_use ()
00312 {
00313 return f_allocated;
00314 }
00315
00316 size_t GC::threshold ()
00317 {
00318 return f_threshold;
00319 }
00320
00321 void GC::compact (bool p_new_limit)
00322 {
00323 GCPP_LOCK lck (global_gc_mutex);
00324 for_each (f_allocators.begin (), f_allocators.end (), boost::bind (&MemoryAllocatorBase::compact, _1));
00325
00326 if (p_new_limit)
00327 f_threshold = max (f_allocated, static_cast<size_t> (50000000));
00328 }
00329
00330 void GC::finalize ()
00331 {
00332 size_t old;
00333
00334 do
00335 {
00336 old = GC::destroyed ();
00337 GC::collect ();
00338 } while (GC::destroyed () > old);
00339 }
00340
00341 Byte* GCpp::OS_malloc (size_t p_size)
00342 {
00343 Byte* ret (static_cast<Byte*> (::malloc (p_size + sizeof (size_t))));
00344 *reinterpret_cast<size_t*> (ret) = p_size;
00345 GC::f_allocated += p_size;
00346 return ret + sizeof (size_t);
00347 }
00348
00349 void GCpp::OS_free (Byte* p_block)
00350 {
00351 Byte* blk (p_block - sizeof (size_t));
00352 GC::f_allocated-= *reinterpret_cast<size_t*> (blk);
00353 ::free (blk);
00354 }