1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/page_mapper.cc Sat Jan 23 00:01:22 2021 +0100
1.3 @@ -0,0 +1,166 @@
1.4 +#include "ipc.h"
1.5 +#include "page_mapper.h"
1.6 +
1.7 +
1.8 +
1.9 +PageMapper::PageMapper(Accessor *accessor, Pages *pages)
1.10 +: _accessor(accessor), _pages(pages), _attached(0)
1.11 +{
1.12 +}
1.13 +
1.14 +/* Accounting methods. */
1.15 +
1.16 +/* Attach a pager, opening the accessor if required. */
1.17 +
1.18 +void PageMapper::attach()
1.19 +{
1.20 + std::lock_guard<std::mutex> guard(_lock);
1.21 +
1.22 + if (!_attached)
1.23 + _accessor->open();
1.24 +
1.25 + _attached += 1;
1.26 +}
1.27 +
1.28 +/* Detach a pager, purging active pages and closing the accessor if no more
1.29 + pagers are attached. Return whether any pagers are still attached. */
1.30 +
1.31 +unsigned int PageMapper::detach()
1.32 +{
1.33 + std::lock_guard<std::mutex> guard(_lock);
1.34 +
1.35 + if (_attached)
1.36 + {
1.37 + _attached -= 1;
1.38 +
1.39 + if (!_attached)
1.40 + {
1.41 + _map.purge(this, _pages);
1.42 + _accessor->close();
1.43 + }
1.44 + }
1.45 +
1.46 + return _attached;
1.47 +}
1.48 +
1.49 +/* Interface for the pager. */
1.50 +
1.51 +/* Return a flexpage providing access to the indicated file 'offset'.
1.52 +
1.53 + The returned flexpage will either be an existing, compatible flexpage or a
1.54 + completely new flexpage.
1.55 +
1.56 + This method locks the accessor to prevent concurrent queries with the
1.57 + same details, with the lock held until the queue or flush_all operations
1.58 + release the lock. */
1.59 +
1.60 +Flexpage *PageMapper::get(offset_t offset)
1.61 +{
1.62 + _lock.lock();
1.63 +
1.64 + Flexpage *f = find(offset);
1.65 +
1.66 + if (f == NULL)
1.67 + f = flexpage(offset);
1.68 +
1.69 + f->increment();
1.70 + return f;
1.71 +}
1.72 +
1.73 +/* Queue the given 'flexpage' in the page collection, making it available for
1.74 + eventual reuse.
1.75 +
1.76 + This method unlocks the accessor. */
1.77 +
1.78 +void PageMapper::queue(Flexpage *flexpage)
1.79 +{
1.80 + _pages->queue(this, flexpage);
1.81 +
1.82 + _lock.unlock();
1.83 +}
1.84 +
1.85 +/* Flush pages in the given range from 'start' with 'size'. */
1.86 +
1.87 +void PageMapper::flush_all(offset_t start, offset_t size)
1.88 +{
1.89 + std::lock_guard<std::mutex> guard(_lock);
1.90 +
1.91 + _map.flush_all(start, size, this, _pages);
1.92 +}
1.93 +
1.94 +/* Return the maximum extent of the mapped resource. */
1.95 +
1.96 +offset_t PageMapper::get_data_size()
1.97 +{
1.98 + return _accessor->get_size();
1.99 +}
1.100 +
1.101 +/* Internal flexpage retrieval methods. */
1.102 +
1.103 +/* Find an existing flexpage for 'offset'. Where the accessor has registered a
1.104 + compatible flexpage, an attempt is made to reserve it in the page collection;
1.105 + if this succeeds, the flexpage is returned. Otherwise, NULL is returned. */
1.106 +
1.107 +Flexpage *PageMapper::find(offset_t offset)
1.108 +{
1.109 + Flexpage *flexpage = _map.find(offset);
1.110 +
1.111 + /* Between finding and reserving a flexpage, there is a possibility that
1.112 + another accessor might acquire the flexpage, issue it, and even purge
1.113 + it. */
1.114 +
1.115 + if ((flexpage != NULL) && _pages->reserve(this, flexpage))
1.116 + return flexpage;
1.117 + else
1.118 + return NULL;
1.119 +}
1.120 +
1.121 +/* Obtain a new flexpage for the file 'offset'. If the page collection is unable
1.122 + to obtain a completely new flexpage, an existing flexpage is requested from
1.123 + the page collection and recycled.
1.124 +
1.125 + The obtained flexpage is filled with content. */
1.126 +
1.127 +Flexpage *PageMapper::flexpage(offset_t offset)
1.128 +{
1.129 + Flexpage *flexpage = _pages->flexpage();
1.130 +
1.131 + /* Obtain an existing flexpage and reuse it. */
1.132 +
1.133 + if (flexpage == NULL)
1.134 + flexpage = _pages->remove();
1.135 +
1.136 + flexpage->reset(offset);
1.137 +
1.138 + fill(flexpage);
1.139 + _map.insert(flexpage);
1.140 + return flexpage;
1.141 +}
1.142 +
1.143 +/* Interface for the page collection. */
1.144 +
1.145 +/* Remove the record of 'flexpage' in this accessor, flushing its content. */
1.146 +
1.147 +void PageMapper::remove(Flexpage *flexpage)
1.148 +{
1.149 + _map.remove(this, flexpage);
1.150 +}
1.151 +
1.152 +/* Data transfer methods. */
1.153 +
1.154 +void PageMapper::fill(Flexpage *flexpage)
1.155 +{
1.156 + _accessor->fill(flexpage);
1.157 +}
1.158 +
1.159 +void PageMapper::flush(Flexpage *flexpage, bool purge)
1.160 +{
1.161 + if (flexpage->decrement() || purge)
1.162 + {
1.163 + _accessor->flush(flexpage);
1.164 + ipc_unmap_flexpage(flexpage);
1.165 + flexpage->invalidate();
1.166 + }
1.167 +}
1.168 +
1.169 +// vim: tabstop=4 expandtab shiftwidth=4