blob: 43ece9e681fcb186a401c2063d257f41608a9e4e [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "system_wrappers/include/aligned_malloc.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
niklase@google.com470e71d2011-07-07 08:21:25 +000013#include <memory.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000014#include <stdlib.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000015
kwiberg77eab702016-09-28 17:42:01 -070016#ifdef _WIN32
henrike@webrtc.org28625c12012-10-02 15:38:35 +000017#include <windows.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000018#else
henrike@webrtc.org28625c12012-10-02 15:38:35 +000019#include <stdint.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000020#endif
21
Mirko Bonadei71207422017-09-15 13:58:09 +020022#include "typedefs.h" // NOLINT(build/include)
niklase@google.com470e71d2011-07-07 08:21:25 +000023
henrike@webrtc.org28625c12012-10-02 15:38:35 +000024// Reference on memory alignment:
niklase@google.com470e71d2011-07-07 08:21:25 +000025// http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me
henrike@webrtc.org28625c12012-10-02 15:38:35 +000026namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000027
henrike@webrtc.org46d40732012-10-03 16:50:37 +000028uintptr_t GetRightAlign(uintptr_t start_pos, size_t alignment) {
henrike@webrtc.org28625c12012-10-02 15:38:35 +000029 // The pointer should be aligned with |alignment| bytes. The - 1 guarantees
30 // that it is aligned towards the closest higher (right) address.
henrike@webrtc.org46d40732012-10-03 16:50:37 +000031 return (start_pos + alignment - 1) & ~(alignment - 1);
henrike@webrtc.orgcd9adf72012-09-29 03:49:36 +000032}
33
34// Alignment must be an integer power of two.
henrike@webrtc.org28625c12012-10-02 15:38:35 +000035bool ValidAlignment(size_t alignment) {
36 if (!alignment) {
37 return false;
38 }
39 return (alignment & (alignment - 1)) == 0;
henrike@webrtc.orgcd9adf72012-09-29 03:49:36 +000040}
41
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000042void* GetRightAlign(const void* pointer, size_t alignment) {
43 if (!pointer) {
henrike@webrtc.org28625c12012-10-02 15:38:35 +000044 return NULL;
45 }
46 if (!ValidAlignment(alignment)) {
47 return NULL;
48 }
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000049 uintptr_t start_pos = reinterpret_cast<uintptr_t>(pointer);
henrike@webrtc.org46d40732012-10-03 16:50:37 +000050 return reinterpret_cast<void*>(GetRightAlign(start_pos, alignment));
henrike@webrtc.orgcd9adf72012-09-29 03:49:36 +000051}
52
henrike@webrtc.org28625c12012-10-02 15:38:35 +000053void* AlignedMalloc(size_t size, size_t alignment) {
54 if (size == 0) {
55 return NULL;
56 }
57 if (!ValidAlignment(alignment)) {
58 return NULL;
59 }
niklase@google.com470e71d2011-07-07 08:21:25 +000060
henrike@webrtc.org28625c12012-10-02 15:38:35 +000061 // The memory is aligned towards the lowest address that so only
62 // alignment - 1 bytes needs to be allocated.
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000063 // A pointer to the start of the memory must be stored so that it can be
64 // retreived for deletion, ergo the sizeof(uintptr_t).
65 void* memory_pointer = malloc(size + sizeof(uintptr_t) + alignment - 1);
66 if (memory_pointer == NULL) {
henrike@webrtc.org28625c12012-10-02 15:38:35 +000067 return NULL;
68 }
niklase@google.com470e71d2011-07-07 08:21:25 +000069
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000070 // Aligning after the sizeof(uintptr_t) bytes will leave room for the header
henrike@webrtc.org28625c12012-10-02 15:38:35 +000071 // in the same memory block.
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000072 uintptr_t align_start_pos = reinterpret_cast<uintptr_t>(memory_pointer);
henrike@webrtc.org46d40732012-10-03 16:50:37 +000073 align_start_pos += sizeof(uintptr_t);
74 uintptr_t aligned_pos = GetRightAlign(align_start_pos, alignment);
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000075 void* aligned_pointer = reinterpret_cast<void*>(aligned_pos);
niklase@google.com470e71d2011-07-07 08:21:25 +000076
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000077 // Store the address to the beginning of the memory just before the aligned
78 // memory.
79 uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
80 void* header_pointer = reinterpret_cast<void*>(header_pos);
81 uintptr_t memory_start = reinterpret_cast<uintptr_t>(memory_pointer);
82 memcpy(header_pointer, &memory_start, sizeof(uintptr_t));
83
84 return aligned_pointer;
niklase@google.com470e71d2011-07-07 08:21:25 +000085}
86
henrike@webrtc.org46d40732012-10-03 16:50:37 +000087void AlignedFree(void* mem_block) {
88 if (mem_block == NULL) {
henrike@webrtc.org28625c12012-10-02 15:38:35 +000089 return;
90 }
henrike@webrtc.org46d40732012-10-03 16:50:37 +000091 uintptr_t aligned_pos = reinterpret_cast<uintptr_t>(mem_block);
92 uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
niklase@google.com470e71d2011-07-07 08:21:25 +000093
henrike@webrtc.org28625c12012-10-02 15:38:35 +000094 // Read out the address of the AlignedMemory struct from the header.
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000095 uintptr_t memory_start_pos = *reinterpret_cast<uintptr_t*>(header_pos);
96 void* memory_start = reinterpret_cast<void*>(memory_start_pos);
97 free(memory_start);
niklase@google.com470e71d2011-07-07 08:21:25 +000098}
henrike@webrtc.org28625c12012-10-02 15:38:35 +000099
henrike@webrtc.orgcd9adf72012-09-29 03:49:36 +0000100} // namespace webrtc