1.1 --- a/Makefile Fri Jan 22 23:59:13 2021 +0100
1.2 +++ b/Makefile Sat Jan 23 00:01:22 2021 +0100
1.3 @@ -22,9 +22,12 @@
1.4 SERVER_INTERFACES_SRC_CC = $(call interfaces_to_server_cc,$(SERVER_INTERFACES_CC))
1.5
1.6 PLAIN_SRC_CC = \
1.7 + access_map.cc accessor.cc \
1.8 dstest_server.cc flexpage.cc ipc.cc \
1.9 memory.cc memory_map.cc memory_utils.cc \
1.10 - region.cc resource.cc simple_pager.cc
1.11 + page_mapper.cc page_queue.cc pager.cc pages.cc \
1.12 + region.cc resource.cc simple_pager.cc \
1.13 + test_file_accessor.cc
1.14
1.15 # Normal definitions.
1.16
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/access_map.cc Sat Jan 23 00:01:22 2021 +0100
2.3 @@ -0,0 +1,134 @@
2.4 +#include "access_map.h"
2.5 +
2.6 +/* Return the flexpage supporting 'position'. */
2.7 +
2.8 +Flexpage *AccessMap::find(offset_t position)
2.9 +{
2.10 + std::lock_guard<std::mutex> guard(_lock);
2.11 +
2.12 + _AccessMap::iterator it = _flexpages.upper_bound(position);
2.13 +
2.14 + if ((_flexpages.size() > 0) && (it != _flexpages.begin()))
2.15 + {
2.16 + it--;
2.17 +
2.18 + if (it->second->supports_position(position))
2.19 + return it->second;
2.20 + }
2.21 +
2.22 + return NULL;
2.23 +}
2.24 +
2.25 +/* Insert a mapping for 'flexpage'. */
2.26 +
2.27 +void AccessMap::insert(Flexpage *flexpage)
2.28 +{
2.29 + std::lock_guard<std::mutex> guard(_lock);
2.30 +
2.31 + _flexpages.insert(_AccessMapEntry(flexpage->base_offset, flexpage));
2.32 +}
2.33 +
2.34 +/* Remove the mapping supported by 'flexpage'.
2.35 +
2.36 + The flexpage may have obtained by another mapper before being purged from
2.37 + this object's mapping and before being purged from the queue (and thus
2.38 + disassociated from this mapper), leaving an opportunity for another mapper to
2.39 + now be removing it here. In such a situation, flushing has already occurred
2.40 + and will not be performed again. */
2.41 +
2.42 +bool AccessMap::remove(PageOwner *owner, Flexpage *flexpage)
2.43 +{
2.44 + std::lock_guard<std::mutex> guard(_lock);
2.45 +
2.46 + _AccessMap::iterator it = _flexpages.find(flexpage->base_offset);
2.47 +
2.48 + if (it != _flexpages.end())
2.49 + {
2.50 + owner->flush(flexpage, true);
2.51 + _flexpages.erase(flexpage->base_offset);
2.52 + return true;
2.53 + }
2.54 +
2.55 + return false;
2.56 +}
2.57 +
2.58 +/* Purge all flexpages, using the 'owner' to flush their contents and
2.59 + 'pages' to make the flexpages available to other accessors. */
2.60 +
2.61 +void AccessMap::purge(PageOwner *owner, Pages *pages)
2.62 +{
2.63 + std::lock_guard<std::mutex> guard(_lock);
2.64 +
2.65 + _AccessMap::iterator it = _flexpages.begin(), entry;
2.66 +
2.67 + while (it != _flexpages.end())
2.68 + {
2.69 + entry = it;
2.70 + it++;
2.71 +
2.72 + Flexpage *flexpage = entry->second;
2.73 +
2.74 + /* Some flexpages may be unavailable in the queue. Only those
2.75 + that can be reserved should be flushed and made available
2.76 + again. */
2.77 +
2.78 + if (pages->reserve(owner, flexpage))
2.79 + {
2.80 + owner->flush(flexpage, true);
2.81 + pages->release(flexpage);
2.82 + _flexpages.erase(entry);
2.83 + }
2.84 + }
2.85 +}
2.86 +
2.87 +/* Flush flexpages in the given range from 'start' with 'size', using 'owner'
2.88 + and 'pages'. */
2.89 +
2.90 +void AccessMap::flush_all(offset_t start, offset_t size, PageOwner *owner, Pages *pages)
2.91 +{
2.92 + offset_t end = start + size;
2.93 +
2.94 + std::lock_guard<std::mutex> guard(_lock);
2.95 +
2.96 + /* The start may be within an existing flexpage where the flexpage size is a
2.97 + page multiple. */
2.98 +
2.99 + _AccessMap::iterator it = _flexpages.upper_bound(start), entry;
2.100 +
2.101 + if ((_flexpages.size() > 0) && (it != _flexpages.begin()))
2.102 + it--;
2.103 +
2.104 + /* Inspect flexpages at or after start until end. */
2.105 +
2.106 + while (it != _flexpages.end())
2.107 + {
2.108 + entry = it;
2.109 + it++;
2.110 +
2.111 + Flexpage *flexpage = entry->second;
2.112 +
2.113 + if (flexpage->base_offset >= end)
2.114 + break;
2.115 +
2.116 + /* Attempt to flush each flexpage, releasing ones that are no longer
2.117 + needed. */
2.118 +
2.119 + if (pages->reserve(owner, flexpage))
2.120 + {
2.121 + owner->flush(flexpage, false);
2.122 +
2.123 + /* Where no users of the flexpage persist, release the flexpage for
2.124 + reuse and remove this entry. */
2.125 +
2.126 + if (!flexpage->valid())
2.127 + {
2.128 + pages->release(flexpage);
2.129 + _flexpages.erase(entry);
2.130 + }
2.131 + else
2.132 + pages->queue(owner, flexpage);
2.133 + }
2.134 + }
2.135 +}
2.136 +
2.137 +// vim: tabstop=4 expandtab shiftwidth=4
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/access_map.h Sat Jan 23 00:01:22 2021 +0100
3.3 @@ -0,0 +1,35 @@
3.4 +#pragma once
3.5 +
3.6 +#include "flexpage.h"
3.7 +#include "page_owner.h"
3.8 +#include "pages.h"
3.9 +
3.10 +#include <map>
3.11 +#include <mutex>
3.12 +
3.13 +/* Collection types. */
3.14 +
3.15 +typedef std::map<offset_t, Flexpage *> _AccessMap;
3.16 +typedef std::pair<offset_t, Flexpage *> _AccessMapEntry;
3.17 +
3.18 +/* A mapping from file positions to flexpages. */
3.19 +
3.20 +class AccessMap
3.21 +{
3.22 +protected:
3.23 + _AccessMap _flexpages;
3.24 + std::mutex _lock;
3.25 +
3.26 +public:
3.27 + Flexpage *find(offset_t position);
3.28 +
3.29 + void insert(Flexpage *flexpage);
3.30 +
3.31 + bool remove(PageOwner *owner, Flexpage *flexpage);
3.32 +
3.33 + void purge(PageOwner *owner, Pages *pages);
3.34 +
3.35 + void flush_all(offset_t start, offset_t size, PageOwner *owner, Pages *pages);
3.36 +};
3.37 +
3.38 +// vim: tabstop=4 expandtab shiftwidth=4
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/accessor.cc Sat Jan 23 00:01:22 2021 +0100
4.3 @@ -0,0 +1,27 @@
4.4 +#include "accessor.h"
4.5 +
4.6 +Accessor::Accessor(fileid_t fileid, offset_t size)
4.7 +: _size(size), fileid(fileid)
4.8 +{
4.9 +}
4.10 +
4.11 +/* Return the size of the file. */
4.12 +
4.13 +offset_t Accessor::get_size()
4.14 +{
4.15 + return _size;
4.16 +}
4.17 +
4.18 +/* Perform any closing operation on the file. */
4.19 +
4.20 +void Accessor::close()
4.21 +{
4.22 +}
4.23 +
4.24 +/* Perform any opening operation on the file. */
4.25 +
4.26 +void Accessor::open()
4.27 +{
4.28 +}
4.29 +
4.30 +// vim: tabstop=4 expandtab shiftwidth=4
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/accessor.h Sat Jan 23 00:01:22 2021 +0100
5.3 @@ -0,0 +1,32 @@
5.4 +#pragma once
5.5 +
5.6 +#include <mutex>
5.7 +
5.8 +#include "flexpage.h"
5.9 +
5.10 +/* A file accessor, providing flexpages corresponding to file regions. */
5.11 +
5.12 +class Accessor
5.13 +{
5.14 +protected:
5.15 + offset_t _size;
5.16 +
5.17 +public:
5.18 + fileid_t fileid;
5.19 +
5.20 + explicit Accessor(fileid_t fileid, offset_t size=0);
5.21 +
5.22 + virtual offset_t get_size();
5.23 +
5.24 + virtual void close();
5.25 +
5.26 + virtual void open();
5.27 +
5.28 + /* Data transfer methods. */
5.29 +
5.30 + virtual void fill(Flexpage *flexpage) = 0;
5.31 +
5.32 + virtual void flush(Flexpage *flexpage) = 0;
5.33 +};
5.34 +
5.35 +// vim: tabstop=4 expandtab shiftwidth=4
6.1 --- a/dstest_client.cc Fri Jan 22 23:59:13 2021 +0100
6.2 +++ b/dstest_client.cc Sat Jan 23 00:01:22 2021 +0100
6.3 @@ -52,7 +52,7 @@
6.4 {
6.5 printf("10 bytes from %p...\n", (memory + offset));
6.6 fwrite((memory + offset), sizeof(char), 10, stdout);
6.7 - fputs("\n", stdout);
6.8 + fwrite("\n", sizeof(char), 1, stdout);
6.9 }
6.10
6.11 return 0;
7.1 --- a/dstest_server.cc Fri Jan 22 23:59:13 2021 +0100
7.2 +++ b/dstest_server.cc Sat Jan 23 00:01:22 2021 +0100
7.3 @@ -29,21 +29,10 @@
7.4 #include <ipc/server.h>
7.5
7.6 #include "dataspace_server.h"
7.7 -#include "simple_pager.h"
7.8 -
7.9 -
7.10 -
7.11 -/* Component interface. */
7.12 -
7.13 -class DataspaceServer : public SimplePager
7.14 -{
7.15 -public:
7.16 - explicit DataspaceServer(Memory *memory)
7.17 - : SimplePager(memory)
7.18 - {
7.19 - memset((void *) _region->start, (int) 'a', PAGE_SIZE);
7.20 - }
7.21 -};
7.22 +#include "page_mapper.h"
7.23 +#include "pager.h"
7.24 +#include "pages.h"
7.25 +#include "test_file_accessor.h"
7.26
7.27
7.28
7.29 @@ -51,11 +40,13 @@
7.30 {
7.31 /* Some memory. */
7.32
7.33 - Memory memory(10);
7.34 + Memory mem(10);
7.35 + Pages pages(&mem);
7.36 + TestFileAccessor a(123UL);
7.37 + PageMapper m(&a, &pages);
7.38 + Pager pager(&m);
7.39
7.40 - /* Dataspace encapsulation. */
7.41 -
7.42 - DataspaceServer obj(&memory);
7.43 + pager.mmap(0, page(10));
7.44
7.45 /* Server capability. */
7.46
7.47 @@ -63,7 +54,7 @@
7.48
7.49 /* Register a server associating it with the given object. */
7.50
7.51 - long err = ipc_server_bind("server", (l4_umword_t) &obj, &server);
7.52 + long err = ipc_server_bind("server", (l4_umword_t) &pager, &server);
7.53
7.54 if (err)
7.55 {
7.56 @@ -73,7 +64,7 @@
7.57
7.58 /* Wait for messages, dispatching to the handler. */
7.59
7.60 - ipc_server_loop(Dataspace_expected_items, &obj,
7.61 + ipc_server_loop(Dataspace_expected_items, &pager,
7.62 (ipc_server_handler_type) handle_Dataspace);
7.63
7.64 return 0;
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/page_mapper.cc Sat Jan 23 00:01:22 2021 +0100
8.3 @@ -0,0 +1,166 @@
8.4 +#include "ipc.h"
8.5 +#include "page_mapper.h"
8.6 +
8.7 +
8.8 +
8.9 +PageMapper::PageMapper(Accessor *accessor, Pages *pages)
8.10 +: _accessor(accessor), _pages(pages), _attached(0)
8.11 +{
8.12 +}
8.13 +
8.14 +/* Accounting methods. */
8.15 +
8.16 +/* Attach a pager, opening the accessor if required. */
8.17 +
8.18 +void PageMapper::attach()
8.19 +{
8.20 + std::lock_guard<std::mutex> guard(_lock);
8.21 +
8.22 + if (!_attached)
8.23 + _accessor->open();
8.24 +
8.25 + _attached += 1;
8.26 +}
8.27 +
8.28 +/* Detach a pager, purging active pages and closing the accessor if no more
8.29 + pagers are attached. Return whether any pagers are still attached. */
8.30 +
8.31 +unsigned int PageMapper::detach()
8.32 +{
8.33 + std::lock_guard<std::mutex> guard(_lock);
8.34 +
8.35 + if (_attached)
8.36 + {
8.37 + _attached -= 1;
8.38 +
8.39 + if (!_attached)
8.40 + {
8.41 + _map.purge(this, _pages);
8.42 + _accessor->close();
8.43 + }
8.44 + }
8.45 +
8.46 + return _attached;
8.47 +}
8.48 +
8.49 +/* Interface for the pager. */
8.50 +
8.51 +/* Return a flexpage providing access to the indicated file 'offset'.
8.52 +
8.53 + The returned flexpage will either be an existing, compatible flexpage or a
8.54 + completely new flexpage.
8.55 +
8.56 + This method locks the accessor to prevent concurrent queries with the
8.57 + same details, with the lock held until the queue or flush_all operations
8.58 + release the lock. */
8.59 +
8.60 +Flexpage *PageMapper::get(offset_t offset)
8.61 +{
8.62 + _lock.lock();
8.63 +
8.64 + Flexpage *f = find(offset);
8.65 +
8.66 + if (f == NULL)
8.67 + f = flexpage(offset);
8.68 +
8.69 + f->increment();
8.70 + return f;
8.71 +}
8.72 +
8.73 +/* Queue the given 'flexpage' in the page collection, making it available for
8.74 + eventual reuse.
8.75 +
8.76 + This method unlocks the accessor. */
8.77 +
8.78 +void PageMapper::queue(Flexpage *flexpage)
8.79 +{
8.80 + _pages->queue(this, flexpage);
8.81 +
8.82 + _lock.unlock();
8.83 +}
8.84 +
8.85 +/* Flush pages in the given range from 'start' with 'size'. */
8.86 +
8.87 +void PageMapper::flush_all(offset_t start, offset_t size)
8.88 +{
8.89 + std::lock_guard<std::mutex> guard(_lock);
8.90 +
8.91 + _map.flush_all(start, size, this, _pages);
8.92 +}
8.93 +
8.94 +/* Return the maximum extent of the mapped resource. */
8.95 +
8.96 +offset_t PageMapper::get_data_size()
8.97 +{
8.98 + return _accessor->get_size();
8.99 +}
8.100 +
8.101 +/* Internal flexpage retrieval methods. */
8.102 +
8.103 +/* Find an existing flexpage for 'offset'. Where the accessor has registered a
8.104 + compatible flexpage, an attempt is made to reserve it in the page collection;
8.105 + if this succeeds, the flexpage is returned. Otherwise, NULL is returned. */
8.106 +
8.107 +Flexpage *PageMapper::find(offset_t offset)
8.108 +{
8.109 + Flexpage *flexpage = _map.find(offset);
8.110 +
8.111 + /* Between finding and reserving a flexpage, there is a possibility that
8.112 + another accessor might acquire the flexpage, issue it, and even purge
8.113 + it. */
8.114 +
8.115 + if ((flexpage != NULL) && _pages->reserve(this, flexpage))
8.116 + return flexpage;
8.117 + else
8.118 + return NULL;
8.119 +}
8.120 +
8.121 +/* Obtain a new flexpage for the file 'offset'. If the page collection is unable
8.122 + to obtain a completely new flexpage, an existing flexpage is requested from
8.123 + the page collection and recycled.
8.124 +
8.125 + The obtained flexpage is filled with content. */
8.126 +
8.127 +Flexpage *PageMapper::flexpage(offset_t offset)
8.128 +{
8.129 + Flexpage *flexpage = _pages->flexpage();
8.130 +
8.131 + /* Obtain an existing flexpage and reuse it. */
8.132 +
8.133 + if (flexpage == NULL)
8.134 + flexpage = _pages->remove();
8.135 +
8.136 + flexpage->reset(offset);
8.137 +
8.138 + fill(flexpage);
8.139 + _map.insert(flexpage);
8.140 + return flexpage;
8.141 +}
8.142 +
8.143 +/* Interface for the page collection. */
8.144 +
8.145 +/* Remove the record of 'flexpage' in this accessor, flushing its content. */
8.146 +
8.147 +void PageMapper::remove(Flexpage *flexpage)
8.148 +{
8.149 + _map.remove(this, flexpage);
8.150 +}
8.151 +
8.152 +/* Data transfer methods. */
8.153 +
8.154 +void PageMapper::fill(Flexpage *flexpage)
8.155 +{
8.156 + _accessor->fill(flexpage);
8.157 +}
8.158 +
8.159 +void PageMapper::flush(Flexpage *flexpage, bool purge)
8.160 +{
8.161 + if (flexpage->decrement() || purge)
8.162 + {
8.163 + _accessor->flush(flexpage);
8.164 + ipc_unmap_flexpage(flexpage);
8.165 + flexpage->invalidate();
8.166 + }
8.167 +}
8.168 +
8.169 +// vim: tabstop=4 expandtab shiftwidth=4
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/page_mapper.h Sat Jan 23 00:01:22 2021 +0100
9.3 @@ -0,0 +1,56 @@
9.4 +#pragma once
9.5 +
9.6 +#include "access_map.h"
9.7 +#include "accessor.h"
9.8 +#include "page_owner.h"
9.9 +
9.10 +#include <mutex>
9.11 +
9.12 +/* A file mapper, associating flexpages with file regions. */
9.13 +
9.14 +class PageMapper : public PageOwner
9.15 +{
9.16 +protected:
9.17 + AccessMap _map;
9.18 + Accessor *_accessor;
9.19 + Pages *_pages;
9.20 + unsigned int _attached;
9.21 + std::mutex _lock;
9.22 +
9.23 + /* Internal flexpage retrieval methods. */
9.24 +
9.25 + Flexpage *find(offset_t offset);
9.26 +
9.27 + Flexpage *flexpage(offset_t offset);
9.28 +
9.29 +public:
9.30 + explicit PageMapper(Accessor *accessor, Pages *pages);
9.31 +
9.32 + /* Accounting methods. */
9.33 +
9.34 + void attach();
9.35 +
9.36 + unsigned int detach();
9.37 +
9.38 + /* Interface for the pager. */
9.39 +
9.40 + Flexpage *get(offset_t offset);
9.41 +
9.42 + void queue(Flexpage *flexpage);
9.43 +
9.44 + void flush_all(offset_t start, offset_t size);
9.45 +
9.46 + offset_t get_data_size();
9.47 +
9.48 + /* Data transfer methods, implementing PageOwner. */
9.49 +
9.50 + void fill(Flexpage *flexpage);
9.51 +
9.52 + void flush(Flexpage *flexpage, bool purge);
9.53 +
9.54 + /* Interface for the page collection, implementing PageOwner. */
9.55 +
9.56 + void remove(Flexpage *flexpage);
9.57 +};
9.58 +
9.59 +// vim: tabstop=4 expandtab shiftwidth=4
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/page_queue.cc Sat Jan 23 00:01:22 2021 +0100
11.3 @@ -0,0 +1,103 @@
11.4 +#include "page_queue.h"
11.5 +
11.6 +#include <stdio.h>
11.7 +
11.8 +/* Keep waiting for a potential queue non-empty condition.
11.9 + Then, attempt to pop an entry from the queue. */
11.10 +
11.11 +void PageQueue::pop(PageOwner **owner, Flexpage **flexpage)
11.12 +{
11.13 + std::unique_lock<std::mutex> guard(_lock);
11.14 + QueueEntry entry;
11.15 +
11.16 + while (1)
11.17 + {
11.18 + if (_pop(&entry))
11.19 + {
11.20 + *owner = entry.owner;
11.21 + *flexpage = entry.flexpage;
11.22 + return;
11.23 + }
11.24 + else
11.25 + _counter.wait(guard);
11.26 + }
11.27 +}
11.28 +
11.29 +/* Check the queue for entries, returning false if no entries are available,
11.30 + returning true and providing the details if an entry can be removed from the
11.31 + front of the queue. */
11.32 +
11.33 +bool PageQueue::_pop(QueueEntry *entry)
11.34 +{
11.35 + if (_queue.empty())
11.36 + return false;
11.37 +
11.38 + *entry = _queue.front();
11.39 + _queue.pop_front();
11.40 +
11.41 + /* Remove any position reference for the flexpage. */
11.42 +
11.43 + Positions::iterator position = _positions.find(entry->flexpage);
11.44 +
11.45 + if (position != _positions.end())
11.46 + _positions.erase(position);
11.47 +
11.48 + return true;
11.49 +}
11.50 +
11.51 +/* Push an entry for the given owner and flexpage to the queue. */
11.52 +
11.53 +void PageQueue::push(PageOwner *owner, Flexpage *flexpage)
11.54 +{
11.55 + std::lock_guard<std::mutex> guard(_lock);
11.56 +
11.57 + /* Record the entry and a position reference for the flexpage. */
11.58 +
11.59 + _queue.push_back((QueueEntry) {flexpage, owner});
11.60 +
11.61 + Queue::iterator last = _queue.end();
11.62 + last--;
11.63 + _positions.insert(Position(flexpage, last));
11.64 +
11.65 + _counter.notify_one();
11.66 +}
11.67 +
11.68 +/* Push an entry to the front of the queue. */
11.69 +
11.70 +void PageQueue::push_front(PageOwner *owner, Flexpage *flexpage)
11.71 +{
11.72 + std::lock_guard<std::mutex> guard(_lock);
11.73 +
11.74 + _queue.push_back((QueueEntry) {flexpage, owner});
11.75 + _positions.insert(Position(flexpage, _queue.begin()));
11.76 +
11.77 + _counter.notify_one();
11.78 +}
11.79 +
11.80 +/* Remove an entry for the given owner and flexpage from the queue. */
11.81 +
11.82 +bool PageQueue::remove(PageOwner *owner, Flexpage *flexpage)
11.83 +{
11.84 + std::lock_guard<std::mutex> guard(_lock);
11.85 +
11.86 + Positions::iterator position = _positions.find(flexpage);
11.87 +
11.88 + if (position == _positions.end())
11.89 + return false;
11.90 +
11.91 + /* The found owner may be different from the requesting owner or even NULL
11.92 + if another owner has acquired and then purged its pages. Such a purged
11.93 + flexpage is not immediately usable, however. */
11.94 +
11.95 + Queue::iterator entry = position->second;
11.96 +
11.97 + if ((entry->owner == NULL) || (entry->owner != owner))
11.98 + return false;
11.99 +
11.100 + _queue.erase(entry);
11.101 + _positions.erase(position);
11.102 +
11.103 + return true;
11.104 +}
11.105 +
11.106 +// vim: tabstop=4 expandtab shiftwidth=4
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/page_queue.h Sat Jan 23 00:01:22 2021 +0100
12.3 @@ -0,0 +1,46 @@
12.4 +#pragma once
12.5 +
12.6 +#include <condition_variable>
12.7 +#include <list>
12.8 +#include <map>
12.9 +#include <mutex>
12.10 +
12.11 +#include "flexpage.h"
12.12 +#include "page_owner.h"
12.13 +
12.14 +
12.15 +
12.16 +/* Collection types. */
12.17 +
12.18 +typedef struct { Flexpage *flexpage; PageOwner *owner; } QueueEntry;
12.19 +typedef std::list<QueueEntry> Queue;
12.20 +
12.21 +typedef std::pair<Flexpage *, Queue::iterator> Position;
12.22 +typedef std::map<Flexpage *, Queue::iterator> Positions;
12.23 +
12.24 +
12.25 +
12.26 +/* A queue of issued pages. */
12.27 +
12.28 +class PageQueue
12.29 +{
12.30 +protected:
12.31 + Queue _queue;
12.32 + Positions _positions;
12.33 +
12.34 + std::mutex _lock;
12.35 + std::condition_variable _counter;
12.36 +
12.37 + bool _pop(QueueEntry *entry);
12.38 +
12.39 +public:
12.40 + void pop(PageOwner **owner, Flexpage **flexpage);
12.41 +
12.42 + void push(PageOwner *owner, Flexpage *flexpage);
12.43 +
12.44 + void push_front(PageOwner *owner, Flexpage *flexpage);
12.45 +
12.46 + bool remove(PageOwner *owner, Flexpage *flexpage);
12.47 +};
12.48 +
12.49 +// vim: tabstop=4 expandtab shiftwidth=4
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/pager.cc Sat Jan 23 00:01:22 2021 +0100
13.3 @@ -0,0 +1,61 @@
13.4 +#include "dataspace_server.h"
13.5 +#include "ipc.h"
13.6 +#include "pager.h"
13.7 +
13.8 +
13.9 +
13.10 +Pager::Pager(PageMapper *mapper)
13.11 +: _start(0), _size(0), _mapper(mapper)
13.12 +{
13.13 + _mapper->attach();
13.14 +}
13.15 +
13.16 +void Pager::close()
13.17 +{
13.18 + _mapper->detach();
13.19 +}
13.20 +
13.21 +PagerState Pager::mmap(offset_t start, offset_t size)
13.22 +{
13.23 + _start = trunc(start, PAGE_SIZE);
13.24 + _size = round(start + size, PAGE_SIZE) - _start;
13.25 +
13.26 + return PagerState(_start, _size, 0);
13.27 +}
13.28 +
13.29 +/* Map a flexpage corresponding to the dataspace 'offset' involving a 'hot_spot'
13.30 + (flexpage offset). */
13.31 +
13.32 +long Pager::map(unsigned long offset, l4_addr_t hot_spot, unsigned long flags, l4_snd_fpage_t *region)
13.33 +{
13.34 + offset_t file_offset = _start + offset;
13.35 + offset_t max_offset = _start + _size;
13.36 + Flexpage *flexpage = _mapper->get(file_offset);
13.37 +
13.38 + /* Issue the flexpage via the IPC system. */
13.39 +
13.40 + long err = ipc_prepare_flexpage(flexpage, file_offset, max_offset, hot_spot, flags, region);
13.41 +
13.42 + if (err)
13.43 + return err;
13.44 +
13.45 + err = complete_Dataspace_map(*region);
13.46 +
13.47 + if (err)
13.48 + return err;
13.49 +
13.50 + /* After the flexpage is issued, it is queued for future reuse. */
13.51 +
13.52 + _mapper->queue(flexpage);
13.53 +
13.54 + return IPC_MESSAGE_SENT;
13.55 +}
13.56 +
13.57 +/* Return the total size of the data. */
13.58 +
13.59 +offset_t Pager::get_data_size()
13.60 +{
13.61 + return _mapper->get_data_size();
13.62 +}
13.63 +
13.64 +// vim: tabstop=4 expandtab shiftwidth=4
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
14.2 +++ b/pager.h Sat Jan 23 00:01:22 2021 +0100
14.3 @@ -0,0 +1,34 @@
14.4 +#pragma once
14.5 +
14.6 +#include "dataspace_interface.h"
14.7 +#include "page_mapper.h"
14.8 +#include "pager_state.h"
14.9 +#include "resource.h"
14.10 +
14.11 +
14.12 +
14.13 +/* A pager exposing a dataspace. */
14.14 +
14.15 +class Pager : public Dataspace, public Resource
14.16 +{
14.17 +protected:
14.18 + offset_t _start, _size;
14.19 + PageMapper *_mapper;
14.20 +
14.21 +public:
14.22 + explicit Pager(PageMapper *mapper);
14.23 +
14.24 + void close();
14.25 +
14.26 + /* Paging methods. */
14.27 +
14.28 + long map(unsigned long offset, l4_addr_t hot_spot, unsigned long flags, l4_snd_fpage_t *region);
14.29 +
14.30 + /* Limit methods. */
14.31 +
14.32 + offset_t get_data_size();
14.33 +
14.34 + PagerState mmap(offset_t start, offset_t size);
14.35 +};
14.36 +
14.37 +// vim: tabstop=4 expandtab shiftwidth=4
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
15.2 +++ b/pager_state.h Sat Jan 23 00:01:22 2021 +0100
15.3 @@ -0,0 +1,18 @@
15.4 +#pragma once
15.5 +
15.6 +/* A package of resource region details. */
15.7 +
15.8 +class PagerState
15.9 +{
15.10 +public:
15.11 + offset_t data_start, data_size, populated_size;
15.12 +
15.13 + explicit PagerState(offset_t data_start, offset_t data_size,
15.14 + offset_t populated_size)
15.15 + : data_start(data_start), data_size(data_size),
15.16 + populated_size(populated_size)
15.17 + {
15.18 + }
15.19 +};
15.20 +
15.21 +// vim: tabstop=4 expandtab shiftwidth=4
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/pages.cc Sat Jan 23 00:01:22 2021 +0100
16.3 @@ -0,0 +1,64 @@
16.4 +#include "pages.h"
16.5 +
16.6 +Pages::Pages(Memory *memory)
16.7 +: _memory(memory)
16.8 +{
16.9 +}
16.10 +
16.11 +Pages::Pages()
16.12 +{
16.13 + _memory = new Memory();
16.14 +}
16.15 +
16.16 +/* Remove the first flexpage in the queue. If its owner exists, remove it from
16.17 + the owner (retiring the content). Return the flexpage for reuse. */
16.18 +
16.19 +Flexpage *Pages::remove()
16.20 +{
16.21 + PageOwner *owner;
16.22 + Flexpage *flexpage;
16.23 +
16.24 + _queue.pop(&owner, &flexpage);
16.25 +
16.26 + if (owner != NULL)
16.27 + owner->remove(flexpage);
16.28 +
16.29 + return flexpage;
16.30 +}
16.31 +
16.32 +/* Reserve 'flexpage' by removing it from this collection. */
16.33 +
16.34 +bool Pages::reserve(PageOwner *owner, Flexpage *flexpage)
16.35 +{
16.36 + return _queue.remove(owner, flexpage);
16.37 +}
16.38 +
16.39 +/* Obtain a new flexpage. Return the flexpage or None if no new flexpage could
16.40 + be created. */
16.41 +
16.42 +Flexpage *Pages::flexpage()
16.43 +{
16.44 + Region *region = _memory->region();
16.45 +
16.46 + if (region != NULL)
16.47 + return new Flexpage(region);
16.48 + else
16.49 + return NULL;
16.50 +}
16.51 +
16.52 +/* Queue an entry associating the given 'owner' and 'flexpage'. */
16.53 +
16.54 +void Pages::queue(PageOwner *owner, Flexpage *flexpage)
16.55 +{
16.56 + _queue.push(owner, flexpage);
16.57 +}
16.58 +
16.59 +/* Push an entry for 'flexpage' without owner association for immediate
16.60 + reuse. */
16.61 +
16.62 +void Pages::release(Flexpage *flexpage)
16.63 +{
16.64 + _queue.push_front(NULL, flexpage);
16.65 +}
16.66 +
16.67 +// vim: tabstop=4 expandtab shiftwidth=4
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/test_file_accessor.cc Sat Jan 23 00:01:22 2021 +0100
18.3 @@ -0,0 +1,54 @@
18.4 +#include <stdio.h>
18.5 +#include <string.h>
18.6 +
18.7 +#include "test_file_accessor.h"
18.8 +
18.9 +TestFileAccessor::TestFileAccessor(fileid_t fileid, offset_t size)
18.10 +: Accessor(fileid, size)
18.11 +{
18.12 +}
18.13 +
18.14 +/* Data transfer methods. */
18.15 +
18.16 +void TestFileAccessor::fill(Flexpage *flexpage)
18.17 +{
18.18 + Region *region = flexpage->region;
18.19 + offset_t filepos = flexpage->base_offset;
18.20 +
18.21 + /* Tag the region with file state. */
18.22 +
18.23 + region->fill(fileid, filepos);
18.24 +
18.25 + /* Write some data to each page of the flexpage in each region. This
18.26 + allows each page to be tested regardless of how large each flexpage
18.27 + or region is. */
18.28 +
18.29 + offset_t addr = flexpage->base_addr;
18.30 + offset_t limit = addr + flexpage->size;
18.31 +
18.32 + while (addr < limit)
18.33 + {
18.34 + /* Overwrite enough of any previous data to make the new data
18.35 + readable. */
18.36 +
18.37 + char tag[32];
18.38 +
18.39 + sprintf(tag, "%ld:%ld", fileid, filepos);
18.40 +
18.41 + memset((void *) addr, 0, strlen(tag) + 1);
18.42 + strcpy((char *) addr, tag);
18.43 +
18.44 + filepos += PAGE_SIZE;
18.45 + addr += PAGE_SIZE;
18.46 + }
18.47 +}
18.48 +
18.49 +void TestFileAccessor::flush(Flexpage *flexpage)
18.50 +{
18.51 + /* NOTE: Flushing would not necessarily blank the region as this does.
18.52 + Also, a real flush operation would store the memory content. */
18.53 +
18.54 + flexpage->region->flush();
18.55 +}
18.56 +
18.57 +// vim: tabstop=4 expandtab shiftwidth=4
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
19.2 +++ b/test_file_accessor.h Sat Jan 23 00:01:22 2021 +0100
19.3 @@ -0,0 +1,19 @@
19.4 +#pragma once
19.5 +
19.6 +#include "accessor.h"
19.7 +
19.8 +/* A file accessor, providing flexpages corresponding to file regions. */
19.9 +
19.10 +class TestFileAccessor : public Accessor
19.11 +{
19.12 +public:
19.13 + explicit TestFileAccessor(fileid_t fileid, offset_t size=0);
19.14 +
19.15 + /* Data transfer methods. */
19.16 +
19.17 + virtual void fill(Flexpage *flexpage);
19.18 +
19.19 + virtual void flush(Flexpage *flexpage);
19.20 +};
19.21 +
19.22 +// vim: tabstop=4 expandtab shiftwidth=4