Home | History | Annotate | Download | only in source
      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 
     37 namespace 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.
     42 struct AlignedMemory
     43 {
     44   void* alignedBuffer;
     45   void* memoryPointer;
     46 };
     47 
     48 void* 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 
    102 void 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