1 /* 2 * An access map providing memory corresponding to file regions. 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 "access_map.h" 23 24 /* Return the flexpage supporting 'position'. */ 25 26 Flexpage *AccessMap::find(offset_t position) 27 { 28 std::lock_guard<std::mutex> guard(_lock); 29 30 _AccessMap::iterator it = _flexpages.upper_bound(position); 31 32 if ((_flexpages.size() > 0) && (it != _flexpages.begin())) 33 { 34 it--; 35 36 if (it->second->supports_position(position)) 37 return it->second; 38 } 39 40 return NULL; 41 } 42 43 /* Insert a mapping for 'flexpage'. */ 44 45 void AccessMap::insert(Flexpage *flexpage) 46 { 47 std::lock_guard<std::mutex> guard(_lock); 48 49 _flexpages.insert(_AccessMapEntry(flexpage->base_offset, flexpage)); 50 } 51 52 /* Remove the mapping supported by 'flexpage'. 53 54 The flexpage may have obtained by another mapper before being purged from 55 this object's mapping and before being purged from the queue (and thus 56 disassociated from this mapper), leaving an opportunity for another mapper to 57 now be removing it here. In such a situation, flushing has already occurred 58 and will not be performed again. */ 59 60 bool AccessMap::remove(PageOwner *owner, Flexpage *flexpage) 61 { 62 std::lock_guard<std::mutex> guard(_lock); 63 64 _AccessMap::iterator it = _flexpages.find(flexpage->base_offset); 65 66 if (it != _flexpages.end()) 67 { 68 owner->flush(flexpage, true); 69 _flexpages.erase(flexpage->base_offset); 70 return true; 71 } 72 73 return false; 74 } 75 76 /* Purge all flexpages, using the 'owner' to flush their contents and 77 'pages' to make the flexpages available to other accessors. */ 78 79 void AccessMap::purge(PageOwner *owner, Pages *pages) 80 { 81 std::lock_guard<std::mutex> guard(_lock); 82 83 _AccessMap::iterator it = _flexpages.begin(), entry; 84 85 while (it != _flexpages.end()) 86 { 87 entry = it; 88 it++; 89 90 Flexpage *flexpage = entry->second; 91 92 /* Some flexpages may be unavailable in the queue. Only those 93 that can be reserved should be flushed and made available 94 again. */ 95 96 if (pages->reserve(owner, flexpage)) 97 { 98 owner->flush(flexpage, true); 99 pages->release(flexpage); 100 _flexpages.erase(entry); 101 } 102 } 103 } 104 105 /* Flush flexpages in the given range from 'start' with 'size', using 'owner' 106 and 'pages'. */ 107 108 void AccessMap::flush_all(offset_t start, offset_t size, PageOwner *owner, Pages *pages) 109 { 110 offset_t end = start + size; 111 112 std::lock_guard<std::mutex> guard(_lock); 113 114 /* The start may be within an existing flexpage where the flexpage size is a 115 page multiple. */ 116 117 _AccessMap::iterator it = _flexpages.upper_bound(start), entry; 118 119 if ((_flexpages.size() > 0) && (it != _flexpages.begin())) 120 it--; 121 122 /* Inspect flexpages at or after start until end. */ 123 124 while (it != _flexpages.end()) 125 { 126 entry = it; 127 it++; 128 129 Flexpage *flexpage = entry->second; 130 131 if (flexpage->base_offset >= end) 132 break; 133 134 /* Attempt to flush each flexpage, releasing ones that are no longer 135 needed. */ 136 137 if (pages->reserve(owner, flexpage)) 138 { 139 owner->flush(flexpage, false); 140 141 /* Where no users of the flexpage persist, release the flexpage for 142 reuse and remove this entry. */ 143 144 if (!flexpage->valid()) 145 { 146 pages->release(flexpage); 147 _flexpages.erase(entry); 148 } 149 else 150 pages->queue(owner, flexpage); 151 } 152 } 153 } 154 155 // vim: tabstop=4 expandtab shiftwidth=4