1 /* 2 * A memory pool allocating a region at a time from the system. 3 * 4 * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include "memory_incremental.h" 23 24 #include <stdlib.h> 25 26 /* Initialise the memory pool with an optional 'limit' in pages. */ 27 28 MemoryIncremental::MemoryIncremental(unsigned int limit, offset_t region_size) 29 : _limit(limit), _region_size(region_size) 30 { 31 _limited = true; 32 } 33 34 MemoryIncremental::MemoryIncremental() 35 : _region_size(PAGE_SIZE) 36 { 37 _limited = false; 38 } 39 40 /* Allocate a block of the given 'size'. */ 41 42 Region *MemoryIncremental::allocate(offset_t size) 43 { 44 /* Attempt to allocate aligned memory. */ 45 46 void *current; 47 48 /* Make the size appropriate for the invocation. */ 49 50 size = round_multiple(size, PAGE_SIZE); 51 52 if (posix_memalign(¤t, size, size)) 53 return NULL; 54 55 return new Region((offset_t) current, (offset_t) current + size); 56 } 57 58 /* Allocate a new region of the given 'size' rounded to the nearest page. */ 59 60 Region *MemoryIncremental::region(offset_t size) 61 { 62 std::lock_guard<std::mutex> guard(_lock); 63 64 offset_t rounded = round(size, PAGE_SIZE); 65 offset_t pages = rounded / PAGE_SIZE; 66 67 /* Check for sufficient pages. */ 68 69 if (!_limited || (_limit >= pages)) 70 { 71 /* Attempt to allocate aligned memory. */ 72 73 Region *region = allocate(rounded); 74 75 if (region == NULL) 76 return NULL; 77 78 if (_limited) 79 _limit -= pages; 80 81 return region; 82 } 83 84 /* Return no region without sufficient pages. */ 85 86 else 87 return NULL; 88 } 89 90 Region *MemoryIncremental::region() 91 { 92 return region(_region_size); 93 } 94 95 /* Release the allocated 'region'. */ 96 97 void MemoryIncremental::release(Region *region) 98 { 99 std::lock_guard<std::mutex> guard(_lock); 100 101 offset_t rounded = round(region->size(), PAGE_SIZE); 102 offset_t pages = rounded / PAGE_SIZE; 103 104 if (_limited) 105 _limit += pages; 106 107 delete region; 108 } 109 110 // vim: tabstop=4 expandtab shiftwidth=4