2005/5/9

     
 

Allocator.h

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_core/src/acdk/lang/sys/Allocator.h,v 1.21 2005/02/05 10:44:59 kommer Exp $
#ifndef acdk_lang_sys_Allocator_h
#define acdk_lang_sys_Allocator_h

#include <acdk.h>
#include "core_string.h"
#include "core_fastmutex.h"
#include "SysRefHolder.h"

namespace acdk {
  namespace lang {
  namespace ref {
  class NotifyObjectEventListener;
  } // namespace ref
  } // namespace lang
} // namespace acdk




namespace acdk {
namespace lang {
namespace sys {


foreign struct AllocTypeInfo
{
  int count;
  int size;
};

/**
  information about the given allocator
*/
foreign
enum AllocatorTypeFlags
{
  StandardAllocatorType   = 0x0000,
  /**
    if this is true, allocated
    acdk::lang::Object should threaded as stack object.
    References to stack object aren't synchronized
  */
  StackObjectAllocatorType      = 0x0001,
  
  /**
    Allocator support listing objects
  */
  SupportListObjectAllocatorType = 0x0004,
  /**
    Allocator itself doesn't need synchronization
  */  
  NoSyncAllocatorType           = 0x0008,
  /**
    Allocator doesn't rely on RefHolders reference counting
  */
  NoRefCountAllocatorType       = 0x0010,
  /**
    Allocator support / needs manual garbage collecting
    calling gc()
  */
  ManualGcAllocatorType   =       0x0020,
  /**
    Automatic gc 
  */
  AutoGcAllocatorType           = 0x0040
};

foreign class ACDK_CORE_PUBLIC AllocatorInfo
{
public:
  core_string name;
  AllocTypeInfo memTypes[MaxAllocatedType + 1];
  
  AllocatorInfo(const core_string& n)
  :  name(n)
  {
    memset(memTypes, 0, sizeof(memTypes));
  }
};

ACDK_DECL_SYS_CLASS(Allocator);


/**
  uses by Allocator
*/
foreign struct MemChunkHeader
{
  Allocator* allocator;
  size_t chunkSize;
};

/** 
  API: ACDK<br>
  Heaps that manages memory
  An Allocator has a little overhead:
  <pre>
  AllocatorHeader:
    0 - 4 (Allocator*)
    5 - 8 size_t size of allocated chunk including AllocatorHeader
  acdk::lang::Object/Raw
    9 - n the allocated memory 
  </pre>
  @author Roger Rene Kommer
  @version $Revision: 1.21 $
  @date $Date: 2005/02/05 10:44:59 $
*/
class ACDK_CORE_PUBLIC Allocator
: public SysObject
{
public: 
 
  /**
    bit combination of AllocatorTypeFlags
  */
  int flags;

  Allocator(int allocatorFlags = StandardAllocatorType) : flags(allocatorFlags) {}
  
  /** type of the allocated object
    
    @see acdk::lang::TracedRawAllocatorInfo
  */
  
  virtual ~Allocator() { }
  /**
    combination of AllocatorTypeFlags
    @see AllocatorTypeFlags
  */
  inline int getFlags() { return flags; }
  /** 
    in case of GC or other scanning activities the Allocator should be locked.
    allocate() and deallocate should simply block 
  */
  virtual void lock() = 0;
  /** 
    in case of GC or other scanning activities the Allocator should be locked.
    allocate() and deallocate should simply block 
  */
  virtual void unlock() = 0;
  /**
    Allocates Memory.
    It is important, that the Allocator itself will be found in MemChunkHeader directly before this memory location)
    @param size size of acdk::lang::Object (not including MemChunkHeader)
    @return the raw preinitialized acdk::lang::Object not including MemChunkHeader
  */
  virtual void* allocate(size_t size, AllocatedType at = RawMem) = 0;
  /**
    Frees Memory
    @param ptr points to user object (not including MemChunkHeader)
  */
  virtual void deallocate(void* ptr, AllocatedType at = RawMem) = 0;
  
  /**
    @param flags combination of ListObjectsFlags
  */
  virtual void listObjects(::acdk::lang::ref::NotifyObjectEventListener* listener, int flags) = 0;
  /**
    @return the filled AllocatorInfo
   */
  virtual const AllocatorInfo& getAllocatorInfo() = 0;
  /**
    try to garbage collect items
    @param threadStorage if true only object allocated in the current thread should be 
                          gced
    @param force if true also release internal buffer
    @return true if any storage was freed
  */
  virtual bool doGc(bool threadStorage = true, bool force = false) = 0;
  
  /**
    use to initialize acdk::lang::Object flags
    probably has no effects
    @todo check if this function is superflous
  */
  void initObjectPtr(void* ptr, AllocatedType type);
  /**
    underlying allocation mechanism via operator ::new
    may call doGc and or throw OutOfMemoryError 
  */
  void* os_alloc(size_t size);
  /**
    dealocate memory via operator ::delete
  */
  void os_dealloc(size_t size, void* ptr);

  /** @internal */
  inline static MemChunkHeader* getHeaderFromObject(void* obj) { return (MemChunkHeader*)(((char*)obj) - ALIGNEDSIZEOF(MemChunkHeader)); }
  /** @internal */
  inline static MemChunkHeader* getHeaderFromChunk(void* obj) { return (MemChunkHeader*)obj; }
  /** @internal */
  inline static size_t getHeaderSize() { return ALIGNEDSIZEOF(MemChunkHeader); }
  /** @internal */
  inline static void* getObjectFromChunk(void* ptr) { return ((char*)ptr) + getHeaderSize(); }
  /** @internal */
  inline static void* getChunkFromObject(void* ptr) { return ((char*)ptr) - getHeaderSize(); }
};


ACDK_DECL_SYS_CLASS(AbstractAllocator);

/**
  The AbstractAllocator allocates for 
  acdk::lang::Object types a little bit memory, where
  the beginning of the allocated block a pointer to
  the Allocator can be found.
  The returned acdk::lang::Object pointer is at offset ALIGNEDSIZEOF(MemChunkHeader).

  All operations are protected by a simple/fast mutex
*/
class ACDK_CORE_PUBLIC AbstractAllocator
:  public Allocator
{
protected:
  core_fastmutex _lock;
public:
  AllocatorInfo _allocInfo;
  AbstractAllocator(int allocatorFlags, const core_string& name);
  virtual ~AbstractAllocator();
  virtual void lock() { if ((NoSyncAllocatorType & flags) == false) _lock.lock(); }
  virtual void unlock() { if ((NoSyncAllocatorType & flags) == false) _lock.unlock(); }
  
  /**
    @param size is including MemChunkHeader
  */
  virtual void* raw_allocate(size_t size, AllocatedType type) = 0;
  /**
    @param size is including MemChunkHeader
    @param ptr is including MemChunkHeader
  */
  virtual void raw_deallocate(size_t size, void* ptr, AllocatedType type) = 0;
  
  virtual void* allocate(size_t size, AllocatedType at = RawMem);
  virtual void deallocate(void* ptr, AllocatedType at = RawMem);
  virtual void listObjects(::acdk::lang::ref::NotifyObjectEventListener* listener, int flags) = 0;

  virtual const AllocatorInfo& getAllocatorInfo() { return _allocInfo; }
  virtual bool doGc(bool threadStorage = true, bool force = false);

  const char* name() const { return _allocInfo.name.c_str(); }

};

ACDK_DECL_SYS_CLASS(RawAllocator);

/**
  This is a thin wrapper to raw allocation
  used by RC_Heap.
*/
class ACDK_CORE_PUBLIC RawAllocator
:  public AbstractAllocator
{
public:
  RawAllocator()
  : AbstractAllocator(StandardAllocatorType, core_string("RawAllocator", false))
  {
  }
  ~RawAllocator() { }
  
  virtual void* raw_allocate(size_t size, AllocatedType type) { return os_alloc(size); }
  virtual void raw_deallocate(size_t size, void* ptr, AllocatedType type) { os_dealloc(size, ptr); }
  virtual void listObjects(::acdk::lang::ref::NotifyObjectEventListener* listener, int flags)
  {
  }
};


} // namespace sys
} // namespace lang 
} // namespace acdk 

/** this is the standard allocator, which directs calls to new/delete */
ACDK_CORE_PUBLIC acdk::lang::sys::Allocator* stdalloc();

inline void* acdk_allocate(size_t size) 
{   
  acdk::lang::sys::Allocator* allocptr = ::acdk::lang::sys::ObjectHeap::allocator();
  if (allocptr == 0) // should never be!!!
    *reinterpret_cast<char*>(allocptr) = 0;
  return  allocptr->allocate(size); 
}

inline void acdk_deallocate(void* ptr) 
{ 
  ::acdk::lang::sys::Allocator::getHeaderFromObject(ptr)->allocator->deallocate(ptr);  
}

inline void* acdk_allocate(size_t size, ::acdk::lang::sys::Allocator* allocator) 
{ 
  return allocator->allocate(size); 
}
inline void acdk_deallocate(void* ptr, ::acdk::lang::sys::Allocator* allocator)
{ 
  allocator->deallocate(ptr); 
}



#endif //acdk_lang_Allocator_h