blob: 75cbd9df7e0000fa7fd4a9f92f41734db713803b [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
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070039const uint32_t kSmallObjectMaxSizeLog2 = 10;
40const uint32_t kSmallObjectMinSizeLog2 = 4;
41const uint32_t kSmallObjectAllocatorsCount = kSmallObjectMaxSizeLog2 - kSmallObjectMinSizeLog2 + 1;
42
Ryan Prichard083d8502019-01-24 13:47:13 -080043class BionicSmallObjectAllocator;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070044
45// This structure is placed at the beginning of each addressable page
46// and has all information we need to find the corresponding memory allocator.
47struct page_info {
48 char signature[4];
49 uint32_t type;
50 union {
51 // we use allocated_size for large objects allocator
52 size_t allocated_size;
53 // and allocator_addr for small ones.
Ryan Prichard083d8502019-01-24 13:47:13 -080054 BionicSmallObjectAllocator* allocator_addr;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070055 };
Vic Yang259429b2018-12-04 23:59:57 -080056};
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070057
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070058struct small_object_block_record {
59 small_object_block_record* next;
60 size_t free_blocks_cnt;
61};
62
Vic Yang54938512018-12-02 23:46:26 -080063// This structure is placed at the beginning of each page managed by
Ryan Prichard083d8502019-01-24 13:47:13 -080064// BionicSmallObjectAllocator. Note that a page_info struct is expected at the
Vic Yang54938512018-12-02 23:46:26 -080065// beginning of each page as well, and therefore this structure contains a
66// page_info as its *first* field.
67struct small_object_page_info {
68 page_info info; // Must be the first field.
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070069
Vic Yang54938512018-12-02 23:46:26 -080070 // Doubly linked list for traversing all pages allocated by a
Ryan Prichard083d8502019-01-24 13:47:13 -080071 // BionicSmallObjectAllocator.
Vic Yang54938512018-12-02 23:46:26 -080072 small_object_page_info* next_page;
73 small_object_page_info* prev_page;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070074
Vic Yang54938512018-12-02 23:46:26 -080075 // Linked list containing all free blocks in this page.
76 small_object_block_record* free_block_list;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070077
Vic Yang259429b2018-12-04 23:59:57 -080078 // Free blocks counter.
Vic Yang54938512018-12-02 23:46:26 -080079 size_t free_blocks_cnt;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070080};
81
Ryan Prichard083d8502019-01-24 13:47:13 -080082class BionicSmallObjectAllocator {
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070083 public:
Ryan Prichard083d8502019-01-24 13:47:13 -080084 BionicSmallObjectAllocator(uint32_t type, size_t block_size);
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070085 void* alloc();
86 void free(void* ptr);
87
88 size_t get_block_size() const { return block_size_; }
89 private:
90 void alloc_page();
Vic Yang54938512018-12-02 23:46:26 -080091 void free_page(small_object_page_info* page);
92 void add_to_page_list(small_object_page_info* page);
93 void remove_from_page_list(small_object_page_info* page);
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070094
Vic Yang259429b2018-12-04 23:59:57 -080095 const uint32_t type_;
96 const size_t block_size_;
97 const size_t blocks_per_page_;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -070098
99 size_t free_pages_cnt_;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700100
Vic Yang54938512018-12-02 23:46:26 -0800101 small_object_page_info* page_list_;
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700102};
103
Ryan Prichard083d8502019-01-24 13:47:13 -0800104class BionicAllocator {
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700105 public:
Ryan Prichard083d8502019-01-24 13:47:13 -0800106 constexpr BionicAllocator() : allocators_(nullptr), allocators_buf_() {}
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700107 void* alloc(size_t size);
108
109 // Note that this implementation of realloc never shrinks allocation
110 void* realloc(void* ptr, size_t size);
111 void free(void* ptr);
112 private:
113 void* alloc_mmap(size_t size);
114 page_info* get_page_info(void* ptr);
Ryan Prichard083d8502019-01-24 13:47:13 -0800115 BionicSmallObjectAllocator* get_small_object_allocator(uint32_t type);
Dimitry Ivanov65707b62016-07-29 13:25:33 -0700116 void initialize_allocators();
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700117
Ryan Prichard083d8502019-01-24 13:47:13 -0800118 BionicSmallObjectAllocator* allocators_;
119 uint8_t allocators_buf_[sizeof(BionicSmallObjectAllocator)*kSmallObjectAllocatorsCount];
Dmitriy Ivanov19656ce2015-03-10 17:48:27 -0700120};