1/*
2 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "aligned_malloc.h"
12
13#include <assert.h>
14#include <memory.h>
15
16#ifdef WEBRTC_ANDROID
17#include <stdlib.h>
18#endif
19
20#if WEBRTC_MAC
21  #include <malloc/malloc.h>
22#else
23  #include <malloc.h>
24#endif
25
26#if _WIN32
27    #include <windows.h>
28#else
29    #include <stdint.h>
30#endif
31
32#include "typedefs.h"
33
34// Ok reference on memory alignment:
35// http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me
36
37namespace webrtc
38{
39// TODO (hellner) better to create just one memory block and
40//                           interpret the first sizeof(AlignedMemory) bytes as
41//                           an AlignedMemory struct.
42struct AlignedMemory
43{
44  void* alignedBuffer;
45  void* memoryPointer;
46};
47
48void* AlignedMalloc(size_t size, size_t alignment)
49{
50    if(alignment == 0)
51    {
52        // Don't allow alignment 0 since it's undefined.
53        return NULL;
54    }
55    // Make sure that the alignment is an integer power of two or fail.
56    if(alignment & (alignment - 1))
57    {
58        return NULL;
59    }
60
61    AlignedMemory* returnValue = new AlignedMemory();
62    if(returnValue == NULL)
63    {
64        return NULL;
65    }
66
67    // The memory is aligned towards the lowest address that so only
68    // alignment - 1 bytes needs to be allocated.
69    // A pointer to AlignedMemory must be stored so that it can be retreived for
70    // deletion, ergo the sizeof(uintptr_t).
71    returnValue->memoryPointer = malloc(size + sizeof(uintptr_t) +
72                                        alignment - 1);
73    if(returnValue->memoryPointer == NULL)
74    {
75        delete returnValue;
76        return NULL;
77    }
78
79    // Alligning after the sizeof(header) bytes will leave room for the header
80    // in the same memory block.
81    uintptr_t alignStartPos = (uintptr_t)returnValue->memoryPointer;
82    alignStartPos += sizeof(uintptr_t);
83
84    // The buffer should be aligned with 'alignment' bytes. The - 1 guarantees
85    // that we align towards the lowest address.
86    uintptr_t alignedPos = (alignStartPos + alignment - 1) & ~(alignment - 1);
87
88    // alignedPos is the address sought for.
89    returnValue->alignedBuffer = (void*)alignedPos;
90
91    // Store the address to the AlignedMemory struct in the header so that a
92    // it's possible to reclaim all memory.
93    uintptr_t headerPos = alignedPos;
94    headerPos -= sizeof(uintptr_t);
95    void* headerPtr = (void*) headerPos;
96    uintptr_t headerValue = (uintptr_t)returnValue;
97    memcpy(headerPtr,&headerValue,sizeof(uintptr_t));
98
99    return returnValue->alignedBuffer;
100}
101
102void AlignedFree(void* memBlock)
103{
104    if(memBlock == NULL)
105    {
106        return;
107    }
108    uintptr_t alignedPos = (uintptr_t)memBlock;
109    uintptr_t headerPos = alignedPos - sizeof(uintptr_t);
110
111    // Read out the address of the AlignedMemory struct from the header.
112    uintptr_t* headerPtr = (uintptr_t*)headerPos;
113    AlignedMemory* deleteMemory = (AlignedMemory*) *headerPtr;
114
115    if(deleteMemory->memoryPointer != NULL)
116    {
117        free(deleteMemory->memoryPointer);
118    }
119    delete deleteMemory;
120}
121} // namespace webrtc
122