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