BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlma_alignedallocator

Detailed Description

Outline

Purpose

Provide a protocol for memory allocators that support alignment.

Classes

See also
bslma_allocator

Description

This component provides an implementation, bdlma::AlignedAllocator, of the base-level protocol (pure abstract interface) class, bslma::Allocator, providing the ability to allocate raw memory with a specified alignment. The following inheritance diagram shows the classes involved and their methods:

,----------------------.
`----------------------'
| allocateAligned
V
,----------------.
( bslma::Allocator )
`----------------'
allocate
deallocate
Definition bdlma_alignedallocator.h:288

The allocateAligned method supplies the address of a contiguous block of allocated memory of at least the indicated size, that is aligned to a given boundary. Note that this behavior is similar to the behavior of the POSIX function posix_memalign .

Usage

This section illustrates intended use of this component.

Example 1: Implementing bdlma::AlignedAllocator

The bdlma::AlignedAllocator protocol provided in this component defines a bilateral contract between suppliers and consumers of raw aligned memory. In order for the bdlma::AlignedAllocator interface to be useful, we must supply a concrete allocator that implements it.

In this example, we demonstrate how to adapt posix_memalign on Linux and AIX, memalign on SunOS and _aligned_malloc on Windows, to this protocol base class:

First, we specify the interface of the concrete implementation of 'MyAlignedAllocator:

// myposixmemalignallocator.h
// ...
class MyAlignedAllocator: public bdlma::AlignedAllocator {
// This class is a sample concrete implementation of the
// 'bdlma::AlignedAllocator' protocol that provides direct access to
// the system-supplied 'posix_memalign' and 'free' on Linux and AIX
// platforms, 'memalign' and 'free' on SunOS, or '_aligned_malloc' and
// '_aligned_free' on Windows.
private:
// NOT IMPLEMENTED
MyAlignedAllocator(const MyAlignedAllocator&);
MyAlignedAllocator& operator=(const MyAlignedAllocator&);
public:
// CREATORS
MyAlignedAllocator();
// Create a 'MyAlignedAllocator' object. Note that all objects of
// this class share the same underlying resource.
virtual ~MyAlignedAllocator();
// Destroy this object. Note that destroying this object has no
// effect on any outstanding allocated memory.
// MANIPULATORS
virtual void *allocate(bsls::Types::size_type size);
// Return a newly allocated block of memory of (at least) the
// specified positive 'size' (in bytes). If 'size' is 0, a null
// pointer is returned with no other effect. If this allocator
// cannot return the requested number of bytes, then it will throw
// an 'std::bad_alloc' exception in an exception-enabled build, or
// else it will abort the program in a non-exception build. The
// behavior is undefined unless '0 <= size'. Note that the
// alignment of the address returned conforms to the platform
// requirement for any object of the 'size'. Also note that global
// 'operator new' is *not* called when 'size' is 0 (in order to
// avoid having to acquire a lock, and potential contention in
// multi-threaded programs).
virtual void *allocateAligned(bsls::Types::size_type size,
// Return the address of a newly allocated block of memory of at
// least the specified positive 'size' (in bytes), sufficiently
// aligned such that the returned 'address' satisfies, for the
// specified 'alignment', '0 == (address & (alignment - 1))'. If
// 'size' is 0, a null pointer is returned with no other effect.
// If the requested number of appropriately aligned bytes cannot be
// returned, then a 'bsl::bad_alloc' exception is thrown, or in a
// non-exception build the program is terminated. The behavior is
// undefined unless 'alignment' is both a multiple of
// 'sizeof(void *)' and an integral non-negative power of two.
virtual void deallocate(void *address);
// Return the memory block at the specified 'address' back to this
// allocator. If 'address' is 0, this function has no effect. The
// behavior is undefined unless 'address' was allocated using this
// allocator object and has not already been deallocated.
};
// ...
memory_resource & operator=(const memory_resource &) BSLS_KEYWORD_DEFAULT
Return a modifiable reference to this object.
std::size_t size_type
Definition bsls_types.h:124

Then, we implement the creators, trivially, as this class contains no instance data members.

// CREATORS
MyAlignedAllocator::MyAlignedAllocator()
{
}
MyAlignedAllocator::~MyAlignedAllocator()
{
}

Now, we define the virtual methods of MyAlignedAllocator. Note that these definitions are not inline, as they would not be inlined when invoked from the base class (the typical usage in this case):

// MANIPULATORS
void *MyAlignedAllocator::allocate(bsls::Types::size_type size)
{
if (0 == size) {
return 0; // RETURN
}
return allocateAligned(size, alignment);
}
void *MyAlignedAllocator::allocateAligned(bsls::Types::size_type size,
{
BSLS_ASSERT_SAFE(0 == (alignment & (alignment - 1)));
BSLS_ASSERT_SAFE(0 == (alignment % sizeof(void *)));
if (0 == size) {
return 0; // RETURN
}
void *ret = 0;
#ifdef BSLS_PLATFORM_OS_WINDOWS
errno = 0;
ret = _aligned_malloc(size, alignment);
if (0 != errno) {
}
#elif defined(BSLS_PLATFORM_OS_SOLARIS)
ret = memalign(alignment, size);
if (0 == ret) {
}
#else
int rc = ::posix_memalign(&ret, alignment, size);
if (0 != rc) {
}
#endif
return ret;
}
void MyAlignedAllocator::deallocate(void *address)
{
if (0 == address) {
return; // RETURN
}
#ifdef BSLS_PLATFORM_WINDOWS
_aligned_free(address);
#else
::free(address);
#endif
}
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1762
static int calculateAlignmentFromSize(std::size_t size)
Definition bsls_alignmentutil.h:344
static BSLS_ANNOTATION_NORETURN void throwBadAlloc()

Finally, we define a function f that instantiates an object of type MyAlignedAllocator:

void f() {
MyAlignedAllocator a;
}

Note that the memory is not released when the allocator goes out of scope.

Example 2: Using the bdlma::AlignedAllocator Protocol

In this example we illustrate how to use the bdlma::AlignedAllocator protocol to allocate memory that is aligned to the beginning of a memory page. Third party libraries, for example device drivers that perform DMA access of device drivers, or some extreme optimizations to reduce the number of page faults, might require page aligned allocations.

First, we create an aligned allocator myAlignedAllocator using the class MyAlignedAllocator defined in the previous example, and obtain a bdlma::AlignedAllocator pointer to it:

MyAlignedAllocator myAlignedAllocator;
bdlma::AlignedAllocator *alignedAllocator = &myAlignedAllocator;

Now, assuming a page size of 4K, we allocate a buffer of 1024 bytes of memory and indicate that it should be aligned on a 4096 boundary:

char *address = (char *) alignedAllocator->allocateAligned(1024, 4096);
virtual void * allocateAligned(bsls::Types::size_type size, bsls::Types::size_type alignment)=0

Finally, we verify that the obtained address actually is aligned as expected:

assert(0 == ((bsl::size_t)address & (4096 - 1)));