paul@25 | 1 | /* |
paul@25 | 2 | * A page collection for handling map requests. |
paul@25 | 3 | * |
paul@168 | 4 | * Copyright (C) 2019, 2020 Paul Boddie <paul@boddie.org.uk> |
paul@25 | 5 | * |
paul@25 | 6 | * This program is free software; you can redistribute it and/or |
paul@25 | 7 | * modify it under the terms of the GNU General Public License as |
paul@25 | 8 | * published by the Free Software Foundation; either version 2 of |
paul@25 | 9 | * the License, or (at your option) any later version. |
paul@25 | 10 | * |
paul@25 | 11 | * This program is distributed in the hope that it will be useful, |
paul@25 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
paul@25 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
paul@25 | 14 | * GNU General Public License for more details. |
paul@25 | 15 | * |
paul@25 | 16 | * You should have received a copy of the GNU General Public License |
paul@25 | 17 | * along with this program; if not, write to the Free Software |
paul@25 | 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, |
paul@25 | 19 | * Boston, MA 02110-1301, USA |
paul@25 | 20 | */ |
paul@25 | 21 | |
paul@25 | 22 | #pragma once |
paul@25 | 23 | |
paul@173 | 24 | #include <l4/sys/semaphore.h> |
paul@25 | 25 | #include <l4/sys/types.h> |
paul@25 | 26 | |
paul@180 | 27 | #include <list> |
paul@180 | 28 | #include <map> |
paul@30 | 29 | |
paul@170 | 30 | #include <fsserver/accessor.h> |
paul@25 | 31 | #include <fsserver/flexpage.h> |
paul@25 | 32 | |
paul@25 | 33 | |
paul@25 | 34 | |
paul@170 | 35 | /* Queue of allocated flexpages with the accessors using them. */ |
paul@48 | 36 | |
paul@171 | 37 | typedef std::pair<PagingAccessor *, Flexpage *> Flexpage_queue_item; |
paul@180 | 38 | typedef std::list<Flexpage_queue_item> Flexpage_queue; |
paul@180 | 39 | |
paul@180 | 40 | /* Mapping of flexpages to their queue positions. */ |
paul@180 | 41 | |
paul@180 | 42 | typedef std::pair<Flexpage *, Flexpage_queue::iterator> Flexpage_position_item; |
paul@180 | 43 | typedef std::map<Flexpage *, Flexpage_queue::iterator> Flexpage_positions; |
paul@43 | 44 | |
paul@30 | 45 | |
paul@30 | 46 | |
paul@204 | 47 | /* A wrapper around a list and map to provide a coherent, searchable queue. */ |
paul@204 | 48 | |
paul@204 | 49 | class PageQueue |
paul@204 | 50 | { |
paul@206 | 51 | protected: |
paul@204 | 52 | Flexpage_queue _queue; |
paul@204 | 53 | Flexpage_positions _positions; |
paul@204 | 54 | |
paul@206 | 55 | /* Semaphores to ensure available flexpages and to guard the queue when adding |
paul@206 | 56 | or removing items. */ |
paul@206 | 57 | |
paul@206 | 58 | l4_cap_idx_t _counter_semaphore; |
paul@206 | 59 | l4_cap_idx_t _queue_semaphore; |
paul@206 | 60 | |
paul@206 | 61 | void lock_queue() |
paul@206 | 62 | { |
paul@206 | 63 | l4_semaphore_down(_queue_semaphore, L4_IPC_NEVER); |
paul@206 | 64 | } |
paul@206 | 65 | |
paul@206 | 66 | void unlock_queue() |
paul@206 | 67 | { |
paul@206 | 68 | l4_semaphore_up(_queue_semaphore); |
paul@206 | 69 | } |
paul@206 | 70 | |
paul@206 | 71 | void decrement() |
paul@206 | 72 | { |
paul@206 | 73 | l4_semaphore_down(_counter_semaphore, L4_IPC_NEVER); |
paul@206 | 74 | } |
paul@206 | 75 | |
paul@206 | 76 | void increment() |
paul@206 | 77 | { |
paul@206 | 78 | l4_semaphore_up(_counter_semaphore); |
paul@206 | 79 | } |
paul@206 | 80 | |
paul@204 | 81 | public: |
paul@206 | 82 | explicit PageQueue(); |
paul@206 | 83 | |
paul@206 | 84 | virtual ~PageQueue(); |
paul@206 | 85 | |
paul@204 | 86 | PagingAccessor *find(Flexpage *flexpage) |
paul@204 | 87 | { |
paul@206 | 88 | lock_queue(); |
paul@206 | 89 | |
paul@204 | 90 | Flexpage_positions::iterator item = _positions.find(flexpage); |
paul@204 | 91 | |
paul@204 | 92 | if (item == _positions.end()) |
paul@206 | 93 | { |
paul@206 | 94 | unlock_queue(); |
paul@204 | 95 | return NULL; |
paul@206 | 96 | } |
paul@204 | 97 | |
paul@206 | 98 | unlock_queue(); |
paul@204 | 99 | return item->second->first; |
paul@204 | 100 | } |
paul@204 | 101 | |
paul@204 | 102 | bool pop(PagingAccessor **accessor, Flexpage **flexpage) |
paul@204 | 103 | { |
paul@204 | 104 | Flexpage_queue_item item; |
paul@204 | 105 | |
paul@210 | 106 | /* Handle concurrent removal. */ |
paul@206 | 107 | |
paul@210 | 108 | while (1) |
paul@206 | 109 | { |
paul@210 | 110 | decrement(); |
paul@210 | 111 | lock_queue(); |
paul@210 | 112 | |
paul@210 | 113 | if (!_queue.empty()) |
paul@210 | 114 | break; |
paul@210 | 115 | |
paul@206 | 116 | unlock_queue(); |
paul@206 | 117 | } |
paul@204 | 118 | |
paul@204 | 119 | item = _queue.front(); |
paul@204 | 120 | |
paul@204 | 121 | *accessor = item.first; |
paul@204 | 122 | *flexpage = item.second; |
paul@204 | 123 | |
paul@206 | 124 | _remove(*flexpage); |
paul@206 | 125 | |
paul@206 | 126 | unlock_queue(); |
paul@204 | 127 | return true; |
paul@204 | 128 | } |
paul@204 | 129 | |
paul@204 | 130 | void push(PagingAccessor *accessor, Flexpage *flexpage) |
paul@204 | 131 | { |
paul@206 | 132 | lock_queue(); |
paul@206 | 133 | |
paul@204 | 134 | if (_positions.find(flexpage) != _positions.end()) |
paul@206 | 135 | { |
paul@206 | 136 | unlock_queue(); |
paul@204 | 137 | return; |
paul@206 | 138 | } |
paul@204 | 139 | |
paul@204 | 140 | _queue.push_back(Flexpage_queue_item(accessor, flexpage)); |
paul@204 | 141 | |
paul@204 | 142 | Flexpage_queue::iterator it = _queue.end(); |
paul@204 | 143 | |
paul@204 | 144 | it--; |
paul@204 | 145 | _positions.insert(Flexpage_position_item(flexpage, it)); |
paul@206 | 146 | |
paul@206 | 147 | increment(); |
paul@206 | 148 | unlock_queue(); |
paul@204 | 149 | } |
paul@204 | 150 | |
paul@204 | 151 | bool remove(Flexpage *flexpage) |
paul@204 | 152 | { |
paul@206 | 153 | lock_queue(); |
paul@206 | 154 | |
paul@206 | 155 | bool result = _remove(flexpage); |
paul@206 | 156 | |
paul@206 | 157 | unlock_queue(); |
paul@206 | 158 | return result; |
paul@206 | 159 | } |
paul@206 | 160 | |
paul@206 | 161 | bool _remove(Flexpage *flexpage) |
paul@206 | 162 | { |
paul@204 | 163 | Flexpage_positions::iterator item = _positions.find(flexpage); |
paul@204 | 164 | |
paul@210 | 165 | /* With the counter moderating access, this condition should never be |
paul@210 | 166 | true. */ |
paul@210 | 167 | |
paul@204 | 168 | if (item == _positions.end()) |
paul@204 | 169 | return false; |
paul@204 | 170 | |
paul@204 | 171 | _queue.erase(item->second); |
paul@204 | 172 | _positions.erase(item); |
paul@204 | 173 | |
paul@204 | 174 | return true; |
paul@204 | 175 | } |
paul@212 | 176 | |
paul@212 | 177 | void purge(PagingAccessor *accessor) |
paul@212 | 178 | { |
paul@212 | 179 | lock_queue(); |
paul@212 | 180 | |
paul@212 | 181 | Flexpage_queue::iterator it = _queue.begin(); |
paul@212 | 182 | |
paul@212 | 183 | while (it != _queue.end()) |
paul@212 | 184 | { |
paul@212 | 185 | Flexpage_queue::iterator current = it; |
paul@212 | 186 | it++; |
paul@212 | 187 | |
paul@212 | 188 | if (current->first != accessor) |
paul@212 | 189 | continue; |
paul@212 | 190 | |
paul@216 | 191 | /* Insert a new queue entry for the flexpage to replace the existing |
paul@216 | 192 | one. */ |
paul@216 | 193 | |
paul@216 | 194 | Flexpage_queue::iterator repl = _queue.insert(it, Flexpage_queue_item(NULL, current->second)); |
paul@216 | 195 | |
paul@216 | 196 | /* Find the position of the queue entry and remove it from the mapping. */ |
paul@216 | 197 | |
paul@216 | 198 | Flexpage_positions::iterator item = _positions.find(current->second); |
paul@216 | 199 | |
paul@216 | 200 | if (item != _positions.end()) |
paul@216 | 201 | { |
paul@216 | 202 | _positions.erase(item); |
paul@216 | 203 | _positions.insert(Flexpage_position_item(current->second, repl)); |
paul@216 | 204 | } |
paul@216 | 205 | |
paul@216 | 206 | /* Erase the existing queue entry, leaving a null replacement. */ |
paul@216 | 207 | |
paul@212 | 208 | _queue.erase(current); |
paul@212 | 209 | } |
paul@212 | 210 | |
paul@212 | 211 | unlock_queue(); |
paul@212 | 212 | } |
paul@204 | 213 | }; |
paul@204 | 214 | |
paul@204 | 215 | |
paul@204 | 216 | |
paul@25 | 217 | /* A page collection exposing parts of a resource. */ |
paul@25 | 218 | |
paul@25 | 219 | class Pages |
paul@25 | 220 | { |
paul@25 | 221 | /* Memory used to provide flexpages. */ |
paul@25 | 222 | |
paul@49 | 223 | unsigned long _allocated, _limit; |
paul@206 | 224 | l4_cap_idx_t _memory_semaphore; |
paul@25 | 225 | |
paul@49 | 226 | /* Queue of issued flexpages for eventual recycling. */ |
paul@49 | 227 | |
paul@204 | 228 | PageQueue _queue; |
paul@25 | 229 | |
paul@49 | 230 | protected: |
paul@49 | 231 | bool can_get_memory(); |
paul@49 | 232 | |
paul@49 | 233 | l4_addr_t get_memory(unsigned long size); |
paul@49 | 234 | |
paul@25 | 235 | public: |
paul@173 | 236 | explicit Pages(unsigned long limit); |
paul@25 | 237 | |
paul@171 | 238 | Flexpage *new_flexpage(unsigned long offset, l4_addr_t hot_spot, |
paul@171 | 239 | unsigned long flags); |
paul@25 | 240 | |
paul@171 | 241 | Flexpage *new_flexpage(unsigned long offset, l4_addr_t hot_spot, |
paul@171 | 242 | unsigned long flags, l4_addr_t address, |
paul@171 | 243 | unsigned long size); |
paul@168 | 244 | |
paul@171 | 245 | void queue_flexpage(PagingAccessor *accessor, Flexpage *flexpage); |
paul@171 | 246 | |
paul@181 | 247 | bool reserve_flexpage(PagingAccessor *accessor, Flexpage *flexpage); |
paul@180 | 248 | |
paul@181 | 249 | Flexpage *remove_flexpage(); |
paul@212 | 250 | |
paul@212 | 251 | void remove_accessor(PagingAccessor *accessor); |
paul@25 | 252 | }; |