L4Re/OLD/libfsserver

Annotated include/fsserver/pages.h

216:f2f123627288
2020-08-05 Paul Boddie When purging flexpages, make sure that the positions are also purged. This was the source of various address exceptions.
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
};