blob: 46198177e8d649d661dd0da3e790a5fd6817a358 [file] [log] [blame]
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
Dimitry Ivanovbcc4da92017-02-15 15:31:13 -08003 * All rights reserved.
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -07004 *
Dimitry Ivanovbcc4da92017-02-15 15:31:13 -08005 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070014 *
Dimitry Ivanovbcc4da92017-02-15 15:31:13 -080015 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070027 */
28
Elliott Hughescbc80ba2018-02-13 14:26:29 -080029#pragma once
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070030
Dan Albert1c78cb02017-10-11 11:25:25 -070031#include <errno.h>
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070032#include <stdlib.h>
33#include <sys/cdefs.h>
34#include <sys/mman.h>
Elliott Hughes99d54652018-08-22 10:36:23 -070035#include <sys/prctl.h>
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070036#include <stddef.h>
37#include <unistd.h>
38
Christopher Ferris7a3681e2017-04-24 17:48:32 -070039#include <async_safe/log.h>
40
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070041const uint32_t kSmallObjectMaxSizeLog2 = 10;
42const uint32_t kSmallObjectMinSizeLog2 = 4;
43const uint32_t kSmallObjectAllocatorsCount = kSmallObjectMaxSizeLog2 - kSmallObjectMinSizeLog2 + 1;
44
45class LinkerSmallObjectAllocator;
46
47// This structure is placed at the beginning of each addressable page
48// and has all information we need to find the corresponding memory allocator.
49struct page_info {
50 char signature[4];
51 uint32_t type;
52 union {
53 // we use allocated_size for large objects allocator
54 size_t allocated_size;
55 // and allocator_addr for small ones.
56 LinkerSmallObjectAllocator* allocator_addr;
57 };
Dimitry Ivanov3edc5c42016-01-21 10:55:40 -080058} __attribute__((aligned(16)));
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070059
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070060struct small_object_block_record {
61 small_object_block_record* next;
62 size_t free_blocks_cnt;
63};
64
Vic Yang54938512018-12-02 23:46:26 -080065// This structure is placed at the beginning of each page managed by
66// LinkerSmallObjectAllocator. Note that a page_info struct is expected at the
67// beginning of each page as well, and therefore this structure contains a
68// page_info as its *first* field.
69struct small_object_page_info {
70 page_info info; // Must be the first field.
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070071
Vic Yang54938512018-12-02 23:46:26 -080072 // Doubly linked list for traversing all pages allocated by a
73 // LinkerSmallObjectAllocator.
74 small_object_page_info* next_page;
75 small_object_page_info* prev_page;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070076
Vic Yang54938512018-12-02 23:46:26 -080077 // Linked list containing all free blocks in this page.
78 small_object_block_record* free_block_list;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070079
Vic Yang54938512018-12-02 23:46:26 -080080 // Free/allocated blocks counter.
81 size_t free_blocks_cnt;
82 size_t allocated_blocks_cnt;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070083};
84
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070085class LinkerSmallObjectAllocator {
86 public:
Dimitry Ivanov65707b62016-07-29 13:25:33 -070087 LinkerSmallObjectAllocator(uint32_t type, size_t block_size);
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070088 void* alloc();
89 void free(void* ptr);
90
91 size_t get_block_size() const { return block_size_; }
92 private:
93 void alloc_page();
Vic Yang54938512018-12-02 23:46:26 -080094 void free_page(small_object_page_info* page);
95 void add_to_page_list(small_object_page_info* page);
96 void remove_from_page_list(small_object_page_info* page);
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070097
98 uint32_t type_;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070099 size_t block_size_;
100
101 size_t free_pages_cnt_;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700102
Vic Yang54938512018-12-02 23:46:26 -0800103 small_object_page_info* page_list_;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700104};
105
106class LinkerMemoryAllocator {
107 public:
Dimitry Ivanov65707b62016-07-29 13:25:33 -0700108 constexpr LinkerMemoryAllocator() : allocators_(nullptr), allocators_buf_() {}
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700109 void* alloc(size_t size);
110
111 // Note that this implementation of realloc never shrinks allocation
112 void* realloc(void* ptr, size_t size);
113 void free(void* ptr);
114 private:
115 void* alloc_mmap(size_t size);
116 page_info* get_page_info(void* ptr);
117 LinkerSmallObjectAllocator* get_small_object_allocator(uint32_t type);
Dimitry Ivanov65707b62016-07-29 13:25:33 -0700118 void initialize_allocators();
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700119
Dimitry Ivanov65707b62016-07-29 13:25:33 -0700120 LinkerSmallObjectAllocator* allocators_;
121 uint8_t allocators_buf_[sizeof(LinkerSmallObjectAllocator)*kSmallObjectAllocatorsCount];
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700122};