1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/*
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Use of this source code is governed by a BSD-style license
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  that can be found in the LICENSE file in the root of the source
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  tree. An additional intellectual property rights grant can be found
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  in the file PATENTS.  All contributing project authors may
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
11c6d6fed3c0a82bb7a09095381b974e8e5eebcb35pbos@webrtc.org#include "webrtc/system_wrappers/interface/aligned_malloc.h"
12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
13b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <memory.h>
14b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <stdlib.h>
15b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
16b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#if _WIN32
17b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <windows.h>
18b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#else
19b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <stdint.h>
20b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#endif
21b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
22c6d6fed3c0a82bb7a09095381b974e8e5eebcb35pbos@webrtc.org#include "webrtc/typedefs.h"
23b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Reference on memory alignment:
25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me
26b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc {
27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orguintptr_t GetRightAlign(uintptr_t start_pos, size_t alignment) {
29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // The pointer should be aligned with |alignment| bytes. The - 1 guarantees
30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // that it is aligned towards the closest higher (right) address.
31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return (start_pos + alignment - 1) & ~(alignment - 1);
32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org// Alignment must be an integer power of two.
35b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgbool ValidAlignment(size_t alignment) {
36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (!alignment) {
37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return false;
38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return (alignment & (alignment - 1)) == 0;
40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid* GetRightAlign(const void* pointer, size_t alignment) {
43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (!pointer) {
44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return NULL;
45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (!ValidAlignment(alignment)) {
47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return NULL;
48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  uintptr_t start_pos = reinterpret_cast<uintptr_t>(pointer);
50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return reinterpret_cast<void*>(GetRightAlign(start_pos, alignment));
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid* AlignedMalloc(size_t size, size_t alignment) {
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (size == 0) {
55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return NULL;
56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (!ValidAlignment(alignment)) {
58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return NULL;
59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // The memory is aligned towards the lowest address that so only
62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // alignment - 1 bytes needs to be allocated.
63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // A pointer to the start of the memory must be stored so that it can be
64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // retreived for deletion, ergo the sizeof(uintptr_t).
65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  void* memory_pointer = malloc(size + sizeof(uintptr_t) + alignment - 1);
66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (memory_pointer == NULL) {
67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return NULL;
68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
70b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Aligning after the sizeof(uintptr_t) bytes will leave room for the header
71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // in the same memory block.
72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  uintptr_t align_start_pos = reinterpret_cast<uintptr_t>(memory_pointer);
73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  align_start_pos += sizeof(uintptr_t);
74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  uintptr_t aligned_pos = GetRightAlign(align_start_pos, alignment);
75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  void* aligned_pointer = reinterpret_cast<void*>(aligned_pos);
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Store the address to the beginning of the memory just before the aligned
78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // memory.
79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  void* header_pointer = reinterpret_cast<void*>(header_pos);
81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  uintptr_t memory_start = reinterpret_cast<uintptr_t>(memory_pointer);
82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  memcpy(header_pointer, &memory_start, sizeof(uintptr_t));
83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  return aligned_pointer;
85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgvoid AlignedFree(void* mem_block) {
88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  if (mem_block == NULL) {
89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return;
90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  uintptr_t aligned_pos = reinterpret_cast<uintptr_t>(mem_block);
92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Read out the address of the AlignedMemory struct from the header.
95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  uintptr_t memory_start_pos = *reinterpret_cast<uintptr_t*>(header_pos);
96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  void* memory_start = reinterpret_cast<void*>(memory_start_pos);
97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  free(memory_start);
98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}  // namespace webrtc
101