paul@0 | 1 | #include <algorithm> |
paul@0 | 2 | |
paul@0 | 3 | #include "flexpage.h" |
paul@0 | 4 | |
paul@0 | 5 | |
paul@0 | 6 | |
paul@0 | 7 | /* Reset the flexpage using 'offset', being the file offset. */ |
paul@0 | 8 | |
paul@0 | 9 | void Flexpage::reset(offset_t offset) |
paul@0 | 10 | { |
paul@0 | 11 | _counter = 0; |
paul@0 | 12 | |
paul@0 | 13 | /* By definition (see "Flexible-Sized Page Objects - Object-Orientation |
paul@0 | 14 | in Operation Systems"), flexpages are aligned to multiples of their |
paul@0 | 15 | size. |
paul@0 | 16 | |
paul@0 | 17 | The size of the flexpage depends on the amount of space around the |
paul@0 | 18 | accessed page. It cannot exceed the size of the memory region. */ |
paul@0 | 19 | |
paul@0 | 20 | size = max_multiple(region->start, region->end, PAGE_SIZE); |
paul@0 | 21 | |
paul@0 | 22 | /* The base address of the flexpage is computed from the region start |
paul@0 | 23 | and flexpage size. It will be no lower than the region start. |
paul@0 | 24 | |
paul@0 | 25 | Sent flexpages may use higher bases due to receive window constraints, |
paul@0 | 26 | these being communicated by the "hot spot". */ |
paul@0 | 27 | |
paul@0 | 28 | base_addr = round(region->start, size); |
paul@0 | 29 | |
paul@0 | 30 | /* Get the file offset for the base of the flexpage. This will be a |
paul@0 | 31 | multiple of the flexpage size for alignment purposes. */ |
paul@0 | 32 | |
paul@0 | 33 | base_offset = trunc(offset, size); |
paul@0 | 34 | |
paul@0 | 35 | /* The page being accessed is relative to the base. |
paul@0 | 36 | (This is transient information recording the initialising access |
paul@0 | 37 | details.) */ |
paul@0 | 38 | |
paul@0 | 39 | page_offset = trunc(offset - base_offset, PAGE_SIZE); |
paul@0 | 40 | page_addr = base_addr + page_offset; |
paul@0 | 41 | } |
paul@0 | 42 | |
paul@0 | 43 | bool Flexpage::decrement() |
paul@0 | 44 | { |
paul@0 | 45 | if (_counter) |
paul@0 | 46 | { |
paul@0 | 47 | _counter--; |
paul@0 | 48 | return _counter == 0; |
paul@0 | 49 | } |
paul@0 | 50 | else |
paul@0 | 51 | return 0; |
paul@0 | 52 | } |
paul@0 | 53 | |
paul@0 | 54 | void Flexpage::increment() |
paul@0 | 55 | { |
paul@0 | 56 | _counter++; |
paul@0 | 57 | } |
paul@0 | 58 | |
paul@0 | 59 | void Flexpage::invalidate() |
paul@0 | 60 | { |
paul@0 | 61 | _counter = 0; |
paul@0 | 62 | } |
paul@0 | 63 | |
paul@0 | 64 | bool Flexpage::valid() |
paul@0 | 65 | { |
paul@0 | 66 | return _counter != 0; |
paul@0 | 67 | } |
paul@0 | 68 | |
paul@0 | 69 | /* Return whether the flexpage supports the given file 'position'. */ |
paul@0 | 70 | |
paul@0 | 71 | bool Flexpage::supports_position(offset_t position) |
paul@0 | 72 | { |
paul@0 | 73 | return (base_offset <= position) && (position < (base_offset + size)); |
paul@0 | 74 | } |
paul@0 | 75 | |
paul@86 | 76 | /* Upgrade the flags involved with this flexpage. This is used to track the |
paul@86 | 77 | maximal flags employed by the different pagers, with the result being used in |
paul@86 | 78 | unmap operations. */ |
paul@86 | 79 | |
paul@54 | 80 | void Flexpage::upgrade(flags_t flags) |
paul@11 | 81 | { |
paul@11 | 82 | if (flags && (flags != _flags)) |
paul@11 | 83 | _flags |= flags; |
paul@11 | 84 | } |
paul@11 | 85 | |
paul@0 | 86 | /* Return a "send" flexpage for an access to 'offset' by positioning it relative |
paul@0 | 87 | to 'hot_spot' for the receive flexpage window. */ |
paul@0 | 88 | |
paul@86 | 89 | SendFlexpage Flexpage::to_send(offset_t offset, offset_t hot_spot, |
paul@86 | 90 | flags_t flags, offset_t max_offset) |
paul@0 | 91 | { |
paul@0 | 92 | /* The dataspace offset of the flexpage base is a multiple of the flexpage |
paul@0 | 93 | size. */ |
paul@0 | 94 | |
paul@0 | 95 | offset_t receive_base_offset = trunc(offset, size); |
paul@0 | 96 | |
paul@0 | 97 | /* The offset of the accessed page within the flexpage is constrained by the |
paul@0 | 98 | current flexpage size. */ |
paul@0 | 99 | |
paul@0 | 100 | offset_t page_offset = trunc(offset - receive_base_offset, PAGE_SIZE); |
paul@0 | 101 | |
paul@0 | 102 | /* The receive flexpage offset (hot spot) must be constrained to the |
paul@0 | 103 | flexpage, both the size and the start. */ |
paul@0 | 104 | |
paul@0 | 105 | offset_t receive_size; |
paul@0 | 106 | |
paul@0 | 107 | if (max_offset) |
paul@23 | 108 | { |
paul@23 | 109 | receive_size = trunc_multiple(max_offset - receive_base_offset, PAGE_SIZE); |
paul@23 | 110 | receive_size = std::min(size, receive_size); |
paul@23 | 111 | } |
paul@0 | 112 | else |
paul@0 | 113 | receive_size = size; |
paul@0 | 114 | |
paul@3 | 115 | if (!receive_size) |
paul@86 | 116 | return SendFlexpage(base_addr, page_order(0), flags); |
paul@3 | 117 | |
paul@0 | 118 | offset_t receive_page_offset = hot_spot % receive_size; |
paul@0 | 119 | |
paul@0 | 120 | while ((receive_size > PAGE_SIZE) && (receive_page_offset != page_offset)) |
paul@0 | 121 | { |
paul@0 | 122 | receive_size /= 2; |
paul@0 | 123 | receive_page_offset = hot_spot % receive_size; |
paul@0 | 124 | } |
paul@0 | 125 | |
paul@0 | 126 | /* The flexpage base address is adjusted using the difference in page |
paul@0 | 127 | offsets. Where the receive flexpage offset is constained further, the |
paul@0 | 128 | base address will be raised to become closer to the accessed page. */ |
paul@0 | 129 | |
paul@0 | 130 | offset_t adjustment = page_offset - receive_page_offset; |
paul@0 | 131 | |
paul@86 | 132 | return SendFlexpage(base_addr + adjustment, page_order(receive_size), flags); |
paul@0 | 133 | } |
paul@0 | 134 | |
paul@0 | 135 | /* Return a representation of the flexpage for unmapping. */ |
paul@0 | 136 | |
paul@0 | 137 | SendFlexpage Flexpage::to_unmap() |
paul@0 | 138 | { |
paul@11 | 139 | return SendFlexpage(base_addr, page_order(size), _flags); |
paul@0 | 140 | } |
paul@0 | 141 | |
paul@0 | 142 | // vim: tabstop=4 expandtab shiftwidth=4 |