# HG changeset patch # User Paul Boddie # Date 1653692344 -7200 # Node ID 86957db2f4f014ac4b62c2bc84bfcc4e3e59e7dc # Parent a1c680a25972191e6c77ad69d29252d909199870 Introduced separate page mappers for masking and copy-on-write semantics. diff -r a1c680a25972 -r 86957db2f4f0 libfsserver/include/fsserver/copied_page_mapper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/include/fsserver/copied_page_mapper.h Sat May 28 00:59:04 2022 +0200 @@ -0,0 +1,78 @@ +/* + * A page mapper providing copied memory pages or deferring to another page + * mapper to satisfy file accesses. + * + * Copyright (C) 2021, 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include +#include + + + +/* A special flexpage class for copied flexpages. */ + +class CopiedFlexpage : public Flexpage +{ +public: + explicit CopiedFlexpage(Region *region = NULL); +}; + + + +/* A file mapper, associating flexpages with file regions. */ + +class CopiedPageMapper : public GenericPageMapper +{ +protected: + GenericPageMapper *_mapper; + offset_t _size; + + /* Copied page support. */ + + AccessMap _map; + MemoryIncremental _memory; + + /* Internal flexpage retrieval methods. */ + + Flexpage *find(offset_t offset); + + Flexpage *replicate_flexpage(offset_t offset, Flexpage *flexpage); + +public: + explicit CopiedPageMapper(GenericPageMapper *mapper); + + virtual ~CopiedPageMapper(); + + /* Interface for the pager, implementing GenericPageMapper. */ + + Flexpage *get(offset_t offset, map_flags_t flags); + + void queue(Flexpage *flexpage); + + void flush_all(offset_t start, offset_t size); + + offset_t get_data_size(); + + void set_data_size(offset_t size); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r a1c680a25972 -r 86957db2f4f0 libfsserver/include/fsserver/generic_page_mapper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/include/fsserver/generic_page_mapper.h Sat May 28 00:59:04 2022 +0200 @@ -0,0 +1,47 @@ +/* + * A generic page mapper providing memory pages to satisfy file accesses. + * + * Copyright (C) 2021, 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include + + + +/* A generic file mapper interface, accessed by the pager, associating flexpages + with file regions. */ + +class GenericPageMapper +{ +public: + virtual ~GenericPageMapper(); + + virtual Flexpage *get(offset_t offset, map_flags_t flags); + + virtual void queue(Flexpage *flexpage); + + virtual void flush_all(offset_t start, offset_t size); + + virtual offset_t get_data_size(); + + virtual void set_data_size(offset_t size); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r a1c680a25972 -r 86957db2f4f0 libfsserver/include/fsserver/masked_page_mapper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/include/fsserver/masked_page_mapper.h Sat May 28 00:59:04 2022 +0200 @@ -0,0 +1,82 @@ +/* + * A page mapper providing memory pages to satisfy file accesses, masking the + * limits of a visible region of the file's contents. + * + * Copyright (C) 2021, 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include +#include + + + +/* A special flexpage class for masked flexpages. */ + +class MaskedFlexpage : public Flexpage +{ +public: + explicit MaskedFlexpage(Region *region = NULL); +}; + + + +/* A file mapper, associating flexpages with file regions. */ + +class MaskedPageMapper : public GenericPageMapper +{ +protected: + GenericPageMapper *_mapper; + offset_t _size; + + /* Masked region support. */ + + MemoryIncremental _memory; + offset_t _start_visible, _end_visible; + MaskedFlexpage _start_flexpage, _end_flexpage, _zero_flexpage; + + /* Internal flexpage retrieval methods. */ + + Flexpage *get_masked_flexpage(Flexpage *flexpage); + + void allocate_region(Flexpage *flexpage, Flexpage &masked); + + void populate_region(Flexpage *flexpage, Flexpage &masked, + bool has_start, bool has_end); + +public: + explicit MaskedPageMapper(GenericPageMapper *mapper, offset_t start_visible, + offset_t end_visible); + + virtual ~MaskedPageMapper(); + + /* Interface for the pager, implementing GenericPageMapper. */ + + Flexpage *get(offset_t offset, map_flags_t flags); + + void queue(Flexpage *flexpage); + + void flush_all(offset_t start, offset_t size); + + offset_t get_data_size(); + + void set_data_size(offset_t size); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r a1c680a25972 -r 86957db2f4f0 libfsserver/include/fsserver/page_mapper.h --- a/libfsserver/include/fsserver/page_mapper.h Fri May 27 00:38:27 2022 +0200 +++ b/libfsserver/include/fsserver/page_mapper.h Sat May 28 00:59:04 2022 +0200 @@ -1,7 +1,7 @@ /* * A page mapper providing memory pages to satisfy file accesses. * - * Copyright (C) 2021 Paul Boddie + * Copyright (C) 2021, 2022 Paul Boddie * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -31,7 +32,7 @@ /* A file mapper, associating flexpages with file regions. */ -class PageMapper : public PageOwner +class PageMapper : public GenericPageMapper, public PageOwner { protected: AccessMap _map; @@ -56,7 +57,7 @@ Accessor *accessor() { return _accessor; } - /* Interface for the pager. */ + /* Interface for the pager, implementing GenericPageMapper. */ Flexpage *get(offset_t offset, map_flags_t flags); diff -r a1c680a25972 -r 86957db2f4f0 libfsserver/include/fsserver/pager.h --- a/libfsserver/include/fsserver/pager.h Fri May 27 00:38:27 2022 +0200 +++ b/libfsserver/include/fsserver/pager.h Sat May 28 00:59:04 2022 +0200 @@ -23,9 +23,8 @@ #include -#include +#include #include -#include @@ -35,33 +34,11 @@ { protected: offset_t _start, _size; - PageMapper *_mapper; + GenericPageMapper *_mapper, *_mapper_base, *_mapper_masked, *_mapper_copied; map_flags_t _flags; - /* Support for masked regions and replicated flexpages. */ - - MemoryIncremental _memory; - - /* Masked region support. */ - - bool _is_masked; - offset_t _start_visible, _end_visible; - Flexpage _start_flexpage, _end_flexpage, _zero_flexpage; - - Flexpage *get_masked_flexpage(Flexpage *flexpage); - - void allocate_region(Flexpage *flexpage, Flexpage &masked); - - void populate_region(Flexpage *flexpage, Flexpage &masked, - bool has_start, bool has_end); - - /* Replicated flexpage support. */ - - AccessMap _map; - Flexpage *get_replicated_flexpage(Flexpage *flexpage, map_flags_t flags); - public: - explicit Pager(PageMapper *mapper, map_flags_t flags); + explicit Pager(GenericPageMapper *mapper, map_flags_t flags); virtual void close(); diff -r a1c680a25972 -r 86957db2f4f0 libfsserver/lib/Makefile --- a/libfsserver/lib/Makefile Fri May 27 00:38:27 2022 +0200 +++ b/libfsserver/lib/Makefile Sat May 28 00:59:04 2022 +0200 @@ -76,7 +76,10 @@ generic/resource_server.cc \ generic/simple_pager.cc \ mapping/access_map.cc \ + mapping/copied_page_mapper.cc \ + mapping/generic_page_mapper.cc \ mapping/ipc.cc \ + mapping/masked_page_mapper.cc \ mapping/page_mapper.cc \ pages/page_queue.cc \ pages/page_queue_partitioned.cc \ diff -r a1c680a25972 -r 86957db2f4f0 libfsserver/lib/generic/pager.cc --- a/libfsserver/lib/generic/pager.cc Fri May 27 00:38:27 2022 +0200 +++ b/libfsserver/lib/generic/pager.cc Sat May 28 00:59:04 2022 +0200 @@ -23,16 +23,19 @@ #include "ipc.h" #include "pager.h" -#include +#include "copied_page_mapper.h" +#include "masked_page_mapper.h" /* Initialise the pager with a page mapper and the given flags controlling access to a file. */ -Pager::Pager(PageMapper *mapper, map_flags_t flags) -: _start(0), _size(0), _mapper(mapper), _flags(flags), - _is_masked(false), _start_visible(0), _end_visible(0) +Pager::Pager(GenericPageMapper *mapper, map_flags_t flags) +: _start(0), _size(0), + _mapper(mapper), _mapper_base(mapper), _mapper_masked(NULL), + _mapper_copied(NULL), + _flags(flags) { } @@ -40,7 +43,17 @@ void Pager::close() { - /* NOTE: Need to deallocate any allocated regions and flexpages. */ + if (_mapper_masked != NULL) + { + delete _mapper_masked; + _mapper_masked = NULL; + } + + if (_mapper_copied != NULL) + { + delete _mapper_copied; + _mapper_copied = NULL; + } } /* Flush data to the file. */ @@ -78,18 +91,21 @@ *start_pos = _start; *end_pos = _start + _size; - *size = _mapper->get_data_size(); + *size = _mapper_base->get_data_size(); /* Permit masking of mapped regions. */ - if (start_visible || end_visible) + if ((start_visible || end_visible) && + ((*start_pos != start_visible) || (*end_pos != end_visible))) { - _start_visible = start_visible; - _end_visible = end_visible; - _is_masked = (*start_pos != _start_visible) || (*end_pos != _end_visible); + /* Introduce the masked page and copied page mappers. */ + + _mapper_masked = new MaskedPageMapper(_mapper_base, start_visible, end_visible); + _mapper_copied = new CopiedPageMapper(_mapper_masked); + _mapper = _mapper_copied; } else - _is_masked = false; + _mapper = _mapper_base; return L4_EOK; } @@ -110,43 +126,22 @@ if (flags & (~(_flags | L4RE_DS_F_X))) return -L4_EACCESS; - Flexpage *issued_flexpage = NULL, *obtained_flexpage = NULL; - - /* Obtain any replicated flexpage. - NOTE: An additional condition should be introduced to test for the - relevance of replicated flexpages. */ - - if (flags & L4RE_DS_F_W) - issued_flexpage = _map.find(file_offset); - - /* Without any replicated flexpage, obtain one for the shared, underlying - file data. */ + /* Obtain a flexpage from the page mapper. */ - if (issued_flexpage == NULL) - { - obtained_flexpage = _mapper->get(file_offset, flags); - - /* Determine if the flexpage should be masked. */ - - issued_flexpage = get_masked_flexpage(obtained_flexpage); - - /* Determine if the flexpage should be replicated. */ - - issued_flexpage = get_replicated_flexpage(issued_flexpage, flags); - } + Flexpage *flexpage = _mapper->get(file_offset, flags); /* Issue the flexpage via the IPC system. */ - long err = ipc_prepare_flexpage(issued_flexpage, file_offset, max_offset, + long err = ipc_prepare_flexpage(flexpage, file_offset, max_offset, hot_spot, flags, region); if (!err) err = complete_Dataspace_map(*region); - /* After the obtained flexpage is issued, it is queued for future reuse. */ + /* After the obtained flexpage is issued, it is queued for future reuse, if + appropriate for the mapper concerned. */ - if (obtained_flexpage != NULL) - _mapper->queue(obtained_flexpage); + _mapper->queue(flexpage); if (err) return err; @@ -161,116 +156,4 @@ return _mapper->get_data_size(); } -/* Detect flexpages with masked content, introducing separate flexpages - offering masked content from the same region. */ - -Flexpage *Pager::get_masked_flexpage(Flexpage *flexpage) -{ - /* If not masking content, return the original flexpage. */ - - if (!_is_masked) - return flexpage; - - /* Determine whether the flexpage involves the limits of the visible - region or is beyond such limits. */ - - bool has_start = flexpage->supports_position(_start_visible) && - flexpage->base_offset != _start_visible; - bool has_end = flexpage->supports_position(_end_visible); - bool has_zero = (flexpage->base_offset >= _end_visible) || - (flexpage->base_offset + flexpage->size < _start_visible); - - /* Return the original flexpage within the visible limits. */ - - if (!has_start && !has_end && !has_zero) - return flexpage; - - /* Allocate and populate a region in one of the preallocated flexpages for - masked content. */ - - Flexpage &masked = has_start ? _start_flexpage : - has_end ? _end_flexpage : - _zero_flexpage; - - allocate_region(flexpage, masked); - populate_region(flexpage, masked, has_start, has_end); - - /* Associate the preallocated flexpage with the original flexpage. */ - - flexpage->associate(&masked); - - return &masked; -} - -void Pager::allocate_region(Flexpage *flexpage, Flexpage &masked) -{ - offset_t needed = flexpage->region->size(); - - /* Attempt to re-use an existing region. */ - - if (masked.region != NULL) - { - if (masked.region->size() == needed) - return; - else - _memory.release(masked.region); - } - - /* Set the region in the flexpage. */ - - masked.set_region(_memory.region(needed)); - masked.reset(flexpage->base_offset); -} - -void Pager::populate_region(Flexpage *flexpage, Flexpage &masked, - bool has_start, bool has_end) -{ - /* Without any limits involved, provide a zero flexpage. */ - - if (!has_start && !has_end) - { - memset((void *) masked.region->start, 0, masked.size); - return; - } - - /* Determine the content limits given start and/or end offsets. */ - - offset_t start_offset = has_start ? _start_visible - masked.base_offset : 0; - offset_t end_offset = has_end ? _end_visible - masked.base_offset : masked.size; - - if (has_start) - memset((void *) masked.region->start, 0, start_offset); - - memcpy((void *) (masked.region->start + start_offset), - (const void *) (flexpage->region->start + start_offset), - end_offset - start_offset); - - if (has_end) - memset((void *) (masked.region->start + end_offset), 0, masked.size - end_offset); -} - -/* Detect flexpages with replicated content, introducing separate flexpages - offering replicated content from the same region. */ - -Flexpage *Pager::get_replicated_flexpage(Flexpage *flexpage, map_flags_t flags) -{ - /* NOTE: An additional condition should be introduced to test for the - relevance of replicated flexpages. For now, detect copy-on-write - situations. */ - - if (_is_masked && (flags & L4RE_DS_F_W)) - { - Region *region = _memory.region(flexpage->size); - Flexpage *replicated = new Flexpage(region); - - replicated->reset(flexpage->base_offset); - - memcpy((void *) region->start, (const void *) flexpage->region->start, flexpage->size); - _map.insert(replicated); - return replicated; - } - else - return flexpage; -} - // vim: tabstop=4 expandtab shiftwidth=4 diff -r a1c680a25972 -r 86957db2f4f0 libfsserver/lib/mapping/copied_page_mapper.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/lib/mapping/copied_page_mapper.cc Sat May 28 00:59:04 2022 +0200 @@ -0,0 +1,154 @@ +/* + * A page mapper providing copied memory pages or deferring to another page + * mapper to satisfy file accesses. + * + * Copyright (C) 2021, 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include + +#include "copied_page_mapper.h" + + + +/* Provide mapped pages populated with the given 'mapper', with pages obtained + from the given 'pages' collection. */ + +CopiedPageMapper::CopiedPageMapper(GenericPageMapper *mapper) +: _mapper(mapper) +{ + _size = _mapper->get_data_size(); +} + +/* Upon deallocation, purge active pages. */ + +CopiedPageMapper::~CopiedPageMapper() +{ +} + +/* Interface for the pager. */ + +/* Return a flexpage providing access to the indicated file 'offset'. + + The returned flexpage will either provide direct access to the underlying + file content or be a completely new flexpage modified through writes to + memory. */ + +Flexpage *CopiedPageMapper::get(offset_t offset, map_flags_t flags) +{ + Flexpage *f = find(offset); + + /* Defer to the underlying page mapper if no flexpage was found. */ + + if (f == NULL) + { + f = _mapper->get(offset, flags); + + /* Replicate the underlying flexpage if writing. */ + + if (flags & L4RE_DS_F_W) + { + Flexpage *rf = replicate_flexpage(offset, f); + _mapper->queue(f); + f = rf; + } + } + + /* Upgrade the access flags. */ + + f->upgrade(flags); + return f; +} + +/* Queue the given 'flexpage'. */ + +void CopiedPageMapper::queue(Flexpage *flexpage) +{ + if (dynamic_cast(flexpage) == NULL) + _mapper->queue(flexpage); +} + +/* Flush pages in the given range from 'start' with 'size'. */ + +void CopiedPageMapper::flush_all(offset_t start, offset_t size) +{ + /* NOTE: This might be superfluous since copy-on-write regions should not + update content. */ + + _mapper->flush_all(start, size); +} + +/* Return the maximum extent of the mapped resource. */ + +offset_t CopiedPageMapper::get_data_size() +{ + return _size; +} + +/* Set the maximum extent of the mapped resource. */ + +void CopiedPageMapper::set_data_size(offset_t size) +{ + _size = size; +} + +/* Internal flexpage retrieval methods. */ + +/* Find an existing flexpage for 'offset'. */ + +Flexpage *CopiedPageMapper::find(offset_t offset) +{ + return _map.find(offset); +} + +/* Replicate an underlying flexpage for the file 'offset' using the given + 'flexpage'. */ + +Flexpage *CopiedPageMapper::replicate_flexpage(offset_t offset, Flexpage *flexpage) +{ + /* Obtain a new memory region and a new flexpage. */ + + Region *region = _memory.region(flexpage->size); + Flexpage *replicated = new CopiedFlexpage(region); + + /* Configure the flexpage for the file region. */ + + replicated->reset(offset); + + /* Copy the contents of the underlying flexpage. */ + + memcpy((void *) region->start, (const void *) flexpage->region->start, flexpage->size); + + /* Register the flexpage for future accesses. */ + + _map.insert(replicated); + return replicated; +} + + + +/* Copied flexpage constructor. */ + +CopiedFlexpage::CopiedFlexpage(Region *region) +: Flexpage(region) +{ +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r a1c680a25972 -r 86957db2f4f0 libfsserver/lib/mapping/generic_page_mapper.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/lib/mapping/generic_page_mapper.cc Sat May 28 00:59:04 2022 +0200 @@ -0,0 +1,30 @@ +/* + * A generic page mapper providing memory pages to satisfy file accesses. + * + * Copyright (C) 2021, 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include "generic_page_mapper.h" + + + +GenericPageMapper::~GenericPageMapper() +{ +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r a1c680a25972 -r 86957db2f4f0 libfsserver/lib/mapping/masked_page_mapper.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfsserver/lib/mapping/masked_page_mapper.cc Sat May 28 00:59:04 2022 +0200 @@ -0,0 +1,195 @@ +/* + * A page mapper providing memory pages to satisfy file accesses, masking the + * limits of a visible region of the file's contents. + * + * Copyright (C) 2021, 2022 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include "masked_page_mapper.h" + + + +/* Provide mapped pages populated using the given 'mapper', with a visible + region defined that causes the limits of this region to be masked. */ + +MaskedPageMapper::MaskedPageMapper(GenericPageMapper *mapper, + offset_t start_visible, offset_t end_visible) +: _mapper(mapper), _start_visible(start_visible), _end_visible(end_visible) +{ + _size = _mapper->get_data_size(); +} + +MaskedPageMapper::~MaskedPageMapper() +{ + if (_start_flexpage.region != NULL) + _memory.release(_start_flexpage.region); + + if (_end_flexpage.region != NULL) + _memory.release(_end_flexpage.region); + + if (_zero_flexpage.region != NULL) + _memory.release(_zero_flexpage.region); +} + +/* Interface for the pager. */ + +/* Return a flexpage providing access to the indicated file 'offset'. + + The returned flexpage will either provide direct access to the underlying + file content or be a completely new flexpage containing masked content. */ + +Flexpage *MaskedPageMapper::get(offset_t offset, map_flags_t flags) +{ + Flexpage *f = _mapper->get(offset, flags); + Flexpage *mf = get_masked_flexpage(f); + + if (f != mf) + _mapper->queue(f); + + return mf; +} + +/* Queue the given 'flexpage'. */ + +void MaskedPageMapper::queue(Flexpage *flexpage) +{ + if (dynamic_cast(flexpage) == NULL) + _mapper->queue(flexpage); +} + +/* Flush pages in the given range from 'start' with 'size'. */ + +void MaskedPageMapper::flush_all(offset_t start, offset_t size) +{ + /* NOTE: This might be superfluous since masked regions probably should be + read-only or copy-on-write. */ + + _mapper->flush_all(start, size); +} + +/* Return the maximum extent of the mapped resource. */ + +offset_t MaskedPageMapper::get_data_size() +{ + return _size; +} + +/* Set the maximum extent of the mapped resource. */ + +void MaskedPageMapper::set_data_size(offset_t size) +{ + _size = size; +} + +/* Internal flexpage retrieval methods. */ + +/* Detect flexpages with masked content, introducing separate flexpages + offering masked content from the same region. */ + +Flexpage *MaskedPageMapper::get_masked_flexpage(Flexpage *flexpage) +{ + /* Determine whether the flexpage involves the limits of the visible + region or is beyond such limits. */ + + bool has_start = flexpage->supports_position(_start_visible) && + flexpage->base_offset != _start_visible; + bool has_end = flexpage->supports_position(_end_visible); + bool has_zero = (flexpage->base_offset >= _end_visible) || + (flexpage->base_offset + flexpage->size < _start_visible); + + /* Return the original flexpage within the visible limits. */ + + if (!has_start && !has_end && !has_zero) + return flexpage; + + /* Allocate and populate a region in one of the preallocated flexpages for + masked content. */ + + Flexpage &masked = has_start ? _start_flexpage : + has_end ? _end_flexpage : + _zero_flexpage; + + allocate_region(flexpage, masked); + populate_region(flexpage, masked, has_start, has_end); + + /* Associate the preallocated flexpage with the original flexpage. */ + + flexpage->associate(&masked); + + return &masked; +} + +void MaskedPageMapper::allocate_region(Flexpage *flexpage, Flexpage &masked) +{ + offset_t needed = flexpage->region->size(); + + /* Attempt to re-use an existing region. */ + + if (masked.region != NULL) + { + if (masked.region->size() == needed) + return; + else + _memory.release(masked.region); + } + + /* Set the region in the flexpage. */ + + masked.set_region(_memory.region(needed)); + masked.reset(flexpage->base_offset); +} + +void MaskedPageMapper::populate_region(Flexpage *flexpage, Flexpage &masked, + bool has_start, bool has_end) +{ + /* Without any limits involved, provide a zero flexpage. */ + + if (!has_start && !has_end) + { + memset((void *) masked.region->start, 0, masked.size); + return; + } + + /* Determine the content limits given start and/or end offsets. */ + + offset_t start_offset = has_start ? _start_visible - masked.base_offset : 0; + offset_t end_offset = has_end ? _end_visible - masked.base_offset : masked.size; + + if (has_start) + memset((void *) masked.region->start, 0, start_offset); + + memcpy((void *) (masked.region->start + start_offset), + (const void *) (flexpage->region->start + start_offset), + end_offset - start_offset); + + if (has_end) + memset((void *) (masked.region->start + end_offset), 0, masked.size - end_offset); +} + + + +/* Masked flexpage constructor. */ + +MaskedFlexpage::MaskedFlexpage(Region *region) +: Flexpage(region) +{ +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r a1c680a25972 -r 86957db2f4f0 libmem/include/mem/flexpage.h --- a/libmem/include/mem/flexpage.h Fri May 27 00:38:27 2022 +0200 +++ b/libmem/include/mem/flexpage.h Sat May 28 00:59:04 2022 +0200 @@ -21,6 +21,8 @@ #pragma once +#include + #include #include @@ -77,6 +79,8 @@ { } + virtual ~Flexpage(); + void set_region(Region *region); void reset(offset_t offset); diff -r a1c680a25972 -r 86957db2f4f0 libmem/lib/src/flexpage.cc --- a/libmem/lib/src/flexpage.cc Fri May 27 00:38:27 2022 +0200 +++ b/libmem/lib/src/flexpage.cc Sat May 28 00:59:04 2022 +0200 @@ -19,14 +19,18 @@ * Boston, MA 02110-1301, USA */ -#include - #include #include "flexpage.h" +/* Virtual destructor required for introspection. */ + +Flexpage::~Flexpage() +{ +} + /* Reset the flexpage using 'offset', being the file offset. */ void Flexpage::reset(offset_t offset)