| 2291 | } |
| 2292 | |
| 2293 | static void* |
| 2294 | _rpmalloc_aligned_allocate(heap_t* heap, size_t alignment, size_t size) { |
| 2295 | if (alignment <= SMALL_GRANULARITY) |
| 2296 | return _rpmalloc_allocate(heap, size); |
| 2297 | |
| 2298 | #if ENABLE_VALIDATE_ARGS |
| 2299 | if ((size + alignment) < size) { |
| 2300 | errno = EINVAL; |
| 2301 | return 0; |
| 2302 | } |
| 2303 | if (alignment & (alignment - 1)) { |
| 2304 | errno = EINVAL; |
| 2305 | return 0; |
| 2306 | } |
| 2307 | #endif |
| 2308 | |
| 2309 | if ((alignment <= SPAN_HEADER_SIZE) && ((size + SPAN_HEADER_SIZE) < _memory_medium_size_limit)) { |
| 2310 | // If alignment is less or equal to span header size (which is power of two), |
| 2311 | // and size aligned to span header size multiples is less than size + alignment, |
| 2312 | // then use natural alignment of blocks to provide alignment |
| 2313 | size_t multiple_size = size ? (size + (SPAN_HEADER_SIZE - 1)) & ~(uintptr_t)(SPAN_HEADER_SIZE - 1) : SPAN_HEADER_SIZE; |
| 2314 | rpmalloc_assert(!(multiple_size % SPAN_HEADER_SIZE), "Failed alignment calculation"); |
| 2315 | if (multiple_size <= (size + alignment)) |
| 2316 | return _rpmalloc_allocate(heap, multiple_size); |
| 2317 | } |
| 2318 | |
| 2319 | void* ptr = 0; |
| 2320 | size_t align_mask = alignment - 1; |
| 2321 | if (alignment <= _memory_page_size) { |
| 2322 | ptr = _rpmalloc_allocate(heap, size + alignment); |
| 2323 | if ((uintptr_t)ptr & align_mask) { |
| 2324 | ptr = (void*)(((uintptr_t)ptr & ~(uintptr_t)align_mask) + alignment); |
| 2325 | //Mark as having aligned blocks |
| 2326 | span_t* span = (span_t*)((uintptr_t)ptr & _memory_span_mask); |
| 2327 | span->flags |= SPAN_FLAG_ALIGNED_BLOCKS; |
| 2328 | } |
| 2329 | return ptr; |
| 2330 | } |
| 2331 | |
| 2332 | // Fallback to mapping new pages for this request. Since pointers passed |
| 2333 | // to rpfree must be able to reach the start of the span by bitmasking of |
| 2334 | // the address with the span size, the returned aligned pointer from this |
| 2335 | // function must be with a span size of the start of the mapped area. |
| 2336 | // In worst case this requires us to loop and map pages until we get a |
| 2337 | // suitable memory address. It also means we can never align to span size |
| 2338 | // or greater, since the span header will push alignment more than one |
| 2339 | // span size away from span start (thus causing pointer mask to give us |
| 2340 | // an invalid span start on free) |
| 2341 | if (alignment & align_mask) { |
| 2342 | errno = EINVAL; |
| 2343 | return 0; |
| 2344 | } |
| 2345 | if (alignment >= _memory_span_size) { |
| 2346 | errno = EINVAL; |
| 2347 | return 0; |
| 2348 | } |
| 2349 | |
| 2350 | size_t extra_pages = alignment / _memory_page_size; |
no test coverage detected