malloc_aligned.hpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /*
  2. * Copyright Andrey Semashev 2007 - 2013.
  3. * Distributed under the Boost Software License, Version 1.0.
  4. * (See accompanying file LICENSE_1_0.txt or copy at
  5. * http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. /*!
  8. * \file malloc_aligned.hpp
  9. * \author Andrey Semashev
  10. * \date 12.07.2013
  11. *
  12. * \brief This header is the Boost.Log library implementation, see the library documentation
  13. * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
  14. */
  15. #ifndef BOOST_LOG_DETAIL_MALLOC_ALIGNED_HPP_INCLUDED_
  16. #define BOOST_LOG_DETAIL_MALLOC_ALIGNED_HPP_INCLUDED_
  17. #include <cstddef>
  18. #include <cstdlib>
  19. #include <boost/assert.hpp>
  20. #include <boost/cstdint.hpp>
  21. #include <boost/log/detail/config.hpp>
  22. // MSVC has its own _aligned_malloc and _aligned_free functions.
  23. // But MinGW doesn't declare these aligned memory allocation routines for MSVC 6 runtime.
  24. #if defined(BOOST_WINDOWS) && !(defined(__MINGW32__) && __MSVCRT_VERSION__ < 0x0700)
  25. #include <malloc.h>
  26. #define BOOST_LOG_HAS_MSVC_ALIGNED_MALLOC 1
  27. #endif
  28. #if defined(BOOST_HAS_UNISTD_H)
  29. #include <unistd.h> // _POSIX_VERSION
  30. #endif
  31. #if defined(__APPLE__) || defined(__APPLE_CC__) || defined(macintosh)
  32. #include <AvailabilityMacros.h>
  33. #if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1060)
  34. // Mac OS X 10.6 and later have posix_memalign
  35. #define BOOST_LOG_HAS_POSIX_MEMALIGN 1
  36. #endif
  37. #elif defined(__ANDROID__)
  38. // Android NDK (up to release 8e, at least) doesn't have posix_memalign despite it defines POSIX macros as if it does.
  39. // But we can use memalign() with free() on this platform.
  40. #include <malloc.h>
  41. #define BOOST_LOG_HAS_FREEABLE_MEMALIGN 1
  42. #elif (defined(_POSIX_VERSION) && (_POSIX_VERSION >= 200112L)) || (defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600))
  43. // Solaris 10 does not have posix_memalign. Solaris 11 and later seem to have it.
  44. #if !(defined(sun) || defined(__sun)) || defined(__SunOS_5_11) || defined(__SunOS_5_12)
  45. #define BOOST_LOG_HAS_POSIX_MEMALIGN 1
  46. #endif
  47. #endif
  48. #include <boost/log/detail/header.hpp>
  49. #ifdef BOOST_HAS_PRAGMA_ONCE
  50. #pragma once
  51. #endif
  52. #ifndef BOOST_LOG_CPU_CACHE_LINE_SIZE
  53. //! The macro defines the CPU cache line size for the target architecture. This is mostly used for optimization.
  54. #define BOOST_LOG_CPU_CACHE_LINE_SIZE 64
  55. #endif
  56. namespace boost {
  57. BOOST_LOG_OPEN_NAMESPACE
  58. namespace aux {
  59. /*!
  60. * Allocates uninitialized aligned memory. Memory alignment must be a power of 2 and a multiple of sizeof(void*).
  61. * The implementation may impose an upper bound of the alignment as well.
  62. */
  63. inline void* malloc_aligned(std::size_t size, uint32_t alignment)
  64. {
  65. #if defined(BOOST_LOG_HAS_POSIX_MEMALIGN)
  66. void* p = NULL;
  67. if (posix_memalign(&p, alignment, size) != 0)
  68. return NULL;
  69. return p;
  70. #elif defined(BOOST_LOG_HAS_FREEABLE_MEMALIGN)
  71. return memalign(alignment, size);
  72. #elif defined(BOOST_LOG_HAS_MSVC_ALIGNED_MALLOC)
  73. return _aligned_malloc(size, alignment);
  74. #else
  75. BOOST_ASSERT(alignment >= sizeof(void*));
  76. void* p = std::malloc(size + alignment);
  77. if (p)
  78. {
  79. unsigned char* q = static_cast< unsigned char* >(p) + alignment;
  80. #if defined(BOOST_HAS_INTPTR_T)
  81. q = (unsigned char*)((uintptr_t)q & (~(uintptr_t)(alignment - 1u)));
  82. #else
  83. q -= ((std::size_t)q & (std::size_t)(alignment - 1u));
  84. #endif
  85. // Here we assume that the system allocator aligns to 4 bytes at the very least.
  86. // Therefore we will always have at least 4 bytes before the aligned pointer.
  87. const uint32_t diff = q - static_cast< unsigned char* >(p);
  88. p = q;
  89. *reinterpret_cast< uint32_t* >(q - 4u) = diff;
  90. }
  91. return p;
  92. #endif
  93. }
  94. /*!
  95. * Frees memory allocated with \c malloc_aligned.
  96. */
  97. inline void free_aligned(void* p)
  98. {
  99. #if defined(BOOST_LOG_HAS_POSIX_MEMALIGN) || defined(BOOST_LOG_HAS_FREEABLE_MEMALIGN)
  100. free(p);
  101. #elif defined(BOOST_LOG_HAS_MSVC_ALIGNED_MALLOC)
  102. _aligned_free(p);
  103. #else
  104. if (p)
  105. {
  106. unsigned char* const q = static_cast< unsigned char* >(p);
  107. const uint32_t diff = *reinterpret_cast< uint32_t* >(q - 4u);
  108. std::free(q - diff);
  109. }
  110. #endif
  111. }
  112. } // namespace aux
  113. BOOST_LOG_CLOSE_NAMESPACE // namespace log
  114. } // namespace boost
  115. #include <boost/log/detail/footer.hpp>
  116. #endif // BOOST_LOG_DETAIL_MALLOC_ALIGNED_HPP_INCLUDED_