memalign.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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. size_t extra_size;
  49. /* Verify that alignment is a power of two */
  50. assert((alignment && !(alignment & (alignment - 1))) != 0);
  51. memptr = NULL;
  52. /* extra_size denotes the worst-case scenario. Because memcpy() is used, at
  53. * least HEADER_SIZE is needed for no memory overlap. */
  54. extra_size = sizeof(raw_block_header_t) + alignment - 1;
  55. if(2 * (size + extra_size) < SYS_ALLOC_SIZE - sizeof(raw_block_header_t) -
  56. sizeof(freelist_rb_t)) {
  57. /* Search the available freelist-organized raw blocks */
  58. SLIST_FOREACH(raw_block, &systemallocator.rb_head, pointers) {
  59. #ifdef TRYLOCK_ON_MALLOC
  60. if(TRYLOCK_RAW_BLOCK(raw_block) == 0) {
  61. #else /* TRYLOCK_ON_MALLOC */
  62. LOCK_RAW_BLOCK(raw_block);
  63. #endif /* TRYLOCK_ON_MALLOC */
  64. encapsulated_rb = (freelist_rb_t *)
  65. ((uintptr_t) raw_block + sizeof(raw_block_header_t));
  66. memptr = freelist_memalign(encapsulated_rb, alignment, size);
  67. UNLOCK_RAW_BLOCK(raw_block);
  68. if(memptr != NULL) {
  69. break;
  70. }
  71. #ifdef TRYLOCK_ON_MALLOC
  72. }
  73. #endif /* TRYLOCK_ON_MALLOC */
  74. }
  75. if(memptr == NULL) { /* no block was found, try to create a new one */
  76. raw_block = create_raw_block((size_t) SYS_ALLOC_SIZE,
  77. DEFAULT_RB_TYPE);
  78. if(raw_block != NULL) {
  79. LOCK_GLOBAL();
  80. LOCK_RAW_BLOCK(raw_block);
  81. SLIST_INSERT_HEAD(&systemallocator.rb_head, raw_block, pointers);
  82. UNLOCK_GLOBAL();
  83. encapsulated_rb = (DEFAULT_RB_T *)
  84. ((uintptr_t) raw_block + sizeof(raw_block_header_t));
  85. memptr = freelist_memalign(encapsulated_rb, alignment, size);
  86. UNLOCK_RAW_BLOCK(raw_block);
  87. }
  88. }
  89. } else { /* A big block has to be created */
  90. memptr = (void *)create_raw_block(size + extra_size +
  91. sizeof(raw_block_header_t), BIGBLOCK);
  92. if(memptr != NULL) {
  93. memptr = (void *)((uintptr_t) memptr + sizeof(raw_block_header_t));
  94. /* Check if alignment is needed */
  95. if(((uintptr_t) memptr) % alignment != 0) {
  96. size_t padding = (- (size_t) memptr) & (alignment - 1);
  97. while(padding < sizeof(raw_block_header_t)) {
  98. padding += alignment;
  99. }
  100. /* Sometimes a deadlock is observed unless the old mutex is
  101. * destroyed. */
  102. DESTROY_RAW_BLOCK_LOCK(((raw_block_header_t *) memptr));
  103. /* Copy the raw block's header to the new location */
  104. memcpy((void *)((uintptr_t) memptr -
  105. sizeof(raw_block_header_t) + padding),
  106. (void *)((uintptr_t) memptr -
  107. sizeof(raw_block_header_t)),
  108. sizeof(raw_block_header_t)
  109. );
  110. /* Update *memptr */
  111. memptr = (void *)((uintptr_t) memptr + padding);
  112. /* Update big block's size and requested size */
  113. raw_block_header_t *aligned_header =
  114. (raw_block_header_t *)((uintptr_t) memptr -
  115. sizeof(raw_block_header_t));
  116. INIT_RAW_BLOCK_LOCK(aligned_header);
  117. LOCK_RAW_BLOCK(aligned_header);
  118. aligned_header->size -= padding;
  119. #ifdef REQUEST_SIZE_INFO
  120. aligned_header->requested_size = size;
  121. #endif /* REQUEST_SIZE_INFO */
  122. UNLOCK_RAW_BLOCK(aligned_header);
  123. }
  124. #ifdef WITH_DEBUG
  125. LOCK_GLOBAL();
  126. LOCK_RAW_BLOCK(((raw_block_header_t *) ((uintptr_t) memptr -
  127. sizeof(raw_block_header_t))));
  128. SLIST_INSERT_HEAD(&systemallocator.bb_head,
  129. (raw_block_header_t *) ((uintptr_t) memptr -
  130. sizeof(raw_block_header_t)), pointers);
  131. UNLOCK_RAW_BLOCK(((raw_block_header_t *) ((uintptr_t) memptr -
  132. sizeof(raw_block_header_t))));
  133. UNLOCK_GLOBAL();
  134. #endif /* WITH_DEBUG */
  135. }
  136. }
  137. if(memptr != NULL) {
  138. /* Assert that the returned address is a multiple of alignment */
  139. assert((uintptr_t) memptr % alignment == 0);
  140. #ifdef REQUEST_SIZE_INFO
  141. UPDATE_GLOBAL_STATS(MEMALIGN, size);
  142. #else /* REQUEST_SIZE_INFO */
  143. UPDATE_GLOBAL_STATS(MEMALIGN);
  144. #endif /* REQUEST_SIZE_INFO */
  145. }
  146. MEM_TRACE("dmmlib - ma %p %zu %zu\n", *memptr, alignment, size);
  147. return memptr;
  148. }
  149. /** The function posix_memalign() allocates size bytes and places the address of
  150. * the allocated memory in *memptr. The address of the allocated memory will be
  151. * a multiple of alignment, which must be a power of two and a multiple of
  152. * sizeof(void *). If size is 0, then posix_memalign() returns either NULL, or a
  153. * unique pointer value that can later be successfully passed to free().
  154. */
  155. int posix_memalign(void **memptr, size_t alignment, size_t size) {
  156. void *ptr = NULL;
  157. /* Input check */
  158. if(size == 0 || (alignment & 1) != 0 || alignment % sizeof(void *) != 0) {
  159. return -1;
  160. }
  161. ptr = memalign(alignment, size);
  162. if(ptr != NULL) {
  163. *memptr = ptr;
  164. return 0;
  165. }
  166. return -1;
  167. }