memalign.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * Copyright Institute of Communication and Computer Systems (ICCS)
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. /**
  18. * @file src/memalign.c
  19. * @author Ioannis Koutras (joko@microlab.ntua.gr)
  20. * @date November 2012
  21. *
  22. * @brief Implementation of memory-aligned allocation calls for
  23. * freelist-organized raw blocks.
  24. */
  25. #include "dmmlib/memalign.h"
  26. #include <inttypes.h>
  27. #include <sys/mman.h>
  28. #include <assert.h>
  29. #include "dmmlib/config.h"
  30. #include "dmmlib/dmmlib.h"
  31. #include "memcpy.h"
  32. #include "default_rb.h"
  33. #include "dmmlib_trace.h"
  34. #include "locks.h"
  35. #include "statistics.h"
  36. #ifdef BITMAP_RB_ONLY
  37. #error Current memory-aligned allocation implementation supports only \
  38. freelist-organized raw blocks.
  39. #endif /* BITMAP_RB_ONLY */
  40. /** The obsolete function memalign() allocates size bytes and returns a pointer
  41. * to the allocated memory. The memory address will be a multiple of alignment,
  42. * which must be a power of two.
  43. */
  44. void *memalign(size_t alignment, size_t size) {
  45. void *memptr;
  46. DEFAULT_RB_T *encapsulated_rb;
  47. raw_block_header_t *raw_block;
  48. /* Verify that alignment is a power of two */
  49. assert((alignment && !(alignment & (alignment - 1))) != 0);
  50. memptr = NULL;
  51. /* Search the available freelist-organized raw blocks for a block whose size
  52. * is size + alignment - 1 */
  53. SLIST_FOREACH(raw_block, &systemallocator.rb_head, pointers) {
  54. #ifdef TRYLOCK_ON_MALLOC
  55. if(TRYLOCK_RAW_BLOCK(raw_block) == 0) {
  56. #else /* TRYLOCK_ON_MALLOC */
  57. LOCK_RAW_BLOCK(raw_block);
  58. #endif /* TRYLOCK_ON_MALLOC */
  59. encapsulated_rb = (freelist_rb_t *)
  60. ((uintptr_t) raw_block + sizeof(raw_block_header_t));
  61. memptr = freelist_memalign(encapsulated_rb, alignment, size);
  62. UNLOCK_RAW_BLOCK(raw_block);
  63. if(memptr != NULL) {
  64. break;
  65. }
  66. #ifdef TRYLOCK_ON_MALLOC
  67. }
  68. #endif /* TRYLOCK_ON_MALLOC */
  69. }
  70. if(memptr == NULL) {
  71. if( 2 * (size + alignment - 1) > SYS_ALLOC_SIZE -
  72. sizeof(raw_block_header_t) - sizeof(freelist_rb_t)) {
  73. /* A big block has to be created */
  74. /* extra_size denotes the worst-case scenario. Because memcpy() is
  75. * used, at least HEADER_SIZE is needed for no memory overlap. */
  76. size_t extra_size = sizeof(raw_block_header_t) + alignment - 1;
  77. memptr = (void *)create_raw_block(size + extra_size +
  78. sizeof(raw_block_header_t), BIGBLOCK);
  79. if(memptr != NULL) {
  80. memptr = (void *)((uintptr_t) memptr +
  81. sizeof(raw_block_header_t));
  82. /* Check if alignment is needed */
  83. if(((uintptr_t) memptr) % alignment != 0) {
  84. size_t padding = (- (size_t) memptr) & (alignment - 1);
  85. while(padding < sizeof(raw_block_header_t)) {
  86. padding += alignment;
  87. }
  88. /* Sometimes a deadlock is observed unless the old mutex is
  89. * destroyed.
  90. */
  91. DESTROY_RAW_BLOCK_LOCK(((raw_block_header_t *) memptr));
  92. /* Copy the raw block's header to the new location */
  93. memcpy((void *)((uintptr_t) memptr
  94. - sizeof(raw_block_header_t) + padding),
  95. (void *)((uintptr_t) memptr
  96. - sizeof(raw_block_header_t)),
  97. sizeof(raw_block_header_t)
  98. );
  99. /* Update *memptr */
  100. memptr = (void *)((uintptr_t) memptr + padding);
  101. /* Update big block's size and requested size */
  102. raw_block_header_t *aligned_header =
  103. (raw_block_header_t *)((uintptr_t) memptr -
  104. sizeof(raw_block_header_t));
  105. INIT_RAW_BLOCK_LOCK(aligned_header);
  106. LOCK_RAW_BLOCK(aligned_header);
  107. aligned_header->size -= padding;
  108. #ifdef REQUEST_SIZE_INFO
  109. aligned_header->requested_size = size;
  110. #endif /* REQUEST_SIZE_INFO */
  111. UNLOCK_RAW_BLOCK(aligned_header);
  112. }
  113. #ifdef WITH_DEBUG
  114. LOCK_GLOBAL();
  115. LOCK_RAW_BLOCK(((raw_block_header_t *) ((uintptr_t) memptr -
  116. sizeof(raw_block_header_t))));
  117. SLIST_INSERT_HEAD(&systemallocator.bb_head,
  118. (raw_block_header_t *) ((uintptr_t) memptr -
  119. sizeof(raw_block_header_t)), pointers);
  120. UNLOCK_RAW_BLOCK(((raw_block_header_t *) ((uintptr_t) memptr -
  121. sizeof(raw_block_header_t))));
  122. UNLOCK_GLOBAL();
  123. #endif /* WITH_DEBUG */
  124. }
  125. } else { /* Create a new raw block and use it */
  126. raw_block = create_raw_block((size_t) SYS_ALLOC_SIZE,
  127. DEFAULT_RB_TYPE);
  128. if(raw_block != NULL) {
  129. LOCK_GLOBAL();
  130. LOCK_RAW_BLOCK(raw_block);
  131. SLIST_INSERT_HEAD(&systemallocator.rb_head, raw_block, pointers);
  132. UNLOCK_GLOBAL();
  133. encapsulated_rb = (DEFAULT_RB_T *)
  134. ((uintptr_t) raw_block + sizeof(raw_block_header_t));
  135. memptr = freelist_memalign(encapsulated_rb, alignment, size);
  136. UNLOCK_RAW_BLOCK(raw_block);
  137. }
  138. }
  139. }
  140. if(memptr != NULL) {
  141. /* Assert that the returned address is a multiple of alignment */
  142. assert((uintptr_t) memptr % alignment == 0);
  143. #ifdef REQUEST_SIZE_INFO
  144. UPDATE_GLOBAL_STATS(MEMALIGN, size);
  145. #else /* REQUEST_SIZE_INFO */
  146. UPDATE_GLOBAL_STATS(MEMALIGN);
  147. #endif /* REQUEST_SIZE_INFO */
  148. }
  149. MEM_TRACE("dmmlib - ma %p %zu %zu\n", *memptr, alignment, size);
  150. return memptr;
  151. }
  152. /** The function posix_memalign() allocates size bytes and places the address of
  153. * the allocated memory in *memptr. The address of the allocated memory will be
  154. * a multiple of alignment, which must be a power of two and a multiple of
  155. * sizeof(void *). If size is 0, then posix_memalign() returns either NULL, or a
  156. * unique pointer value that can later be successfully passed to free().
  157. */
  158. int posix_memalign(void **memptr, size_t alignment, size_t size) {
  159. void *ptr = NULL;
  160. /* Input check */
  161. if(size == 0 || (alignment & 1) != 0 || alignment % sizeof(void *) != 0) {
  162. return -1;
  163. }
  164. ptr = memalign(alignment, size);
  165. if(ptr != NULL) {
  166. *memptr = ptr;
  167. return 0;
  168. }
  169. return -1;
  170. }