blob: c893c96ef2af0883c03fa120eff385a58e3acb48 [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
Karl Wiberg29e7bee2018-03-22 14:11:52 +010011#include "rtc_base/memory/aligned_malloc.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
Yves Gerey2e00abc2018-10-05 15:39:24 +020013#include <stdlib.h> // for free, malloc
14#include <string.h> // for memcpy
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
henrike@webrtc.org28625c12012-10-02 15:38:35 +000022// Reference on memory alignment:
niklase@google.com470e71d2011-07-07 08:21:25 +000023// http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me
henrike@webrtc.org28625c12012-10-02 15:38:35 +000024namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000025
henrike@webrtc.org46d40732012-10-03 16:50:37 +000026uintptr_t GetRightAlign(uintptr_t start_pos, size_t alignment) {
henrike@webrtc.org28625c12012-10-02 15:38:35 +000027 // The pointer should be aligned with |alignment| bytes. The - 1 guarantees
28 // that it is aligned towards the closest higher (right) address.
henrike@webrtc.org46d40732012-10-03 16:50:37 +000029 return (start_pos + alignment - 1) & ~(alignment - 1);
henrike@webrtc.orgcd9adf72012-09-29 03:49:36 +000030}
31
32// Alignment must be an integer power of two.
henrike@webrtc.org28625c12012-10-02 15:38:35 +000033bool ValidAlignment(size_t alignment) {
34 if (!alignment) {
35 return false;
36 }
37 return (alignment & (alignment - 1)) == 0;
henrike@webrtc.orgcd9adf72012-09-29 03:49:36 +000038}
39
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000040void* GetRightAlign(const void* pointer, size_t alignment) {
41 if (!pointer) {
henrike@webrtc.org28625c12012-10-02 15:38:35 +000042 return NULL;
43 }
44 if (!ValidAlignment(alignment)) {
45 return NULL;
46 }
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000047 uintptr_t start_pos = reinterpret_cast<uintptr_t>(pointer);
henrike@webrtc.org46d40732012-10-03 16:50:37 +000048 return reinterpret_cast<void*>(GetRightAlign(start_pos, alignment));
henrike@webrtc.orgcd9adf72012-09-29 03:49:36 +000049}
50
henrike@webrtc.org28625c12012-10-02 15:38:35 +000051void* AlignedMalloc(size_t size, size_t alignment) {
52 if (size == 0) {
53 return NULL;
54 }
55 if (!ValidAlignment(alignment)) {
56 return NULL;
57 }
niklase@google.com470e71d2011-07-07 08:21:25 +000058
henrike@webrtc.org28625c12012-10-02 15:38:35 +000059 // The memory is aligned towards the lowest address that so only
60 // alignment - 1 bytes needs to be allocated.
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000061 // A pointer to the start of the memory must be stored so that it can be
62 // retreived for deletion, ergo the sizeof(uintptr_t).
63 void* memory_pointer = malloc(size + sizeof(uintptr_t) + alignment - 1);
64 if (memory_pointer == NULL) {
henrike@webrtc.org28625c12012-10-02 15:38:35 +000065 return NULL;
66 }
niklase@google.com470e71d2011-07-07 08:21:25 +000067
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000068 // Aligning after the sizeof(uintptr_t) bytes will leave room for the header
henrike@webrtc.org28625c12012-10-02 15:38:35 +000069 // in the same memory block.
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000070 uintptr_t align_start_pos = reinterpret_cast<uintptr_t>(memory_pointer);
henrike@webrtc.org46d40732012-10-03 16:50:37 +000071 align_start_pos += sizeof(uintptr_t);
72 uintptr_t aligned_pos = GetRightAlign(align_start_pos, alignment);
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000073 void* aligned_pointer = reinterpret_cast<void*>(aligned_pos);
niklase@google.com470e71d2011-07-07 08:21:25 +000074
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000075 // Store the address to the beginning of the memory just before the aligned
76 // memory.
77 uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
78 void* header_pointer = reinterpret_cast<void*>(header_pos);
79 uintptr_t memory_start = reinterpret_cast<uintptr_t>(memory_pointer);
80 memcpy(header_pointer, &memory_start, sizeof(uintptr_t));
81
82 return aligned_pointer;
niklase@google.com470e71d2011-07-07 08:21:25 +000083}
84
henrike@webrtc.org46d40732012-10-03 16:50:37 +000085void AlignedFree(void* mem_block) {
86 if (mem_block == NULL) {
henrike@webrtc.org28625c12012-10-02 15:38:35 +000087 return;
88 }
henrike@webrtc.org46d40732012-10-03 16:50:37 +000089 uintptr_t aligned_pos = reinterpret_cast<uintptr_t>(mem_block);
90 uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
niklase@google.com470e71d2011-07-07 08:21:25 +000091
henrike@webrtc.org28625c12012-10-02 15:38:35 +000092 // Read out the address of the AlignedMemory struct from the header.
henrike@webrtc.org0ed9c692012-10-08 20:20:22 +000093 uintptr_t memory_start_pos = *reinterpret_cast<uintptr_t*>(header_pos);
94 void* memory_start = reinterpret_cast<void*>(memory_start_pos);
95 free(memory_start);
niklase@google.com470e71d2011-07-07 08:21:25 +000096}
henrike@webrtc.org28625c12012-10-02 15:38:35 +000097
henrike@webrtc.orgcd9adf72012-09-29 03:49:36 +000098} // namespace webrtc