diff --git a/src/system_wrappers/interface/aligned_malloc.h b/src/system_wrappers/interface/aligned_malloc.h index c229435e6..3fda6b660 100644 --- a/src/system_wrappers/interface/aligned_malloc.h +++ b/src/system_wrappers/interface/aligned_malloc.h @@ -11,15 +11,37 @@ #ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ALIGNED_MALLOC_H_ #define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ALIGNED_MALLOC_H_ +// The functions declared here +// 1) Allocates block of aligned memory. +// 2) Re-calculates a pointer such that it is aligned to a higher or equal +// address. +// Note: alignment must be a power of two. The alignment is in bytes. + #include -namespace webrtc -{ - void* AlignedMalloc( - size_t size, - size_t alignment); - void AlignedFree( - void* memBlock); -} +#include "system_wrappers/interface/scoped_ptr.h" + +namespace webrtc { + +// Returns a pointer to the first boundry of |alignment| bytes following the +// address of |ptr|. +// Note that there is no guarantee that the memory in question is available. +// |ptr| has no requirements other than it can't be NULL. +void* GetRightAlign(const void* ptr, size_t alignment); + +// Allocates memory of |size| bytes aligned on an |alignment| boundry. +// The return value is a pointer to the memory. Note that the memory must +// be de-allocated using AlignedFree. +void* AlignedMalloc(size_t size, size_t alignment); +// De-allocates memory created using the AlignedMalloc() API. +void AlignedFree(void* memBlock); + +// Scoped pointer to AlignedMalloc-memory. +template +struct Allocator { + typedef scoped_ptr_malloc scoped_ptr_aligned; +}; + +} // namespace webrtc #endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ALIGNED_MALLOC_H_ diff --git a/src/system_wrappers/source/aligned_malloc.cc b/src/system_wrappers/source/aligned_malloc.cc index bb10c6bb4..c54a59897 100644 --- a/src/system_wrappers/source/aligned_malloc.cc +++ b/src/system_wrappers/source/aligned_malloc.cc @@ -45,15 +45,43 @@ struct AlignedMemory void* memoryPointer; }; -void* AlignedMalloc(size_t size, size_t alignment) +uintptr_t GetRightAlign(uintptr_t startPos, size_t alignment) { - if(alignment == 0) + // The pointer should be aligned with |alignment| bytes. The - 1 guarantees + // that it is aligned towards the closest higher (right) address. + return (startPos + alignment - 1) & ~(alignment - 1); +} + +// Alignment must be an integer power of two. +bool ValidAlignment(size_t alignment) +{ + if (!alignment) + { + return false; + } + return (alignment & (alignment - 1)) == 0; +} + +void* GetRightAlign(const void* ptr, size_t alignment) +{ + if (!ptr) { - // Don't allow alignment 0 since it's undefined. return NULL; } - // Make sure that the alignment is an integer power of two or fail. - if(alignment & (alignment - 1)) + if (!ValidAlignment(alignment)) + { + return NULL; + } + uintptr_t startPos = reinterpret_cast (ptr); + return reinterpret_cast (GetRightAlign(startPos, alignment)); +} + +void* AlignedMalloc(size_t size, size_t alignment) +{ + if (size == 0) { + return NULL; + } + if (!ValidAlignment(alignment)) { return NULL; } @@ -80,19 +108,14 @@ void* AlignedMalloc(size_t size, size_t alignment) // in the same memory block. uintptr_t alignStartPos = (uintptr_t)returnValue->memoryPointer; alignStartPos += sizeof(uintptr_t); - - // The buffer should be aligned with 'alignment' bytes. The - 1 guarantees - // that we align towards the lowest address. - uintptr_t alignedPos = (alignStartPos + alignment - 1) & ~(alignment - 1); - - // alignedPos is the address sought for. - returnValue->alignedBuffer = (void*)alignedPos; + uintptr_t alignedPos = GetRightAlign(alignStartPos, alignment); + returnValue->alignedBuffer = reinterpret_cast (alignedPos); // Store the address to the AlignedMemory struct in the header so that a // it's possible to reclaim all memory. uintptr_t headerPos = alignedPos; headerPos -= sizeof(uintptr_t); - void* headerPtr = (void*) headerPos; + void* headerPtr = reinterpret_cast (headerPos); uintptr_t headerValue = (uintptr_t)returnValue; memcpy(headerPtr,&headerValue,sizeof(uintptr_t)); @@ -118,4 +141,4 @@ void AlignedFree(void* memBlock) } delete deleteMemory; } -} // namespace webrtc +} // namespace webrtc diff --git a/src/system_wrappers/source/aligned_malloc_unittest.cc b/src/system_wrappers/source/aligned_malloc_unittest.cc new file mode 100644 index 000000000..9c6223c63 --- /dev/null +++ b/src/system_wrappers/source/aligned_malloc_unittest.cc @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "system_wrappers/interface/aligned_malloc.h" + +#if _WIN32 +#include +#else +#include +#endif + +#include "typedefs.h" // NOLINT + +#include "gtest/gtest.h" + +// Returns true if |size| and |alignment| are valid combinations. +bool CorrectUsage(size_t size, size_t alignment) { + webrtc::Allocator::scoped_ptr_aligned scoped( + static_cast (webrtc::AlignedMalloc(size, alignment))); + if (scoped.get() == NULL) { + return false; + } + const uintptr_t scoped_address = reinterpret_cast (scoped.get()); + return 0u == scoped_address % alignment; +} + +TEST(AlignedMalloc, GetRightAlign) { + const size_t size = 100; + const size_t alignment = 32; + const size_t left_missalignment = 8; + webrtc::Allocator::scoped_ptr_aligned scoped( + static_cast (webrtc::AlignedMalloc(size, alignment))); + EXPECT_TRUE(scoped.get() != NULL); + const uintptr_t aligned_address = reinterpret_cast (scoped.get()); + const uintptr_t missaligned_address = aligned_address - left_missalignment; + const void* missaligned_ptr = reinterpret_cast (missaligned_address); + const void* realignedPtr = webrtc::GetRightAlign( + missaligned_ptr, alignment); + EXPECT_EQ(scoped.get(), realignedPtr); +} + +TEST(AlignedMalloc, IncorrectSize) { + const size_t incorrect_size = 0; + const size_t alignment = 64; + EXPECT_FALSE(CorrectUsage(incorrect_size, alignment)); +} + +TEST(AlignedMalloc, IncorrectAlignment) { + const size_t size = 100; + const size_t incorrect_alignment = 63; + EXPECT_FALSE(CorrectUsage(size, incorrect_alignment)); +} + +TEST(AlignedMalloc, AlignTo2Bytes) { + size_t size = 100; + size_t alignment = 2; + EXPECT_TRUE(CorrectUsage(size, alignment)); +} + +TEST(AlignedMalloc, AlignTo32Bytes) { + size_t size = 100; + size_t alignment = 32; + EXPECT_TRUE(CorrectUsage(size, alignment)); +} + +TEST(AlignedMalloc, AlignTo128Bytes) { + size_t size = 100; + size_t alignment = 128; + EXPECT_TRUE(CorrectUsage(size, alignment)); +} diff --git a/src/system_wrappers/source/system_wrappers.gyp b/src/system_wrappers/source/system_wrappers.gyp index 386a2c66a..dcde1c7de 100644 --- a/src/system_wrappers/source/system_wrappers.gyp +++ b/src/system_wrappers/source/system_wrappers.gyp @@ -202,6 +202,7 @@ '<(webrtc_root)/test/test.gyp:test_support_main', ], 'sources': [ + 'aligned_malloc_unittest.cc', 'condition_variable_unittest.cc', 'cpu_wrapper_unittest.cc', 'cpu_measurement_harness.h',