# HG changeset patch # User Paul Boddie # Date 1617231463 -7200 # Node ID 405eb83f7eed53aaf9c038f31f8aa8a3d3c2ef5d # Parent 138ddb918cf2b870457211ebc3d989e768162d20 Moved various files into subdirectories. Renamed Paging to FilePaging along with the associated files. diff -r 138ddb918cf2 -r 405eb83f7eed Makefile --- a/Makefile Thu Apr 01 00:39:16 2021 +0200 +++ b/Makefile Thu Apr 01 00:57:43 2021 +0200 @@ -43,51 +43,54 @@ COMMON_SRC_CC = memory/memory_utils.cc -PLAIN_SRC_CC_dstest_block_client = dstest_block_client.cc file.cc +PLAIN_SRC_CC_dstest_block_client = tests/dstest_block_client.cc file.cc -PLAIN_SRC_CC_dstest_host_client = dstest_host_client.cc file.cc +PLAIN_SRC_CC_dstest_host_client = tests/dstest_host_client.cc file.cc -PLAIN_SRC_CC_dstest_pipe_client = dstest_pipe_client.cc file.cc +PLAIN_SRC_CC_dstest_pipe_client = tests/dstest_pipe_client.cc file.cc -PLAIN_SRC_CC_dstest_test_client = dstest_test_client.cc file.cc +PLAIN_SRC_CC_dstest_test_client = tests/dstest_test_client.cc file.cc PLAIN_SRC_CC_common_server = \ - access_map.cc accessor.cc \ - flexpage.cc ipc.cc \ + accessor.cc \ + ipc.cc \ + mapping/access_map.cc mapping/flexpage.cc mapping/page_mapper.cc \ memory/memory_incremental.cc memory/memory_preallocated.cc \ memory/region.cc \ - page_mapper.cc pager.cc paging.cc \ + pager.cc \ pages/page_queue.cc pages/page_queue_partitioned.cc \ pages/page_queue_shared.cc pages/pages.cc \ - resource_server.cc simple_pager.cc + resource_server.cc + +PLAIN_SRC_CC_common_file_server = \ + files/file_pager.cc files/file_paging.cc \ + files/opener_resource.cc files/opener_context_resource.cc \ + simple_pager.cc PLAIN_SRC_CC_dstest_block_server = \ $(PLAIN_SRC_CC_common_server) \ - dstest_block_server.cc \ - files/file_pager.cc \ - files/opener_resource.cc files/opener_context_resource.cc \ + $(PLAIN_SRC_CC_common_file_server) \ files/block_file_accessor.cc files/block_file_opener.cc \ - files/host_file_accessor.cc files/host_file_opener.cc + files/host_file_accessor.cc files/host_file_opener.cc \ + tests/dstest_block_server.cc PLAIN_SRC_CC_dstest_host_server = \ $(PLAIN_SRC_CC_common_server) \ - dstest_host_server.cc \ - files/file_pager.cc \ - files/opener_resource.cc files/opener_context_resource.cc \ - files/host_file_accessor.cc files/host_file_opener.cc + $(PLAIN_SRC_CC_common_file_server) \ + files/host_file_accessor.cc files/host_file_opener.cc \ + tests/dstest_host_server.cc PLAIN_SRC_CC_dstest_pipe_server = \ $(PLAIN_SRC_CC_common_server) \ - dstest_pipe_server.cc \ pipes/pipe_opener_resource.cc pipes/pipe_pager.cc \ - pipes/pipe_accessor.cc pipes/pipe_paging.cc + pipes/pipe_accessor.cc pipes/pipe_paging.cc \ + tests/dstest_pipe_server.cc PLAIN_SRC_CC_dstest_test_server = \ $(PLAIN_SRC_CC_common_server) \ - dstest_test_server.cc \ - files/file_pager.cc \ - files/opener_resource.cc files/opener_context_resource.cc \ - files/test_file_accessor.cc files/test_file_opener.cc + $(PLAIN_SRC_CC_common_file_server) \ + files/test_file_accessor.cc files/test_file_opener.cc \ + tests/dstest_test_server.cc # Normal definitions. @@ -133,8 +136,7 @@ REQUIRES_LIBS = l4re_c-util libipc libstdc++ libsystypes -PRIVATE_INCDIR = $(PKGDIR) \ - $(PKGDIR)/files $(PKGDIR)/memory \ +PRIVATE_INCDIR = $(PKGDIR) $(PKGDIR)/files $(PKGDIR)/mapping $(PKGDIR)/memory \ $(PKGDIR)/pages $(PKGDIR)/pipes \ $(IDL_BUILD_DIR) $(IDL_EXPORT_DIR) diff -r 138ddb918cf2 -r 405eb83f7eed access_map.cc --- a/access_map.cc Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -#include "access_map.h" - -/* Return the flexpage supporting 'position'. */ - -Flexpage *AccessMap::find(offset_t position) -{ - std::lock_guard guard(_lock); - - _AccessMap::iterator it = _flexpages.upper_bound(position); - - if ((_flexpages.size() > 0) && (it != _flexpages.begin())) - { - it--; - - if (it->second->supports_position(position)) - return it->second; - } - - return NULL; -} - -/* Insert a mapping for 'flexpage'. */ - -void AccessMap::insert(Flexpage *flexpage) -{ - std::lock_guard guard(_lock); - - _flexpages.insert(_AccessMapEntry(flexpage->base_offset, flexpage)); -} - -/* Remove the mapping supported by 'flexpage'. - - The flexpage may have obtained by another mapper before being purged from - this object's mapping and before being purged from the queue (and thus - disassociated from this mapper), leaving an opportunity for another mapper to - now be removing it here. In such a situation, flushing has already occurred - and will not be performed again. */ - -bool AccessMap::remove(PageOwner *owner, Flexpage *flexpage) -{ - std::lock_guard guard(_lock); - - _AccessMap::iterator it = _flexpages.find(flexpage->base_offset); - - if (it != _flexpages.end()) - { - owner->flush(flexpage, true); - _flexpages.erase(flexpage->base_offset); - return true; - } - - return false; -} - -/* Purge all flexpages, using the 'owner' to flush their contents and - 'pages' to make the flexpages available to other accessors. */ - -void AccessMap::purge(PageOwner *owner, Pages *pages) -{ - std::lock_guard guard(_lock); - - _AccessMap::iterator it = _flexpages.begin(), entry; - - while (it != _flexpages.end()) - { - entry = it; - it++; - - Flexpage *flexpage = entry->second; - - /* Some flexpages may be unavailable in the queue. Only those - that can be reserved should be flushed and made available - again. */ - - if (pages->reserve(owner, flexpage)) - { - owner->flush(flexpage, true); - pages->release(flexpage); - _flexpages.erase(entry); - } - } -} - -/* Flush flexpages in the given range from 'start' with 'size', using 'owner' - and 'pages'. */ - -void AccessMap::flush_all(offset_t start, offset_t size, PageOwner *owner, Pages *pages) -{ - offset_t end = start + size; - - std::lock_guard guard(_lock); - - /* The start may be within an existing flexpage where the flexpage size is a - page multiple. */ - - _AccessMap::iterator it = _flexpages.upper_bound(start), entry; - - if ((_flexpages.size() > 0) && (it != _flexpages.begin())) - it--; - - /* Inspect flexpages at or after start until end. */ - - while (it != _flexpages.end()) - { - entry = it; - it++; - - Flexpage *flexpage = entry->second; - - if (flexpage->base_offset >= end) - break; - - /* Attempt to flush each flexpage, releasing ones that are no longer - needed. */ - - if (pages->reserve(owner, flexpage)) - { - owner->flush(flexpage, false); - - /* Where no users of the flexpage persist, release the flexpage for - reuse and remove this entry. */ - - if (!flexpage->valid()) - { - pages->release(flexpage); - _flexpages.erase(entry); - } - else - pages->queue(owner, flexpage); - } - } -} - -// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed access_map.h --- a/access_map.h Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -#pragma once - -#include "flexpage.h" -#include "page_owner.h" -#include "pages.h" - -#include -#include - -/* Collection types. */ - -typedef std::map _AccessMap; -typedef std::pair _AccessMapEntry; - -/* A mapping from file positions to flexpages. */ - -class AccessMap -{ -protected: - _AccessMap _flexpages; - std::mutex _lock; - -public: - Flexpage *find(offset_t position); - - void insert(Flexpage *flexpage); - - bool remove(PageOwner *owner, Flexpage *flexpage); - - void purge(PageOwner *owner, Pages *pages); - - void flush_all(offset_t start, offset_t size, PageOwner *owner, Pages *pages); -}; - -// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed dstest_block_client.cc --- a/dstest_block_client.cc Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -/* - * Test dataspace operations. - * - * Copyright (C) 2020, 2021 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 -#include -#include - -#include "file.h" -#include "memory_utils.h" - - - -static void show(file_t *file, unsigned long step, unsigned long sample) -{ - /* Allocate a buffer for sampling from the file. */ - - char buf[sample + 1]; - - for (unsigned long offset = 0; offset < file_populated_span(file); offset += step) - { - unsigned long remaining = file_populated_span(file) - offset; - unsigned long sample_remaining = remaining < sample ? remaining : sample; - - printf("%ld bytes from %p...\n", sample_remaining, (file->memory + offset)); - strncpy(buf, (file->memory + offset), sample_remaining); - buf[sample_remaining] = '\0'; - printf("%s\n", buf); - } -} - -int main(int argc, char *argv[]) -{ - if (argc < 4) - { - printf("Need filename, step and sample size.\n"); - return 1; - } - - /* Obtain filename and access parameters. */ - - char *filename = argv[1]; - unsigned long step = atoi(argv[2]); - unsigned long sample = atoi(argv[3]); - - /* Obtain access to the filesystem. */ - - l4_cap_idx_t server = l4re_env_get_cap("server"); - - /* Invoke the open method to receive the file reference. */ - - file_t file; - long err = file_open(&file, filename, server); - - if (err) - { - printf("Could not obtain file: %s\n", l4sys_errtostr(err)); - return 1; - } - - /* A region of the file is mapped. */ - - err = file_mmap(&file, 0, page(10)); - - if (err) - { - printf("Could not map file region: %s\n", l4sys_errtostr(err)); - return 1; - } - - show(&file, step, sample); - - /* Resizing must occur before writing beyond the end of file. Otherwise, the - data may get discarded if the supporting flexpage needs to be flushed. */ - - offset_t new_region = round(file_populated_span(&file), page(1)); - - printf("Resize to %ld...\n", new_region + file_populated_span(&file)); - - err = file_resize(&file, new_region + file_populated_span(&file)); - - if (err) - { - printf("Could not resize file: %s\n", l4sys_errtostr(err)); - return 1; - } - - printf("Resized file...\n"); - - /* Copy the sampled data to another file region. */ - - printf("Copy data to %ld...\n", new_region); - - for (unsigned long offset = 0; offset < file_populated_span(&file); offset += step) - { - memcpy(file.memory + new_region + offset, file.memory + offset, sample); - if (step > sample) - memset(file.memory + new_region + offset + sample, 0, step - sample); - } - - show(&file, step, sample); - - printf("File shown.\n"); - - return 0; -} - -// vim: tabstop=2 expandtab shiftwidth=2 diff -r 138ddb918cf2 -r 405eb83f7eed dstest_block_server.cc --- a/dstest_block_server.cc Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * Test dataspace operations. - * - * Copyright (C) 2020, 2021 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 -#include -#include - -#include "memory_incremental.h" -#include "memory_utils.h" -#include "page_queue_shared.h" -#include "pages.h" -#include "resource_server.h" -#include "block_file_opener.h" - - - -const unsigned int MEMORY_PAGES = 10; - -int main(void) -{ - /* Some memory plus infrastructure. */ - - MemoryIncremental mem(MEMORY_PAGES); - PageQueueShared queue; - Pages pages(&mem, &queue); - BlockFileOpener opener(&pages); - - /* Register a server associating it with the given object. */ - - ResourceServer server(&opener); - long err = server.bind("server"); - - if (err) - { - printf("Could not bind server: %s\n", l4sys_errtostr(err)); - return 1; - } - - printf("Starting server...\n"); - server.start(); - return 0; -} - -// vim: tabstop=2 expandtab shiftwidth=2 diff -r 138ddb918cf2 -r 405eb83f7eed dstest_host_client.cc --- a/dstest_host_client.cc Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - * Test dataspace operations. - * - * Copyright (C) 2020, 2021 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 -#include -#include - -#include "file.h" -#include "memory_utils.h" - - - -int main(int argc, char *argv[]) -{ - if (argc < 4) - { - printf("Need filename, step and sample size.\n"); - return 1; - } - - /* Obtain filename and access parameters. */ - - char *filename = argv[1]; - unsigned long step = atoi(argv[2]); - unsigned long sample = atoi(argv[3]); - - /* Allocate a buffer for sampling from the file. */ - - char buf[sample + 1]; - - /* Obtain access to the filesystem. */ - - l4_cap_idx_t server = l4re_env_get_cap("server"); - - /* Invoke the open method to receive the file reference. */ - - file_t file; - long err = file_open(&file, filename, server); - - if (err) - { - printf("Could not obtain file: %s\n", l4sys_errtostr(err)); - return 1; - } - - /* A region of the file is mapped. */ - - err = file_mmap(&file, 0, page(10)); - - if (err) - { - printf("Could not map file region: %s\n", l4sys_errtostr(err)); - return 1; - } - - for (unsigned long offset = 0; offset < file_populated_span(&file); offset += step) - { - unsigned long remaining = file_populated_span(&file) - offset; - unsigned long sample_remaining = remaining < sample ? remaining : sample; - - printf("%ld bytes from %p...\n", sample_remaining, (file.memory + offset)); - strncpy(buf, (file.memory + offset), sample_remaining); - buf[sample_remaining] = '\0'; - printf("%s\n", buf); - } - - printf("File shown.\n"); - - return 0; -} - -// vim: tabstop=2 expandtab shiftwidth=2 diff -r 138ddb918cf2 -r 405eb83f7eed dstest_host_server.cc --- a/dstest_host_server.cc Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Test dataspace operations. - * - * Copyright (C) 2020, 2021 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 -#include -#include - -#include "memory_incremental.h" -#include "memory_utils.h" -#include "page_queue_shared.h" -#include "pages.h" -#include "resource_server.h" -#include "host_file_opener.h" - - - -const unsigned int MEMORY_PAGES = 10; - -int main(void) -{ - /* Some memory plus infrastructure. */ - - MemoryIncremental mem(MEMORY_PAGES); - PageQueueShared queue; - Pages pages(&mem, &queue); - HostFileOpener opener(&pages); - - /* Register a server associating it with the given object. */ - - ResourceServer server(&opener); - long err = server.bind("server"); - - if (err) - { - printf("Could not bind server: %s\n", l4sys_errtostr(err)); - return 1; - } - - printf("Starting server...\n"); - server.start(); - return 0; -} diff -r 138ddb918cf2 -r 405eb83f7eed dstest_pipe_client.cc --- a/dstest_pipe_client.cc Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,121 +0,0 @@ -/* - * Test pipe operations. - * - * Copyright (C) 2020, 2021 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 -#include -#include - -#include "file.h" -#include "memory_utils.h" - - - -static void show(file_t *file, offset_t step, offset_t sample) -{ - /* Allocate a buffer for sampling from the file. */ - - char buf[sample + 1]; - - for (offset_t offset = 0; offset < file_populated_span(file); offset += step) - { - printf("show %ld of %ld...\n", offset, file_populated_span(file)); - - unsigned long remaining = file_populated_span(file) - offset; - unsigned long sample_remaining = remaining < sample ? remaining : sample; - - printf("%ld bytes from %p...\n", sample_remaining, (file->memory + offset)); - strncpy(buf, (file->memory + offset), sample_remaining); - buf[sample_remaining] = '\0'; - printf("%s\n", buf); - } -} - - - -const unsigned int PIPE_PAGES = 2; - -int main(void) -{ - /* Obtain access to the filesystem. */ - - l4_cap_idx_t server = l4re_env_get_cap("server"); - - /* Invoke the open method to receive the file reference. */ - - file_t reader, writer; - long err = pipe_open(page(PIPE_PAGES), &reader, &writer, server); - - if (err) - { - printf("Could not obtain pipe: %s\n", l4sys_errtostr(err)); - return 1; - } - - /* Use the writer to fill the pipe with data. */ - - for (int region = 0; region < 3; region++) - { - printf("Write %ld to pipe at %p...\n", file_span(&writer), writer.memory); - - memset(writer.memory, (int) 'a' + region, file_span(&writer)); - - err = pipe_written(&writer, file_span(&writer)); - - if (err) - { - printf("Written data error: %s\n", l4sys_errtostr(err)); - return 1; - } - - show(&writer, page(1), 60); - - err = pipe_next(&writer); - - if (err) - { - printf("Region traversal error at region %d: %s\n", region, l4sys_errtostr(err)); - break; - } - } - - /* Use the reader to obtain data from the pipe. */ - - err = pipe_current(&reader); - - while (!err) - { - printf("show...\n"); - show(&reader, page(1), 60); - err = pipe_next(&reader); - } - - if (err) - printf("Reading termination condition: %s\n", l4sys_errtostr(err)); - - printf("Data shown.\n"); - - return 0; -} - -// vim: tabstop=2 expandtab shiftwidth=2 diff -r 138ddb918cf2 -r 405eb83f7eed dstest_pipe_server.cc --- a/dstest_pipe_server.cc Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - * Test pipe operations. - * - * Copyright (C) 2020, 2021 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 "memory_incremental.h" -#include "pipe_opener_resource.h" -#include "resource_server.h" - - - -const unsigned int MEMORY_PAGES = 20; - -int main(void) -{ - /* Some memory plus infrastructure. */ - - MemoryIncremental mem(MEMORY_PAGES); - PipeOpenerResource opener(&mem); - - /* Register a server associating it with the given object. */ - - ResourceServer server(&opener); - long err = server.bind("server"); - - if (err) - { - printf("Could not bind server: %s\n", l4sys_errtostr(err)); - return 1; - } - - printf("Starting server...\n"); - server.start(); - return 0; -} - -// vim: tabstop=2 expandtab shiftwidth=2 diff -r 138ddb918cf2 -r 405eb83f7eed dstest_test_client.cc --- a/dstest_test_client.cc Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,242 +0,0 @@ -/* - * Test dataspace operations. - * - * Copyright (C) 2020, 2021 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 -#include -#include -#include - -#include -#include - -#include - -#include "file.h" -#include "memory_utils.h" - - - -/* Test parameters affected by capability limits. */ - -const unsigned long NUMBER_OF_FILES = 10; -const unsigned int START_LIMIT = 10; -const unsigned int ACTIVITY_ITERATIONS = 20; - -/* Test parameters unaffected by any capability limits. */ - -const unsigned int MAP_PAGES = 20; -const unsigned int REGION_ITERATIONS = 20; - - - -/* An activity opening and reading from a file. */ - -static long activity(file_t *context, unsigned long fileid, unsigned int start_page) -{ - unsigned long step = page(1); - unsigned long sample = page(1); - - /* Allocate a buffer for sampling from the file. */ - - char buf[sample + 1]; - - /* Invoke the open method to receive the file reference. */ - - file_t file; - - long err = file_context_open(&file, context); - - if (err) - { - printf("Could not obtain file for %ld @ page %d: %s\n", fileid, start_page, l4sys_errtostr(err)); - return err; - } - - /* A region of the file is mapped. */ - - err = file_mmap(&file, page(start_page), page(MAP_PAGES)); - - if (err) - { - printf("Could not map file region for %ld @ page %d: %s\n", fileid, start_page, l4sys_errtostr(err)); - file_close(&file); - return err; - } - - /* Read the region a number of times. */ - - for (unsigned int read_counter = 0; read_counter < REGION_ITERATIONS; read_counter++) - { - for (unsigned long offset = 0; offset < file_populated_span(&file); offset += step) - { - unsigned long remaining = file_populated_span(&file) - offset; - unsigned long sample_remaining = remaining < sample ? remaining : sample; - - strncpy(buf, (file.memory + offset), sample_remaining); - buf[sample_remaining] = '\0'; - - /* Test the data obtained. */ - - unsigned long filepos = file.start_pos + offset; - unsigned long _fileid = 0, _filepos = 0; - char *sep = strchr(buf, ':'); - - if (sep != NULL) - { - *sep = '\0'; sep++; - _fileid = atol(buf); _filepos = atol(sep); - } - - if ((fileid != _fileid) || (filepos != _filepos)) - printf("! %ld:%ld is not %ld:%ld\n", _fileid, _filepos, fileid, filepos); - } - } - - file_close(&file); - - return L4_EOK; -} - - - -static long activity_iterate(file_t *context, unsigned long fileid, unsigned int start_page) -{ - long err; - - /* Open the file, read pages, close the file, over and over. */ - - for (unsigned int iteration = 0; iteration < ACTIVITY_ITERATIONS; iteration++) - { - err = activity(context, fileid, start_page); - if (err) - break; - } - - return err; -} - - - -static long context_for_file(unsigned long fileid, file_t *file, l4_cap_idx_t server) -{ - long err = file_context(file, server); - - if (err) - { - printf("Could not obtain context: %s\n", l4sys_errtostr(err)); - file_close(file); - return err; - } - - /* Write the filename. */ - - sprintf(file->memory, "%ld", fileid); - - return L4_EOK; -} - - - -int main(void) -{ - long err; - - /* Introduce concurrency control. */ - - err = ipc_thread_init(); - - if (err) - { - printf("Initialisation error: %s\n", l4sys_errtostr(err)); - return 1; - } - - /* Retain activity and context details. */ - - std::thread *activities[NUMBER_OF_FILES * START_LIMIT]; - file_t contexts[NUMBER_OF_FILES]; - - /* Obtain access to the filesystem. */ - - l4_cap_idx_t server = l4re_env_get_cap("server"); - - /* Obtain opener contexts for the files. */ - - unsigned long fileid; - - for (fileid = 0; fileid < NUMBER_OF_FILES; fileid++) - { - err = context_for_file(fileid, &contexts[fileid], server); - - if (err) - { - printf("Context allocation failed.\n"); - return 1; - } - } - - /* Start threads accessing all the files. */ - - printf("Starting threads...\n"); - - time_t t = time(NULL); - int current = 0; - unsigned long errors = 0; - - for (fileid = 0; fileid < NUMBER_OF_FILES; fileid++) - { - for (unsigned int start_page = 0; start_page < START_LIMIT; start_page++) - { - try - { - activities[current++] = new std::thread(activity_iterate, &contexts[fileid], fileid, start_page); - } - catch (const std::system_error &exc) - { - errors++; - } - } - } - - /* Wait for the threads. */ - - int limit = current; - - printf("Waiting for %d threads...\n", limit); - - for (current = 0; current < limit; current++) - activities[current]->join(); - - /* Discard the contexts. */ - - for (fileid = 0; fileid < NUMBER_OF_FILES; fileid++) - file_close(&contexts[fileid]); - - t = time(NULL) - t; - printf("Activities completed in %ld seconds (with %ld threads not started).\n", t, errors); - - return 0; -} - -// vim: tabstop=2 expandtab shiftwidth=2 diff -r 138ddb918cf2 -r 405eb83f7eed dstest_test_server.cc --- a/dstest_test_server.cc Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * Test dataspace operations. - * - * Copyright (C) 2020, 2021 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 - -#include -#include -#include - -#include "memory_incremental.h" -#include "memory_utils.h" -#include "page_queue_shared.h" -#include "pages.h" -#include "resource_server.h" -#include "test_file_opener.h" - - - -const unsigned int REGION_PAGES = 8; -const unsigned int MEMORY_PAGES = REGION_PAGES * 10; -const unsigned int FILE_PAGES = 20; - -int main(int argc, char *argv[]) -{ - long err; - - /* Introduce concurrency control. */ - - err = ipc_thread_init(); - - if (err) - { - printf("Initialisation error: %s\n", l4sys_errtostr(err)); - return 1; - } - - /* Configure the number of available pages using any argument. */ - - unsigned int memory_pages = MEMORY_PAGES; - - if (argc > 1) - memory_pages = atoi(argv[1]) * REGION_PAGES; - - /* Some memory plus infrastructure. */ - - MemoryIncremental mem(memory_pages, page(REGION_PAGES)); - PageQueueShared queue; - Pages pages(&mem, &queue); - TestFileOpener opener(&pages, page(FILE_PAGES)); - - /* Register a server associating it with the given object. */ - - ResourceServer server(&opener); - err = server.bind("server"); - - if (err) - { - printf("Could not bind server: %s\n", l4sys_errtostr(err)); - return 1; - } - - printf("Starting server...\n"); - server.start(); - return 0; -} - -// vim: tabstop=2 expandtab shiftwidth=2 diff -r 138ddb918cf2 -r 405eb83f7eed files/file_pager.cc --- a/files/file_pager.cc Thu Apr 01 00:39:16 2021 +0200 +++ b/files/file_pager.cc Thu Apr 01 00:57:43 2021 +0200 @@ -5,7 +5,7 @@ mapper for moderating access to loaded pages. */ FilePager::FilePager(fileid_t fileid, PageMapper *mapper, flags_t flags, - Paging *paging) + FilePaging *paging) : Pager(mapper, flags), _paging(paging), fileid(fileid) { } diff -r 138ddb918cf2 -r 405eb83f7eed files/file_pager.h --- a/files/file_pager.h Thu Apr 01 00:39:16 2021 +0200 +++ b/files/file_pager.h Thu Apr 01 00:57:43 2021 +0200 @@ -2,20 +2,20 @@ #include "mapped_file_object_interface.h" #include "pager.h" -#include "paging.h" +#include "file_paging.h" /* A pager abstraction for a file. */ class FilePager : public Pager, public MappedFileObject { protected: - Paging *_paging; + FilePaging *_paging; public: fileid_t fileid; explicit FilePager(fileid_t fileid, PageMapper *mapper, flags_t flags, - Paging *paging); + FilePaging *paging); virtual void close(); diff -r 138ddb918cf2 -r 405eb83f7eed files/file_paging.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/files/file_paging.cc Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,88 @@ +#include "file_pager.h" +#include "file_paging.h" + + + +FilePaging::FilePaging(Pages *pages) +: _pages(pages) +{ +} + +/* Return any registered page mapper for the given 'fileid' or NULL if no such + mapper is registered. */ + +PageMapper *FilePaging::get(fileid_t fileid) +{ + FileMapping::iterator entry = _mappers.find(fileid); + PageMapper *mapper; + + if (entry == _mappers.end()) + mapper = NULL; + else + mapper = entry->second; + + return mapper; +} + +/* Register a page 'mapper' for the given 'fileid'. */ + +void FilePaging::set(fileid_t fileid, PageMapper *mapper) +{ + FileMapping::iterator entry = _mappers.find(fileid); + + if (entry == _mappers.end()) + _mappers[fileid] = mapper; +} + +/* Obtain a page mapper for the 'fileid' or register a new one in the + paging object. */ + +PageMapper *FilePaging::get_mapper(fileid_t fileid) +{ + /* Obtain any registered page mapper. */ + + PageMapper *mapper = get(fileid); + + if (mapper != NULL) + return mapper; + + /* Make an accessor and page mapper, registering the mapper. */ + + Accessor *accessor = make_accessor(fileid); + mapper = new PageMapper(accessor, _pages); + + set(fileid, mapper); + + return mapper; +} + + + +/* Return a pager initialised with a page mapper. */ + +Pager *FilePaging::get_pager(fileid_t fileid, flags_t flags) +{ + std::lock_guard guard(_lock); + + /* Initialise the pager with the mapper and a reference to this object for + closing the mapper and accessor. */ + + PageMapper *mapper = get_mapper(fileid); + return new FilePager(fileid, mapper, flags, this); +} + +/* Detach a pager, potentially removing its resources. */ + +void FilePaging::detach_pager(fileid_t fileid, PageMapper *mapper) +{ + std::lock_guard guard(_lock); + + if (!mapper->detach()) + { + _mappers.erase(fileid); + delete mapper->accessor(); + delete mapper; + } +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed files/file_paging.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/files/file_paging.h Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,59 @@ +#pragma once + +#include +#include + +#include "accessor.h" +#include "pager.h" +#include "page_mapper.h" + + + +/* Mapping type from accessors to page mappers. */ + +typedef std::map FileMapping; +typedef std::pair FileMappingEntry; + + + +/* A registry of mappers for accessors. */ + +class FilePaging +{ +protected: + Pages *_pages; + + FileMapping _mappers; + std::mutex _lock; + + /* Pager initialisation methods. */ + + PageMapper *get_mapper(fileid_t fileid); + + Pager *get_pager(fileid_t fileid, flags_t flags); + + /* Configurable methods. */ + + virtual fileid_t get_fileid(const char *path) = 0; + + virtual Accessor *make_accessor(fileid_t fileid) = 0; + + /* Mapper registry access. */ + + PageMapper *get(fileid_t fileid); + + void set(fileid_t fileid, PageMapper *mapper); + +public: + explicit FilePaging(Pages *pages); + + virtual ~FilePaging() + { + } + + /* Methods for the pager. */ + + void detach_pager(fileid_t fileid, PageMapper *mapper); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed files/opener_resource.cc --- a/files/opener_resource.cc Thu Apr 01 00:39:16 2021 +0200 +++ b/files/opener_resource.cc Thu Apr 01 00:57:43 2021 +0200 @@ -5,7 +5,7 @@ /* Support for providing access to files. */ OpenerResource::OpenerResource(Pages *pages) -: Paging(pages) +: FilePaging(pages) { } diff -r 138ddb918cf2 -r 405eb83f7eed files/opener_resource.h --- a/files/opener_resource.h Thu Apr 01 00:39:16 2021 +0200 +++ b/files/opener_resource.h Thu Apr 01 00:57:43 2021 +0200 @@ -2,15 +2,15 @@ #include +#include "file_paging.h" #include "opener_context_resource.h" #include "opener_interface.h" -#include "paging.h" #include "pages.h" #include "resource.h" /* Support for providing access to files. */ -class OpenerResource : public Resource, public Paging, public Opener +class OpenerResource : public Resource, public FilePaging, public Opener { public: explicit OpenerResource(Pages *pages); diff -r 138ddb918cf2 -r 405eb83f7eed flexpage.cc --- a/flexpage.cc Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ -#include - -#include "flexpage.h" - - - -/* Reset the flexpage using 'offset', being the file offset. */ - -void Flexpage::reset(offset_t offset) -{ - _counter = 0; - - /* By definition (see "Flexible-Sized Page Objects - Object-Orientation - in Operation Systems"), flexpages are aligned to multiples of their - size. - - The size of the flexpage depends on the amount of space around the - accessed page. It cannot exceed the size of the memory region. */ - - size = max_multiple(region->start, region->end, PAGE_SIZE); - - /* The base address of the flexpage is computed from the region start - and flexpage size. It will be no lower than the region start. - - Sent flexpages may use higher bases due to receive window constraints, - these being communicated by the "hot spot". */ - - base_addr = round(region->start, size); - - /* Get the file offset for the base of the flexpage. This will be a - multiple of the flexpage size for alignment purposes. */ - - base_offset = trunc(offset, size); - - /* The page being accessed is relative to the base. - (This is transient information recording the initialising access - details.) */ - - page_offset = trunc(offset - base_offset, PAGE_SIZE); - page_addr = base_addr + page_offset; -} - -bool Flexpage::decrement() -{ - if (_counter) - { - _counter--; - return _counter == 0; - } - else - return 0; -} - -void Flexpage::increment() -{ - _counter++; -} - -void Flexpage::invalidate() -{ - _counter = 0; -} - -bool Flexpage::valid() -{ - return _counter != 0; -} - -/* Return whether the flexpage supports the given file 'position'. */ - -bool Flexpage::supports_position(offset_t position) -{ - return (base_offset <= position) && (position < (base_offset + size)); -} - -void Flexpage::upgrade(flags_t flags) -{ - if (flags && (flags != _flags)) - _flags |= flags; -} - -/* Return a "send" flexpage for an access to 'offset' by positioning it relative - to 'hot_spot' for the receive flexpage window. */ - -SendFlexpage Flexpage::to_send(offset_t offset, offset_t hot_spot, offset_t max_offset) -{ - /* The dataspace offset of the flexpage base is a multiple of the flexpage - size. */ - - offset_t receive_base_offset = trunc(offset, size); - - /* The offset of the accessed page within the flexpage is constrained by the - current flexpage size. */ - - offset_t page_offset = trunc(offset - receive_base_offset, PAGE_SIZE); - - /* The receive flexpage offset (hot spot) must be constrained to the - flexpage, both the size and the start. */ - - offset_t receive_size; - - if (max_offset) - { - receive_size = trunc_multiple(max_offset - receive_base_offset, PAGE_SIZE); - receive_size = std::min(size, receive_size); - } - else - receive_size = size; - - if (!receive_size) - return SendFlexpage(base_addr, page_order(0), _flags); - - offset_t receive_page_offset = hot_spot % receive_size; - - while ((receive_size > PAGE_SIZE) && (receive_page_offset != page_offset)) - { - receive_size /= 2; - receive_page_offset = hot_spot % receive_size; - } - - /* The flexpage base address is adjusted using the difference in page - offsets. Where the receive flexpage offset is constained further, the - base address will be raised to become closer to the accessed page. */ - - offset_t adjustment = page_offset - receive_page_offset; - - return SendFlexpage(base_addr + adjustment, page_order(receive_size), _flags); -} - -/* Return a representation of the flexpage for unmapping. */ - -SendFlexpage Flexpage::to_unmap() -{ - return SendFlexpage(base_addr, page_order(size), _flags); -} - -// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed flexpage.h --- a/flexpage.h Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -#pragma once - -#include "memory_utils.h" -#include "region.h" -#include "send_flexpage.h" - - - -/* A flexpage abstraction. */ - -class Flexpage -{ -protected: - unsigned int _counter; - flags_t _flags; - -public: - Region *region; - - /* General flexpage characteristics. */ - - offset_t base_addr, size; - offset_t base_offset; - - /* Transient debugging information. */ - - offset_t page_addr, page_offset; - - /* Associate a flexpage with a memory 'region'. */ - - explicit Flexpage(Region *region) : region(region) - { - } - - void reset(offset_t offset); - - bool decrement(); - - void increment(); - - void invalidate(); - - bool valid(); - - bool supports_position(offset_t position); - - void upgrade(flags_t flags); - - SendFlexpage to_send(offset_t offset, offset_t hot_spot, offset_t max_offset=0); - - SendFlexpage to_unmap(); -}; - -// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed mapping/access_map.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mapping/access_map.cc Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,134 @@ +#include "access_map.h" + +/* Return the flexpage supporting 'position'. */ + +Flexpage *AccessMap::find(offset_t position) +{ + std::lock_guard guard(_lock); + + _AccessMap::iterator it = _flexpages.upper_bound(position); + + if ((_flexpages.size() > 0) && (it != _flexpages.begin())) + { + it--; + + if (it->second->supports_position(position)) + return it->second; + } + + return NULL; +} + +/* Insert a mapping for 'flexpage'. */ + +void AccessMap::insert(Flexpage *flexpage) +{ + std::lock_guard guard(_lock); + + _flexpages.insert(_AccessMapEntry(flexpage->base_offset, flexpage)); +} + +/* Remove the mapping supported by 'flexpage'. + + The flexpage may have obtained by another mapper before being purged from + this object's mapping and before being purged from the queue (and thus + disassociated from this mapper), leaving an opportunity for another mapper to + now be removing it here. In such a situation, flushing has already occurred + and will not be performed again. */ + +bool AccessMap::remove(PageOwner *owner, Flexpage *flexpage) +{ + std::lock_guard guard(_lock); + + _AccessMap::iterator it = _flexpages.find(flexpage->base_offset); + + if (it != _flexpages.end()) + { + owner->flush(flexpage, true); + _flexpages.erase(flexpage->base_offset); + return true; + } + + return false; +} + +/* Purge all flexpages, using the 'owner' to flush their contents and + 'pages' to make the flexpages available to other accessors. */ + +void AccessMap::purge(PageOwner *owner, Pages *pages) +{ + std::lock_guard guard(_lock); + + _AccessMap::iterator it = _flexpages.begin(), entry; + + while (it != _flexpages.end()) + { + entry = it; + it++; + + Flexpage *flexpage = entry->second; + + /* Some flexpages may be unavailable in the queue. Only those + that can be reserved should be flushed and made available + again. */ + + if (pages->reserve(owner, flexpage)) + { + owner->flush(flexpage, true); + pages->release(flexpage); + _flexpages.erase(entry); + } + } +} + +/* Flush flexpages in the given range from 'start' with 'size', using 'owner' + and 'pages'. */ + +void AccessMap::flush_all(offset_t start, offset_t size, PageOwner *owner, Pages *pages) +{ + offset_t end = start + size; + + std::lock_guard guard(_lock); + + /* The start may be within an existing flexpage where the flexpage size is a + page multiple. */ + + _AccessMap::iterator it = _flexpages.upper_bound(start), entry; + + if ((_flexpages.size() > 0) && (it != _flexpages.begin())) + it--; + + /* Inspect flexpages at or after start until end. */ + + while (it != _flexpages.end()) + { + entry = it; + it++; + + Flexpage *flexpage = entry->second; + + if (flexpage->base_offset >= end) + break; + + /* Attempt to flush each flexpage, releasing ones that are no longer + needed. */ + + if (pages->reserve(owner, flexpage)) + { + owner->flush(flexpage, false); + + /* Where no users of the flexpage persist, release the flexpage for + reuse and remove this entry. */ + + if (!flexpage->valid()) + { + pages->release(flexpage); + _flexpages.erase(entry); + } + else + pages->queue(owner, flexpage); + } + } +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed mapping/access_map.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mapping/access_map.h Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,35 @@ +#pragma once + +#include "flexpage.h" +#include "page_owner.h" +#include "pages.h" + +#include +#include + +/* Collection types. */ + +typedef std::map _AccessMap; +typedef std::pair _AccessMapEntry; + +/* A mapping from file positions to flexpages. */ + +class AccessMap +{ +protected: + _AccessMap _flexpages; + std::mutex _lock; + +public: + Flexpage *find(offset_t position); + + void insert(Flexpage *flexpage); + + bool remove(PageOwner *owner, Flexpage *flexpage); + + void purge(PageOwner *owner, Pages *pages); + + void flush_all(offset_t start, offset_t size, PageOwner *owner, Pages *pages); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed mapping/flexpage.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mapping/flexpage.cc Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,137 @@ +#include + +#include "flexpage.h" + + + +/* Reset the flexpage using 'offset', being the file offset. */ + +void Flexpage::reset(offset_t offset) +{ + _counter = 0; + + /* By definition (see "Flexible-Sized Page Objects - Object-Orientation + in Operation Systems"), flexpages are aligned to multiples of their + size. + + The size of the flexpage depends on the amount of space around the + accessed page. It cannot exceed the size of the memory region. */ + + size = max_multiple(region->start, region->end, PAGE_SIZE); + + /* The base address of the flexpage is computed from the region start + and flexpage size. It will be no lower than the region start. + + Sent flexpages may use higher bases due to receive window constraints, + these being communicated by the "hot spot". */ + + base_addr = round(region->start, size); + + /* Get the file offset for the base of the flexpage. This will be a + multiple of the flexpage size for alignment purposes. */ + + base_offset = trunc(offset, size); + + /* The page being accessed is relative to the base. + (This is transient information recording the initialising access + details.) */ + + page_offset = trunc(offset - base_offset, PAGE_SIZE); + page_addr = base_addr + page_offset; +} + +bool Flexpage::decrement() +{ + if (_counter) + { + _counter--; + return _counter == 0; + } + else + return 0; +} + +void Flexpage::increment() +{ + _counter++; +} + +void Flexpage::invalidate() +{ + _counter = 0; +} + +bool Flexpage::valid() +{ + return _counter != 0; +} + +/* Return whether the flexpage supports the given file 'position'. */ + +bool Flexpage::supports_position(offset_t position) +{ + return (base_offset <= position) && (position < (base_offset + size)); +} + +void Flexpage::upgrade(flags_t flags) +{ + if (flags && (flags != _flags)) + _flags |= flags; +} + +/* Return a "send" flexpage for an access to 'offset' by positioning it relative + to 'hot_spot' for the receive flexpage window. */ + +SendFlexpage Flexpage::to_send(offset_t offset, offset_t hot_spot, offset_t max_offset) +{ + /* The dataspace offset of the flexpage base is a multiple of the flexpage + size. */ + + offset_t receive_base_offset = trunc(offset, size); + + /* The offset of the accessed page within the flexpage is constrained by the + current flexpage size. */ + + offset_t page_offset = trunc(offset - receive_base_offset, PAGE_SIZE); + + /* The receive flexpage offset (hot spot) must be constrained to the + flexpage, both the size and the start. */ + + offset_t receive_size; + + if (max_offset) + { + receive_size = trunc_multiple(max_offset - receive_base_offset, PAGE_SIZE); + receive_size = std::min(size, receive_size); + } + else + receive_size = size; + + if (!receive_size) + return SendFlexpage(base_addr, page_order(0), _flags); + + offset_t receive_page_offset = hot_spot % receive_size; + + while ((receive_size > PAGE_SIZE) && (receive_page_offset != page_offset)) + { + receive_size /= 2; + receive_page_offset = hot_spot % receive_size; + } + + /* The flexpage base address is adjusted using the difference in page + offsets. Where the receive flexpage offset is constained further, the + base address will be raised to become closer to the accessed page. */ + + offset_t adjustment = page_offset - receive_page_offset; + + return SendFlexpage(base_addr + adjustment, page_order(receive_size), _flags); +} + +/* Return a representation of the flexpage for unmapping. */ + +SendFlexpage Flexpage::to_unmap() +{ + return SendFlexpage(base_addr, page_order(size), _flags); +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed mapping/flexpage.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mapping/flexpage.h Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,54 @@ +#pragma once + +#include "memory_utils.h" +#include "region.h" +#include "send_flexpage.h" + + + +/* A flexpage abstraction. */ + +class Flexpage +{ +protected: + unsigned int _counter; + flags_t _flags; + +public: + Region *region; + + /* General flexpage characteristics. */ + + offset_t base_addr, size; + offset_t base_offset; + + /* Transient debugging information. */ + + offset_t page_addr, page_offset; + + /* Associate a flexpage with a memory 'region'. */ + + explicit Flexpage(Region *region) : region(region) + { + } + + void reset(offset_t offset); + + bool decrement(); + + void increment(); + + void invalidate(); + + bool valid(); + + bool supports_position(offset_t position); + + void upgrade(flags_t flags); + + SendFlexpage to_send(offset_t offset, offset_t hot_spot, offset_t max_offset=0); + + SendFlexpage to_unmap(); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed mapping/page_mapper.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mapping/page_mapper.cc Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,175 @@ +#include "ipc.h" +#include "page_mapper.h" + + + +PageMapper::PageMapper(Accessor *accessor, Pages *pages) +: _accessor(accessor), _pages(pages), _attached(0) +{ +} + +/* Accounting methods. */ + +/* Attach a pager, opening the accessor if required. */ + +void PageMapper::attach() +{ + std::lock_guard guard(_lock); + + if (!_attached) + _accessor->open(); + + _attached += 1; +} + +/* Detach a pager, purging active pages and closing the accessor if no more + pagers are attached. Return whether any pagers are still attached. */ + +unsigned int PageMapper::detach() +{ + std::lock_guard guard(_lock); + + if (_attached) + { + _attached -= 1; + + if (!_attached) + { + _map.purge(this, _pages); + _accessor->close(); + } + } + + return _attached; +} + +/* Interface for the pager. */ + +/* Return a flexpage providing access to the indicated file 'offset'. + + The returned flexpage will either be an existing, compatible flexpage or a + completely new flexpage. + + This method locks the mapper to prevent concurrent queries with the same + details, with the lock held until the queue operation releases the lock. */ + +Flexpage *PageMapper::get(offset_t offset, flags_t flags) +{ + _lock.lock(); + + Flexpage *f = find(offset); + + if (f == NULL) + f = flexpage(offset); + + /* Record a new user of the flexpage and upgrade the access flags. */ + + f->increment(); + f->upgrade(flags); + return f; +} + +/* Queue the given 'flexpage' in the page collection, making it available for + eventual reuse. + + This method unlocks the mapper. */ + +void PageMapper::queue(Flexpage *flexpage) +{ + _pages->queue(this, flexpage); + + _lock.unlock(); +} + +/* Flush pages in the given range from 'start' with 'size'. */ + +void PageMapper::flush_all(offset_t start, offset_t size) +{ + std::lock_guard guard(_lock); + + _map.flush_all(start, size, this, _pages); +} + +/* Return the maximum extent of the mapped resource. */ + +offset_t PageMapper::get_data_size() +{ + return _accessor->get_size(); +} + +/* Set the maximum extent of the mapped resource. */ + +void PageMapper::set_data_size(offset_t size) +{ + _accessor->set_size(size); +} + +/* Internal flexpage retrieval methods. */ + +/* Find an existing flexpage for 'offset'. Where the accessor has registered a + compatible flexpage, an attempt is made to reserve it in the page collection; + if this succeeds, the flexpage is returned. Otherwise, NULL is returned. */ + +Flexpage *PageMapper::find(offset_t offset) +{ + Flexpage *flexpage = _map.find(offset); + + /* Between finding and reserving a flexpage, there is a possibility that + another accessor might acquire the flexpage, issue it, and even purge + it. */ + + if ((flexpage != NULL) && _pages->reserve(this, flexpage)) + return flexpage; + else + return NULL; +} + +/* Obtain a new flexpage for the file 'offset'. If the page collection is unable + to obtain a completely new flexpage, an existing flexpage is requested from + the page collection and recycled. + + The obtained flexpage is filled with content. */ + +Flexpage *PageMapper::flexpage(offset_t offset) +{ + Flexpage *flexpage = _pages->flexpage(); + + /* Obtain an existing flexpage and reuse it. */ + + if (flexpage == NULL) + flexpage = _pages->remove(); + + flexpage->reset(offset); + + fill(flexpage); + _map.insert(flexpage); + return flexpage; +} + +/* Interface for the page collection. */ + +/* Remove the record of 'flexpage' in this accessor, flushing its content. */ + +void PageMapper::remove(Flexpage *flexpage) +{ + _map.remove(this, flexpage); +} + +/* Data transfer methods. */ + +void PageMapper::fill(Flexpage *flexpage) +{ + _accessor->fill(flexpage); +} + +void PageMapper::flush(Flexpage *flexpage, bool purge) +{ + if (flexpage->decrement() || purge) + { + _accessor->flush(flexpage); + ipc_unmap_flexpage(flexpage); + flexpage->invalidate(); + } +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed mapping/page_mapper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mapping/page_mapper.h Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,64 @@ +#pragma once + +#include "access_map.h" +#include "accessor.h" +#include "page_owner.h" + +#include + +/* A file mapper, associating flexpages with file regions. */ + +class PageMapper : public PageOwner +{ +protected: + AccessMap _map; + Accessor *_accessor; + Pages *_pages; + unsigned int _attached; + + /* Serialisation of accesses. */ + + std::mutex _lock; + + /* Internal flexpage retrieval methods. */ + + Flexpage *find(offset_t offset); + + Flexpage *flexpage(offset_t offset); + +public: + explicit PageMapper(Accessor *accessor, Pages *pages); + + /* Accounting methods. */ + + void attach(); + + unsigned int detach(); + + Accessor *accessor() + { return _accessor; } + + /* Interface for the pager. */ + + Flexpage *get(offset_t offset, 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); + + /* Data transfer methods, implementing PageOwner. */ + + void fill(Flexpage *flexpage); + + void flush(Flexpage *flexpage, bool purge); + + /* Interface for the page collection, implementing PageOwner. */ + + void remove(Flexpage *flexpage); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed mapping/page_owner.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mapping/page_owner.h Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,30 @@ +#pragma once + +#include "flexpage.h" + +/* The owner of a flexpage. */ + +class PageOwner +{ +public: + virtual ~PageOwner() + { + } + + virtual void fill(Flexpage *flexpage) + { + (void) flexpage; + } + + virtual void flush(Flexpage *flexpage, bool purge) + { + (void) flexpage; (void) purge; + } + + virtual void remove(Flexpage *flexpage) + { + (void) flexpage; + } +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed mapping/send_flexpage.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mapping/send_flexpage.h Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,21 @@ +#pragma once + +#include "types.h" + +/* A "send" flexpage abstraction. */ + +class SendFlexpage +{ +public: + offset_t base_addr; + unsigned int order; + flags_t flags; + + explicit SendFlexpage(offset_t base_addr, unsigned int order, + flags_t flags) + : base_addr(base_addr), order(order), flags(flags) + { + } +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed page_mapper.cc --- a/page_mapper.cc Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,175 +0,0 @@ -#include "ipc.h" -#include "page_mapper.h" - - - -PageMapper::PageMapper(Accessor *accessor, Pages *pages) -: _accessor(accessor), _pages(pages), _attached(0) -{ -} - -/* Accounting methods. */ - -/* Attach a pager, opening the accessor if required. */ - -void PageMapper::attach() -{ - std::lock_guard guard(_lock); - - if (!_attached) - _accessor->open(); - - _attached += 1; -} - -/* Detach a pager, purging active pages and closing the accessor if no more - pagers are attached. Return whether any pagers are still attached. */ - -unsigned int PageMapper::detach() -{ - std::lock_guard guard(_lock); - - if (_attached) - { - _attached -= 1; - - if (!_attached) - { - _map.purge(this, _pages); - _accessor->close(); - } - } - - return _attached; -} - -/* Interface for the pager. */ - -/* Return a flexpage providing access to the indicated file 'offset'. - - The returned flexpage will either be an existing, compatible flexpage or a - completely new flexpage. - - This method locks the mapper to prevent concurrent queries with the same - details, with the lock held until the queue operation releases the lock. */ - -Flexpage *PageMapper::get(offset_t offset, flags_t flags) -{ - _lock.lock(); - - Flexpage *f = find(offset); - - if (f == NULL) - f = flexpage(offset); - - /* Record a new user of the flexpage and upgrade the access flags. */ - - f->increment(); - f->upgrade(flags); - return f; -} - -/* Queue the given 'flexpage' in the page collection, making it available for - eventual reuse. - - This method unlocks the mapper. */ - -void PageMapper::queue(Flexpage *flexpage) -{ - _pages->queue(this, flexpage); - - _lock.unlock(); -} - -/* Flush pages in the given range from 'start' with 'size'. */ - -void PageMapper::flush_all(offset_t start, offset_t size) -{ - std::lock_guard guard(_lock); - - _map.flush_all(start, size, this, _pages); -} - -/* Return the maximum extent of the mapped resource. */ - -offset_t PageMapper::get_data_size() -{ - return _accessor->get_size(); -} - -/* Set the maximum extent of the mapped resource. */ - -void PageMapper::set_data_size(offset_t size) -{ - _accessor->set_size(size); -} - -/* Internal flexpage retrieval methods. */ - -/* Find an existing flexpage for 'offset'. Where the accessor has registered a - compatible flexpage, an attempt is made to reserve it in the page collection; - if this succeeds, the flexpage is returned. Otherwise, NULL is returned. */ - -Flexpage *PageMapper::find(offset_t offset) -{ - Flexpage *flexpage = _map.find(offset); - - /* Between finding and reserving a flexpage, there is a possibility that - another accessor might acquire the flexpage, issue it, and even purge - it. */ - - if ((flexpage != NULL) && _pages->reserve(this, flexpage)) - return flexpage; - else - return NULL; -} - -/* Obtain a new flexpage for the file 'offset'. If the page collection is unable - to obtain a completely new flexpage, an existing flexpage is requested from - the page collection and recycled. - - The obtained flexpage is filled with content. */ - -Flexpage *PageMapper::flexpage(offset_t offset) -{ - Flexpage *flexpage = _pages->flexpage(); - - /* Obtain an existing flexpage and reuse it. */ - - if (flexpage == NULL) - flexpage = _pages->remove(); - - flexpage->reset(offset); - - fill(flexpage); - _map.insert(flexpage); - return flexpage; -} - -/* Interface for the page collection. */ - -/* Remove the record of 'flexpage' in this accessor, flushing its content. */ - -void PageMapper::remove(Flexpage *flexpage) -{ - _map.remove(this, flexpage); -} - -/* Data transfer methods. */ - -void PageMapper::fill(Flexpage *flexpage) -{ - _accessor->fill(flexpage); -} - -void PageMapper::flush(Flexpage *flexpage, bool purge) -{ - if (flexpage->decrement() || purge) - { - _accessor->flush(flexpage); - ipc_unmap_flexpage(flexpage); - flexpage->invalidate(); - } -} - -// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed page_mapper.h --- a/page_mapper.h Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -#pragma once - -#include "access_map.h" -#include "accessor.h" -#include "page_owner.h" - -#include - -/* A file mapper, associating flexpages with file regions. */ - -class PageMapper : public PageOwner -{ -protected: - AccessMap _map; - Accessor *_accessor; - Pages *_pages; - unsigned int _attached; - - /* Serialisation of accesses. */ - - std::mutex _lock; - - /* Internal flexpage retrieval methods. */ - - Flexpage *find(offset_t offset); - - Flexpage *flexpage(offset_t offset); - -public: - explicit PageMapper(Accessor *accessor, Pages *pages); - - /* Accounting methods. */ - - void attach(); - - unsigned int detach(); - - Accessor *accessor() - { return _accessor; } - - /* Interface for the pager. */ - - Flexpage *get(offset_t offset, 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); - - /* Data transfer methods, implementing PageOwner. */ - - void fill(Flexpage *flexpage); - - void flush(Flexpage *flexpage, bool purge); - - /* Interface for the page collection, implementing PageOwner. */ - - void remove(Flexpage *flexpage); -}; - -// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed page_owner.h --- a/page_owner.h Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -#pragma once - -#include "flexpage.h" - -/* The owner of a flexpage. */ - -class PageOwner -{ -public: - virtual ~PageOwner() - { - } - - virtual void fill(Flexpage *flexpage) - { - (void) flexpage; - } - - virtual void flush(Flexpage *flexpage, bool purge) - { - (void) flexpage; (void) purge; - } - - virtual void remove(Flexpage *flexpage) - { - (void) flexpage; - } -}; - -// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed paging.cc --- a/paging.cc Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -#include "file_pager.h" -#include "paging.h" - - - -Paging::Paging(Pages *pages) -: _pages(pages) -{ -} - -/* Return any registered page mapper for the given 'fileid' or NULL if no such - mapper is registered. */ - -PageMapper *Paging::get(fileid_t fileid) -{ - FileMapping::iterator entry = _mappers.find(fileid); - PageMapper *mapper; - - if (entry == _mappers.end()) - mapper = NULL; - else - mapper = entry->second; - - return mapper; -} - -/* Register a page 'mapper' for the given 'fileid'. */ - -void Paging::set(fileid_t fileid, PageMapper *mapper) -{ - FileMapping::iterator entry = _mappers.find(fileid); - - if (entry == _mappers.end()) - _mappers[fileid] = mapper; -} - -/* Obtain a page mapper for the 'fileid' or register a new one in the - paging object. */ - -PageMapper *Paging::get_mapper(fileid_t fileid) -{ - /* Obtain any registered page mapper. */ - - PageMapper *mapper = get(fileid); - - if (mapper != NULL) - return mapper; - - /* Make an accessor and page mapper, registering the mapper. */ - - Accessor *accessor = make_accessor(fileid); - mapper = new PageMapper(accessor, _pages); - - set(fileid, mapper); - - return mapper; -} - - - -/* Return a pager initialised with a page mapper. */ - -Pager *Paging::get_pager(fileid_t fileid, flags_t flags) -{ - std::lock_guard guard(_lock); - - /* Initialise the pager with the mapper and a reference to this object for - closing the mapper and accessor. */ - - PageMapper *mapper = get_mapper(fileid); - return new FilePager(fileid, mapper, flags, this); -} - -/* Detach a pager, potentially removing its resources. */ - -void Paging::detach_pager(fileid_t fileid, PageMapper *mapper) -{ - std::lock_guard guard(_lock); - - if (!mapper->detach()) - { - _mappers.erase(fileid); - delete mapper->accessor(); - delete mapper; - } -} - -// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed paging.h --- a/paging.h Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -#pragma once - -#include -#include - -#include "accessor.h" -#include "pager.h" -#include "page_mapper.h" - - - -/* Mapping type from accessors to page mappers. */ - -typedef std::map FileMapping; -typedef std::pair FileMappingEntry; - - - -/* A registry of mappers for accessors. */ - -class Paging -{ -protected: - Pages *_pages; - - FileMapping _mappers; - std::mutex _lock; - - /* Pager initialisation methods. */ - - PageMapper *get_mapper(fileid_t fileid); - - Pager *get_pager(fileid_t fileid, flags_t flags); - - /* Configurable methods. */ - - virtual fileid_t get_fileid(const char *path) = 0; - - virtual Accessor *make_accessor(fileid_t fileid) = 0; - - /* Mapper registry access. */ - - PageMapper *get(fileid_t fileid); - - void set(fileid_t fileid, PageMapper *mapper); - -public: - explicit Paging(Pages *pages); - - virtual ~Paging() - { - } - - /* Methods for the pager. */ - - void detach_pager(fileid_t fileid, PageMapper *mapper); -}; - -// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed send_flexpage.h --- a/send_flexpage.h Thu Apr 01 00:39:16 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -#pragma once - -#include "types.h" - -/* A "send" flexpage abstraction. */ - -class SendFlexpage -{ -public: - offset_t base_addr; - unsigned int order; - flags_t flags; - - explicit SendFlexpage(offset_t base_addr, unsigned int order, - flags_t flags) - : base_addr(base_addr), order(order), flags(flags) - { - } -}; - -// vim: tabstop=4 expandtab shiftwidth=4 diff -r 138ddb918cf2 -r 405eb83f7eed tests/dstest_block_client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/dstest_block_client.cc Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,128 @@ +/* + * Test dataspace operations. + * + * Copyright (C) 2020, 2021 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 +#include +#include + +#include "file.h" +#include "memory_utils.h" + + + +static void show(file_t *file, unsigned long step, unsigned long sample) +{ + /* Allocate a buffer for sampling from the file. */ + + char buf[sample + 1]; + + for (unsigned long offset = 0; offset < file_populated_span(file); offset += step) + { + unsigned long remaining = file_populated_span(file) - offset; + unsigned long sample_remaining = remaining < sample ? remaining : sample; + + printf("%ld bytes from %p...\n", sample_remaining, (file->memory + offset)); + strncpy(buf, (file->memory + offset), sample_remaining); + buf[sample_remaining] = '\0'; + printf("%s\n", buf); + } +} + +int main(int argc, char *argv[]) +{ + if (argc < 4) + { + printf("Need filename, step and sample size.\n"); + return 1; + } + + /* Obtain filename and access parameters. */ + + char *filename = argv[1]; + unsigned long step = atoi(argv[2]); + unsigned long sample = atoi(argv[3]); + + /* Obtain access to the filesystem. */ + + l4_cap_idx_t server = l4re_env_get_cap("server"); + + /* Invoke the open method to receive the file reference. */ + + file_t file; + long err = file_open(&file, filename, server); + + if (err) + { + printf("Could not obtain file: %s\n", l4sys_errtostr(err)); + return 1; + } + + /* A region of the file is mapped. */ + + err = file_mmap(&file, 0, page(10)); + + if (err) + { + printf("Could not map file region: %s\n", l4sys_errtostr(err)); + return 1; + } + + show(&file, step, sample); + + /* Resizing must occur before writing beyond the end of file. Otherwise, the + data may get discarded if the supporting flexpage needs to be flushed. */ + + offset_t new_region = round(file_populated_span(&file), page(1)); + + printf("Resize to %ld...\n", new_region + file_populated_span(&file)); + + err = file_resize(&file, new_region + file_populated_span(&file)); + + if (err) + { + printf("Could not resize file: %s\n", l4sys_errtostr(err)); + return 1; + } + + printf("Resized file...\n"); + + /* Copy the sampled data to another file region. */ + + printf("Copy data to %ld...\n", new_region); + + for (unsigned long offset = 0; offset < file_populated_span(&file); offset += step) + { + memcpy(file.memory + new_region + offset, file.memory + offset, sample); + if (step > sample) + memset(file.memory + new_region + offset + sample, 0, step - sample); + } + + show(&file, step, sample); + + printf("File shown.\n"); + + return 0; +} + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 138ddb918cf2 -r 405eb83f7eed tests/dstest_block_server.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/dstest_block_server.cc Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,65 @@ +/* + * Test dataspace operations. + * + * Copyright (C) 2020, 2021 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 +#include +#include + +#include "memory_incremental.h" +#include "memory_utils.h" +#include "page_queue_shared.h" +#include "pages.h" +#include "resource_server.h" +#include "block_file_opener.h" + + + +const unsigned int MEMORY_PAGES = 10; + +int main(void) +{ + /* Some memory plus infrastructure. */ + + MemoryIncremental mem(MEMORY_PAGES); + PageQueueShared queue; + Pages pages(&mem, &queue); + BlockFileOpener opener(&pages); + + /* Register a server associating it with the given object. */ + + ResourceServer server(&opener); + long err = server.bind("server"); + + if (err) + { + printf("Could not bind server: %s\n", l4sys_errtostr(err)); + return 1; + } + + printf("Starting server...\n"); + server.start(); + return 0; +} + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 138ddb918cf2 -r 405eb83f7eed tests/dstest_host_client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/dstest_host_client.cc Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,93 @@ +/* + * Test dataspace operations. + * + * Copyright (C) 2020, 2021 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 +#include +#include + +#include "file.h" +#include "memory_utils.h" + + + +int main(int argc, char *argv[]) +{ + if (argc < 4) + { + printf("Need filename, step and sample size.\n"); + return 1; + } + + /* Obtain filename and access parameters. */ + + char *filename = argv[1]; + unsigned long step = atoi(argv[2]); + unsigned long sample = atoi(argv[3]); + + /* Allocate a buffer for sampling from the file. */ + + char buf[sample + 1]; + + /* Obtain access to the filesystem. */ + + l4_cap_idx_t server = l4re_env_get_cap("server"); + + /* Invoke the open method to receive the file reference. */ + + file_t file; + long err = file_open(&file, filename, server); + + if (err) + { + printf("Could not obtain file: %s\n", l4sys_errtostr(err)); + return 1; + } + + /* A region of the file is mapped. */ + + err = file_mmap(&file, 0, page(10)); + + if (err) + { + printf("Could not map file region: %s\n", l4sys_errtostr(err)); + return 1; + } + + for (unsigned long offset = 0; offset < file_populated_span(&file); offset += step) + { + unsigned long remaining = file_populated_span(&file) - offset; + unsigned long sample_remaining = remaining < sample ? remaining : sample; + + printf("%ld bytes from %p...\n", sample_remaining, (file.memory + offset)); + strncpy(buf, (file.memory + offset), sample_remaining); + buf[sample_remaining] = '\0'; + printf("%s\n", buf); + } + + printf("File shown.\n"); + + return 0; +} + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 138ddb918cf2 -r 405eb83f7eed tests/dstest_host_server.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/dstest_host_server.cc Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,63 @@ +/* + * Test dataspace operations. + * + * Copyright (C) 2020, 2021 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 +#include +#include + +#include "memory_incremental.h" +#include "memory_utils.h" +#include "page_queue_shared.h" +#include "pages.h" +#include "resource_server.h" +#include "host_file_opener.h" + + + +const unsigned int MEMORY_PAGES = 10; + +int main(void) +{ + /* Some memory plus infrastructure. */ + + MemoryIncremental mem(MEMORY_PAGES); + PageQueueShared queue; + Pages pages(&mem, &queue); + HostFileOpener opener(&pages); + + /* Register a server associating it with the given object. */ + + ResourceServer server(&opener); + long err = server.bind("server"); + + if (err) + { + printf("Could not bind server: %s\n", l4sys_errtostr(err)); + return 1; + } + + printf("Starting server...\n"); + server.start(); + return 0; +} diff -r 138ddb918cf2 -r 405eb83f7eed tests/dstest_pipe_client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/dstest_pipe_client.cc Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,121 @@ +/* + * Test pipe operations. + * + * Copyright (C) 2020, 2021 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 +#include +#include + +#include "file.h" +#include "memory_utils.h" + + + +static void show(file_t *file, offset_t step, offset_t sample) +{ + /* Allocate a buffer for sampling from the file. */ + + char buf[sample + 1]; + + for (offset_t offset = 0; offset < file_populated_span(file); offset += step) + { + printf("show %ld of %ld...\n", offset, file_populated_span(file)); + + unsigned long remaining = file_populated_span(file) - offset; + unsigned long sample_remaining = remaining < sample ? remaining : sample; + + printf("%ld bytes from %p...\n", sample_remaining, (file->memory + offset)); + strncpy(buf, (file->memory + offset), sample_remaining); + buf[sample_remaining] = '\0'; + printf("%s\n", buf); + } +} + + + +const unsigned int PIPE_PAGES = 2; + +int main(void) +{ + /* Obtain access to the filesystem. */ + + l4_cap_idx_t server = l4re_env_get_cap("server"); + + /* Invoke the open method to receive the file reference. */ + + file_t reader, writer; + long err = pipe_open(page(PIPE_PAGES), &reader, &writer, server); + + if (err) + { + printf("Could not obtain pipe: %s\n", l4sys_errtostr(err)); + return 1; + } + + /* Use the writer to fill the pipe with data. */ + + for (int region = 0; region < 3; region++) + { + printf("Write %ld to pipe at %p...\n", file_span(&writer), writer.memory); + + memset(writer.memory, (int) 'a' + region, file_span(&writer)); + + err = pipe_written(&writer, file_span(&writer)); + + if (err) + { + printf("Written data error: %s\n", l4sys_errtostr(err)); + return 1; + } + + show(&writer, page(1), 60); + + err = pipe_next(&writer); + + if (err) + { + printf("Region traversal error at region %d: %s\n", region, l4sys_errtostr(err)); + break; + } + } + + /* Use the reader to obtain data from the pipe. */ + + err = pipe_current(&reader); + + while (!err) + { + printf("show...\n"); + show(&reader, page(1), 60); + err = pipe_next(&reader); + } + + if (err) + printf("Reading termination condition: %s\n", l4sys_errtostr(err)); + + printf("Data shown.\n"); + + return 0; +} + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 138ddb918cf2 -r 405eb83f7eed tests/dstest_pipe_server.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/dstest_pipe_server.cc Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,57 @@ +/* + * Test pipe operations. + * + * Copyright (C) 2020, 2021 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 "memory_incremental.h" +#include "pipe_opener_resource.h" +#include "resource_server.h" + + + +const unsigned int MEMORY_PAGES = 20; + +int main(void) +{ + /* Some memory plus infrastructure. */ + + MemoryIncremental mem(MEMORY_PAGES); + PipeOpenerResource opener(&mem); + + /* Register a server associating it with the given object. */ + + ResourceServer server(&opener); + long err = server.bind("server"); + + if (err) + { + printf("Could not bind server: %s\n", l4sys_errtostr(err)); + return 1; + } + + printf("Starting server...\n"); + server.start(); + return 0; +} + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 138ddb918cf2 -r 405eb83f7eed tests/dstest_test_client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/dstest_test_client.cc Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,242 @@ +/* + * Test dataspace operations. + * + * Copyright (C) 2020, 2021 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 +#include +#include +#include + +#include +#include + +#include + +#include "file.h" +#include "memory_utils.h" + + + +/* Test parameters affected by capability limits. */ + +const unsigned long NUMBER_OF_FILES = 10; +const unsigned int START_LIMIT = 10; +const unsigned int ACTIVITY_ITERATIONS = 20; + +/* Test parameters unaffected by any capability limits. */ + +const unsigned int MAP_PAGES = 20; +const unsigned int REGION_ITERATIONS = 20; + + + +/* An activity opening and reading from a file. */ + +static long activity(file_t *context, unsigned long fileid, unsigned int start_page) +{ + unsigned long step = page(1); + unsigned long sample = page(1); + + /* Allocate a buffer for sampling from the file. */ + + char buf[sample + 1]; + + /* Invoke the open method to receive the file reference. */ + + file_t file; + + long err = file_context_open(&file, context); + + if (err) + { + printf("Could not obtain file for %ld @ page %d: %s\n", fileid, start_page, l4sys_errtostr(err)); + return err; + } + + /* A region of the file is mapped. */ + + err = file_mmap(&file, page(start_page), page(MAP_PAGES)); + + if (err) + { + printf("Could not map file region for %ld @ page %d: %s\n", fileid, start_page, l4sys_errtostr(err)); + file_close(&file); + return err; + } + + /* Read the region a number of times. */ + + for (unsigned int read_counter = 0; read_counter < REGION_ITERATIONS; read_counter++) + { + for (unsigned long offset = 0; offset < file_populated_span(&file); offset += step) + { + unsigned long remaining = file_populated_span(&file) - offset; + unsigned long sample_remaining = remaining < sample ? remaining : sample; + + strncpy(buf, (file.memory + offset), sample_remaining); + buf[sample_remaining] = '\0'; + + /* Test the data obtained. */ + + unsigned long filepos = file.start_pos + offset; + unsigned long _fileid = 0, _filepos = 0; + char *sep = strchr(buf, ':'); + + if (sep != NULL) + { + *sep = '\0'; sep++; + _fileid = atol(buf); _filepos = atol(sep); + } + + if ((fileid != _fileid) || (filepos != _filepos)) + printf("! %ld:%ld is not %ld:%ld\n", _fileid, _filepos, fileid, filepos); + } + } + + file_close(&file); + + return L4_EOK; +} + + + +static long activity_iterate(file_t *context, unsigned long fileid, unsigned int start_page) +{ + long err; + + /* Open the file, read pages, close the file, over and over. */ + + for (unsigned int iteration = 0; iteration < ACTIVITY_ITERATIONS; iteration++) + { + err = activity(context, fileid, start_page); + if (err) + break; + } + + return err; +} + + + +static long context_for_file(unsigned long fileid, file_t *file, l4_cap_idx_t server) +{ + long err = file_context(file, server); + + if (err) + { + printf("Could not obtain context: %s\n", l4sys_errtostr(err)); + file_close(file); + return err; + } + + /* Write the filename. */ + + sprintf(file->memory, "%ld", fileid); + + return L4_EOK; +} + + + +int main(void) +{ + long err; + + /* Introduce concurrency control. */ + + err = ipc_thread_init(); + + if (err) + { + printf("Initialisation error: %s\n", l4sys_errtostr(err)); + return 1; + } + + /* Retain activity and context details. */ + + std::thread *activities[NUMBER_OF_FILES * START_LIMIT]; + file_t contexts[NUMBER_OF_FILES]; + + /* Obtain access to the filesystem. */ + + l4_cap_idx_t server = l4re_env_get_cap("server"); + + /* Obtain opener contexts for the files. */ + + unsigned long fileid; + + for (fileid = 0; fileid < NUMBER_OF_FILES; fileid++) + { + err = context_for_file(fileid, &contexts[fileid], server); + + if (err) + { + printf("Context allocation failed.\n"); + return 1; + } + } + + /* Start threads accessing all the files. */ + + printf("Starting threads...\n"); + + time_t t = time(NULL); + int current = 0; + unsigned long errors = 0; + + for (fileid = 0; fileid < NUMBER_OF_FILES; fileid++) + { + for (unsigned int start_page = 0; start_page < START_LIMIT; start_page++) + { + try + { + activities[current++] = new std::thread(activity_iterate, &contexts[fileid], fileid, start_page); + } + catch (const std::system_error &exc) + { + errors++; + } + } + } + + /* Wait for the threads. */ + + int limit = current; + + printf("Waiting for %d threads...\n", limit); + + for (current = 0; current < limit; current++) + activities[current]->join(); + + /* Discard the contexts. */ + + for (fileid = 0; fileid < NUMBER_OF_FILES; fileid++) + file_close(&contexts[fileid]); + + t = time(NULL) - t; + printf("Activities completed in %ld seconds (with %ld threads not started).\n", t, errors); + + return 0; +} + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 138ddb918cf2 -r 405eb83f7eed tests/dstest_test_server.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/dstest_test_server.cc Thu Apr 01 00:57:43 2021 +0200 @@ -0,0 +1,88 @@ +/* + * Test dataspace operations. + * + * Copyright (C) 2020, 2021 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 + +#include +#include +#include + +#include "memory_incremental.h" +#include "memory_utils.h" +#include "page_queue_shared.h" +#include "pages.h" +#include "resource_server.h" +#include "test_file_opener.h" + + + +const unsigned int REGION_PAGES = 8; +const unsigned int MEMORY_PAGES = REGION_PAGES * 10; +const unsigned int FILE_PAGES = 20; + +int main(int argc, char *argv[]) +{ + long err; + + /* Introduce concurrency control. */ + + err = ipc_thread_init(); + + if (err) + { + printf("Initialisation error: %s\n", l4sys_errtostr(err)); + return 1; + } + + /* Configure the number of available pages using any argument. */ + + unsigned int memory_pages = MEMORY_PAGES; + + if (argc > 1) + memory_pages = atoi(argv[1]) * REGION_PAGES; + + /* Some memory plus infrastructure. */ + + MemoryIncremental mem(memory_pages, page(REGION_PAGES)); + PageQueueShared queue; + Pages pages(&mem, &queue); + TestFileOpener opener(&pages, page(FILE_PAGES)); + + /* Register a server associating it with the given object. */ + + ResourceServer server(&opener); + err = server.bind("server"); + + if (err) + { + printf("Could not bind server: %s\n", l4sys_errtostr(err)); + return 1; + } + + printf("Starting server...\n"); + server.start(); + return 0; +} + +// vim: tabstop=2 expandtab shiftwidth=2