/* Jitter: allocated heap memory blocks. Copyright (C) 2020 Luca Saiu Written by Luca Saiu This file is part of Jitter. Jitter is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Jitter is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Jitter. If not, see . */ #include #include #include /* Include the right header, according to the selected implementation. */ #if defined (JITTER_ALIGNED_BLOCK_USE_MMAP) # include /* For sysconf . */ # include /* For mmap and munmap . */ #elif defined (JITTER_ALIGNED_BLOCK_USE_ALIGNED_ALLOC) # include #elif defined (JITTER_ALIGNED_BLOCK_USE_POSIX_MEMALIGN) # include #elif defined (JITTER_ALIGNED_BLOCK_USE_FALLBACK) # include #else # error "no aligned block implementation defined. This should never happen." #endif /* Aligned block allocation and destruction. * ************************************************************************** */ void * jitter_aligned_block_make (jitter_aligned_block_id *id, size_t alignment_in_bytes, size_t size_in_bytes) { void *res; /* The mmap and malloc implementations share the strategy of allocating a larger block guaranteed to contain an aligned block inside. */ #if defined (JITTER_ALIGNED_BLOCK_USE_MMAP) \ || defined (JITTER_ALIGNED_BLOCK_USE_FALLBACK) /* Allocate a larger buffer which is guaranteed to contain an aligned buffer of the required size as a sub-buffer. Keep a pointer to the initial buffer, in order to be able to free it later, in the block id. */ size_t allocated_size_in_bytes; if (size_in_bytes < alignment_in_bytes) allocated_size_in_bytes = alignment_in_bytes * 2; else allocated_size_in_bytes = size_in_bytes * 2; void *initial_pointer; #endif #if defined (JITTER_ALIGNED_BLOCK_USE_MMAP) /* Allocate a larger block. */ initial_pointer = mmap (NULL, allocated_size_in_bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (initial_pointer == NULL) jitter_fatal ("mmap failed"); /* Find the aligned part of the mapping, which is the only part we are interested in. */ res = ((void *) JITTER_NEXT_MULTIPLE_OF_POWER_OF_TWO ((jitter_uint) initial_pointer, alignment_in_bytes)); id->initial_map = res; id->mapping_length_in_bytes = size_in_bytes; /* Unmap the misaligned part (which means: aligned to a double memory page, but not to the required alignment) at the beginning and the end. This also checks that the block alignment is a multiple of double the page size, as munmap fails otherwise. */ void *misaligned_before = initial_pointer; size_t misaligned_before_length = (char *) res - (char *) initial_pointer; void *misaligned_after = (char *) res + size_in_bytes; size_t misaligned_after_length = (((char *) initial_pointer + allocated_size_in_bytes) - (char *) misaligned_after); if (misaligned_before_length > 0) if (munmap (misaligned_before, misaligned_before_length) != 0) jitter_fatal ("munmap failed (%li B not an even multiple of the page " "size?)", (long) alignment_in_bytes); if (misaligned_after_length > 0) if (munmap (misaligned_after, misaligned_after_length) != 0) jitter_fatal ("munmap failed (%li B not an even multiple of the page " "size?)", (long) alignment_in_bytes); #elif defined (JITTER_ALIGNED_BLOCK_USE_ALIGNED_ALLOC) /* According to the specification aligned_alloc requires that the size be a multiple of the alignment -- thanks to Bruno Haible for letting me notice. This solution is therefore, in theory (in practice alignment_in_bytes will usually be the same as size_in_bytes), wasteful. */ size_in_bytes = JITTER_NEXT_MULTIPLE_OF_POWER_OF_TWO (size_in_bytes, alignment_in_bytes); res = aligned_alloc (alignment_in_bytes, size_in_bytes); if (res == NULL) jitter_fatal ("aligned_alloc failed"); id->aligned_alloced_buffer = res; #elif defined (JITTER_ALIGNED_BLOCK_USE_POSIX_MEMALIGN) if (posix_memalign (& res, alignment_in_bytes, size_in_bytes) != 0) jitter_fatal ("posix_memalign failed"); id->posix_memaligned_buffer = res; #elif defined (JITTER_ALIGNED_BLOCK_USE_FALLBACK) initial_pointer = jitter_xmalloc (allocated_size_in_bytes); res = ((void *) JITTER_NEXT_MULTIPLE_OF_POWER_OF_TWO ((jitter_uint) initial_pointer, alignment_in_bytes)); id->initial_pointer = initial_pointer; #else # error "no aligned block implementation defined. This should never happen." #endif return res; } void jitter_aligned_block_destroy (jitter_aligned_block_id id) { #if defined (JITTER_ALIGNED_BLOCK_USE_MMAP) munmap (id.initial_map, id.mapping_length_in_bytes); #elif defined (JITTER_ALIGNED_BLOCK_USE_ALIGNED_ALLOC) free (id.aligned_alloced_buffer); #elif defined (JITTER_ALIGNED_BLOCK_USE_POSIX_MEMALIGN) free (id.posix_memaligned_buffer); #elif defined (JITTER_ALIGNED_BLOCK_USE_FALLBACK) free (id.initial_pointer); #else # error "no aligned block implementation defined. This should never happen." #endif }