Browse Source

small fixes to memalign() when using big blocks

Ioannis Koutras 11 years ago
parent
commit
97e1dee818
2 changed files with 29 additions and 3 deletions
  1. 5 1
      private-include/locks.h
  2. 24 2
      src/memalign.c

+ 5 - 1
private-include/locks.h

@@ -37,8 +37,10 @@
 #define UNLOCK_GLOBAL() pthread_mutex_unlock(&systemallocator.creation_mutex)
 /** Locks a specific raw block */
 #define LOCK_RAW_BLOCK(rb) pthread_mutex_lock(&rb->mutex)
-/** Initialized a raw block lock */
+/** Initializes a raw block lock */
 #define INIT_RAW_BLOCK_LOCK(rb) pthread_mutex_init(&rb->mutex, NULL);
+/** Destroys a raw block lock */
+#define DESTROY_RAW_BLOCK_LOCK(rb) pthread_mutex_destroy(&rb->mutex);
 /** Unlocks a specific raw block */
 #define UNLOCK_RAW_BLOCK(rb) pthread_mutex_unlock(&rb->mutex)
 
@@ -53,6 +55,8 @@
 /** Does nothing. */
 #define INIT_RAW_BLOCK_LOCK(RB)
 /** Does nothing. */
+#define DESTROY_RAW_BLOCK_LOCK(RB)
+/** Does nothing. */
 #define UNLOCK_RAW_BLOCK(RB)
 
 #endif /* HAVE_LOCKS */

+ 24 - 2
src/memalign.c

@@ -79,8 +79,23 @@ int posix_memalign(void **memptr, size_t alignment, size_t size) {
 
             /* A big block has to be created */
 
-            *memptr = (void *)create_raw_block(size + alignment - 1 +
-                    sizeof(raw_block_header_t), BIGBLOCK);
+            /* If the alignment size is smaller than the raw block header size,
+             * the padding may cause an overlap between the old and the new
+             * (aligned) raw block header. In order to ensure this is not
+             * happening and memcpy() is safe to be used, the alignment size is
+             * increased until it is bigger than the header size.
+             */
+            unsigned int counter;
+            if(alignment < sizeof(raw_block_header_t)) {
+                size_t new_alignment = alignment;
+                for(counter = 0; new_alignment < sizeof(raw_block_header_t);
+                        counter++) {
+                    new_alignment += alignment;
+                }
+            }
+
+            *memptr = (void *)create_raw_block(size + (counter + 1) * alignment
+                    - 1 + sizeof(raw_block_header_t), BIGBLOCK);
             if(*memptr != NULL) {
 
                 *memptr = (void *)((uintptr_t) *memptr +
@@ -89,6 +104,12 @@ int posix_memalign(void **memptr, size_t alignment, size_t size) {
                 /* Check if alignment is needed */
                 if(((uintptr_t) *memptr) % alignment != 0) {
                     size_t padding = (- (size_t) *memptr) & (alignment - 1);
+                    padding += counter * alignment;
+
+                    /* Sometimes a deadlock is observed unless the old mutex is
+                     * destroyed.
+                     */
+                    DESTROY_RAW_BLOCK_LOCK(((raw_block_header_t *) *memptr));
 
                     /* Copy the raw block's header to the new location */
                     memcpy((void *)((uintptr_t) *memptr
@@ -105,6 +126,7 @@ int posix_memalign(void **memptr, size_t alignment, size_t size) {
                     raw_block_header_t *aligned_header =
                         (raw_block_header_t *)((uintptr_t) *memptr -
                                 sizeof(raw_block_header_t));
+                    INIT_RAW_BLOCK_LOCK(aligned_header);
                     LOCK_RAW_BLOCK(aligned_header);
                     aligned_header->size -= padding;
 #ifdef REQUEST_SIZE_INFO