1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/libmem/lib/src/flexpage.cc Thu Apr 15 23:15:17 2021 +0200
1.3 @@ -0,0 +1,163 @@
1.4 +/*
1.5 + * A flexpage abstraction.
1.6 + *
1.7 + * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
1.8 + *
1.9 + * This program is free software; you can redistribute it and/or
1.10 + * modify it under the terms of the GNU General Public License as
1.11 + * published by the Free Software Foundation; either version 2 of
1.12 + * the License, or (at your option) any later version.
1.13 + *
1.14 + * This program is distributed in the hope that it will be useful,
1.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 + * GNU General Public License for more details.
1.18 + *
1.19 + * You should have received a copy of the GNU General Public License
1.20 + * along with this program; if not, write to the Free Software
1.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.22 + * Boston, MA 02110-1301, USA
1.23 + */
1.24 +
1.25 +#include <algorithm>
1.26 +
1.27 +#include "flexpage.h"
1.28 +
1.29 +
1.30 +
1.31 +/* Reset the flexpage using 'offset', being the file offset. */
1.32 +
1.33 +void Flexpage::reset(offset_t offset)
1.34 +{
1.35 + _counter = 0;
1.36 +
1.37 + /* By definition (see "Flexible-Sized Page Objects - Object-Orientation
1.38 + in Operation Systems"), flexpages are aligned to multiples of their
1.39 + size.
1.40 +
1.41 + The size of the flexpage depends on the amount of space around the
1.42 + accessed page. It cannot exceed the size of the memory region. */
1.43 +
1.44 + size = max_multiple(region->start, region->end, PAGE_SIZE);
1.45 +
1.46 + /* The base address of the flexpage is computed from the region start
1.47 + and flexpage size. It will be no lower than the region start.
1.48 +
1.49 + Sent flexpages may use higher bases due to receive window constraints,
1.50 + these being communicated by the "hot spot". */
1.51 +
1.52 + base_addr = round(region->start, size);
1.53 +
1.54 + /* Get the file offset for the base of the flexpage. This will be a
1.55 + multiple of the flexpage size for alignment purposes. */
1.56 +
1.57 + base_offset = trunc(offset, size);
1.58 +
1.59 + /* The page being accessed is relative to the base.
1.60 + (This is transient information recording the initialising access
1.61 + details.) */
1.62 +
1.63 + page_offset = trunc(offset - base_offset, PAGE_SIZE);
1.64 + page_addr = base_addr + page_offset;
1.65 +}
1.66 +
1.67 +bool Flexpage::decrement()
1.68 +{
1.69 + if (_counter)
1.70 + {
1.71 + _counter--;
1.72 + return _counter == 0;
1.73 + }
1.74 + else
1.75 + return 0;
1.76 +}
1.77 +
1.78 +void Flexpage::increment()
1.79 +{
1.80 + _counter++;
1.81 +}
1.82 +
1.83 +void Flexpage::invalidate()
1.84 +{
1.85 + _counter = 0;
1.86 +}
1.87 +
1.88 +bool Flexpage::valid()
1.89 +{
1.90 + return _counter != 0;
1.91 +}
1.92 +
1.93 +/* Return whether the flexpage supports the given file 'position'. */
1.94 +
1.95 +bool Flexpage::supports_position(offset_t position)
1.96 +{
1.97 + return (base_offset <= position) && (position < (base_offset + size));
1.98 +}
1.99 +
1.100 +/* Upgrade the flags involved with this flexpage. This is used to track the
1.101 + maximal flags employed by the different pagers, with the result being used in
1.102 + unmap operations. */
1.103 +
1.104 +void Flexpage::upgrade(flags_t flags)
1.105 +{
1.106 + if (flags && (flags != _flags))
1.107 + _flags |= flags;
1.108 +}
1.109 +
1.110 +/* Return a "send" flexpage for an access to 'offset' by positioning it relative
1.111 + to 'hot_spot' for the receive flexpage window. */
1.112 +
1.113 +SendFlexpage Flexpage::to_send(offset_t offset, offset_t hot_spot,
1.114 + flags_t flags, offset_t max_offset)
1.115 +{
1.116 + /* The dataspace offset of the flexpage base is a multiple of the flexpage
1.117 + size. */
1.118 +
1.119 + offset_t receive_base_offset = trunc(offset, size);
1.120 +
1.121 + /* The offset of the accessed page within the flexpage is constrained by the
1.122 + current flexpage size. */
1.123 +
1.124 + offset_t page_offset = trunc(offset - receive_base_offset, PAGE_SIZE);
1.125 +
1.126 + /* The receive flexpage offset (hot spot) must be constrained to the
1.127 + flexpage, both the size and the start. */
1.128 +
1.129 + offset_t receive_size;
1.130 +
1.131 + if (max_offset)
1.132 + {
1.133 + receive_size = trunc_multiple(max_offset - receive_base_offset, PAGE_SIZE);
1.134 + receive_size = std::min(size, receive_size);
1.135 + }
1.136 + else
1.137 + receive_size = size;
1.138 +
1.139 + if (!receive_size)
1.140 + return SendFlexpage(base_addr, page_order(0), flags);
1.141 +
1.142 + offset_t receive_page_offset = hot_spot % receive_size;
1.143 +
1.144 + while ((receive_size > PAGE_SIZE) && (receive_page_offset != page_offset))
1.145 + {
1.146 + receive_size /= 2;
1.147 + receive_page_offset = hot_spot % receive_size;
1.148 + }
1.149 +
1.150 + /* The flexpage base address is adjusted using the difference in page
1.151 + offsets. Where the receive flexpage offset is constained further, the
1.152 + base address will be raised to become closer to the accessed page. */
1.153 +
1.154 + offset_t adjustment = page_offset - receive_page_offset;
1.155 +
1.156 + return SendFlexpage(base_addr + adjustment, page_order(receive_size), flags);
1.157 +}
1.158 +
1.159 +/* Return a representation of the flexpage for unmapping. */
1.160 +
1.161 +SendFlexpage Flexpage::to_unmap()
1.162 +{
1.163 + return SendFlexpage(base_addr, page_order(size), _flags);
1.164 +}
1.165 +
1.166 +// vim: tabstop=4 expandtab shiftwidth=4