# HG changeset patch # User Paul Boddie # Date 1616625893 -3600 # Node ID ec1f8f18c3069381b1fb91ebf46ca125aae51bd5 # Parent 9952e8331ad5fbf601112e55fd3da11c87a2ae27 Introduced initial pipe support using a special "conserving" page collection which only queues released pages, not issued pages, for reuse, together with dedicated paging coordinators for each pipe. diff -r 9952e8331ad5 -r ec1f8f18c306 Makefile --- a/Makefile Wed Mar 24 23:18:06 2021 +0100 +++ b/Makefile Wed Mar 24 23:44:53 2021 +0100 @@ -2,8 +2,8 @@ L4DIR ?= $(PKGDIR)/../.. TARGET = \ - dstest_block_client dstest_host_client dstest_test_client \ - dstest_block_server dstest_host_server dstest_test_server + dstest_block_client dstest_host_client dstest_pipe_client dstest_test_client \ + dstest_block_server dstest_host_server dstest_pipe_server dstest_test_server MODE = static @@ -24,13 +24,16 @@ opener_context_object_NAME = OpenerContextObject opener_context_object_INTERFACES = dataspace opener_context -COMP_INTERFACES_CC = mapped_file_object opener_context_object +pipe_object_NAME = PipeObject +pipe_object_INTERFACES = dataspace pipe + +COMP_INTERFACES_CC = mapped_file_object opener_context_object pipe_object # Individual interfaces. -CLIENT_INTERFACES_CC = dataspace file mapped_file opener opener_context +CLIENT_INTERFACES_CC = dataspace file mapped_file opener opener_context pipe pipe_opener -SERVER_INTERFACES_CC = opener $(call common_interfaces,$(COMP_INTERFACES_CC)) +SERVER_INTERFACES_CC = opener pipe_opener $(call common_interfaces,$(COMP_INTERFACES_CC)) # Generated and plain source files. @@ -44,13 +47,16 @@ PLAIN_SRC_CC_dstest_host_client = dstest_host_client.cc file.cc +PLAIN_SRC_CC_dstest_pipe_client = dstest_pipe_client.cc file.cc + PLAIN_SRC_CC_dstest_test_client = dstest_test_client.cc file.cc PLAIN_SRC_CC_common_server = \ access_map.cc accessing.cc accessor.cc \ flexpage.cc file_pager.cc ipc.cc memory.cc \ opener_resource.cc opener_context_resource.cc \ - page_mapper.cc page_queue.cc pager.cc pages.cc paging.cc \ + page_mapper.cc page_queue.cc pager.cc \ + pages.cc pages_conserving.cc paging.cc \ region.cc resource_server.cc simple_pager.cc PLAIN_SRC_CC_dstest_block_server = \ @@ -64,6 +70,12 @@ dstest_host_server.cc \ files/host_file_accessor.cc files/host_file_opener.cc +PLAIN_SRC_CC_dstest_pipe_server = \ + $(PLAIN_SRC_CC_common_server) \ + dstest_pipe_server.cc \ + pipe_opener_resource.cc pipe_pager.cc \ + files/pipe_accessor.cc files/pipe_paging.cc + PLAIN_SRC_CC_dstest_test_server = \ $(PLAIN_SRC_CC_common_server) \ dstest_test_server.cc \ @@ -81,6 +93,11 @@ $(PLAIN_SRC_CC_dstest_host_client) \ $(COMMON_SRC_CC) +SRC_CC_dstest_pipe_client = \ + $(CLIENT_INTERFACES_SRC_CC) \ + $(PLAIN_SRC_CC_dstest_pipe_client) \ + $(COMMON_SRC_CC) + SRC_CC_dstest_test_client = \ $(CLIENT_INTERFACES_SRC_CC) \ $(PLAIN_SRC_CC_dstest_test_client) \ @@ -96,6 +113,11 @@ $(PLAIN_SRC_CC_dstest_host_server) \ $(COMMON_SRC_CC) +SRC_CC_dstest_pipe_server = \ + $(SERVER_INTERFACES_SRC_CC) \ + $(PLAIN_SRC_CC_dstest_pipe_server) \ + $(COMMON_SRC_CC) + SRC_CC_dstest_test_server = \ $(SERVER_INTERFACES_SRC_CC) \ $(PLAIN_SRC_CC_dstest_test_server) \ @@ -112,10 +134,14 @@ $(PLAIN_SRC_CC_dstest_host_client): $(CLIENT_INTERFACES_SRC_CC) +$(PLAIN_SRC_CC_dstest_pipe_client): $(CLIENT_INTERFACES_SRC_CC) + $(PLAIN_SRC_CC_dstest_test_client): $(CLIENT_INTERFACES_SRC_CC) $(PLAIN_SRC_CC_dstest_block_server): $(SERVER_INTERFACES_SRC_CC) $(PLAIN_SRC_CC_dstest_host_server): $(SERVER_INTERFACES_SRC_CC) +$(PLAIN_SRC_CC_dstest_pipe_server): $(SERVER_INTERFACES_SRC_CC) + $(PLAIN_SRC_CC_dstest_test_server): $(SERVER_INTERFACES_SRC_CC) diff -r 9952e8331ad5 -r ec1f8f18c306 conf/dstest_pipe.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/dstest_pipe.cfg Wed Mar 24 23:44:53 2021 +0100 @@ -0,0 +1,23 @@ +-- vim:set ft=lua: + +local L4 = require("L4"); + +local l = L4.default_loader; + +local server = l:new_channel(); + +l:start({ + caps = { + server = server:svr(), + }, + log = { "server", "r" }, + }, + "rom/dstest_pipe_server"); + +l:start({ + caps = { + server = server, + }, + log = { "client", "g" }, + }, + "rom/dstest_pipe_client"); diff -r 9952e8331ad5 -r ec1f8f18c306 conf/dstest_pipe.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/dstest_pipe.list Wed Mar 24 23:44:53 2021 +0100 @@ -0,0 +1,25 @@ +entry dstest_pipe +roottask moe rom/dstest_pipe.cfg +module dstest_pipe.cfg +module l4re +module ned +module dstest_pipe_client +module dstest_pipe_server +module lib4re-c.so +module lib4re-c-util.so +module lib4re.so +module lib4re-util.so +module libc_be_l4refile.so +module libc_be_l4re.so +module libc_be_socket_noop.so +module libc_support_misc.so +module libdl.so +module libipc.so +module libl4sys-direct.so +module libl4sys.so +module libl4util.so +module libld-l4.so +module libpthread.so +module libstdc++.so +module libsupc++.so +module libuc_c.so diff -r 9952e8331ad5 -r ec1f8f18c306 dstest_pipe_client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dstest_pipe_client.cc Wed Mar 24 23:44:53 2021 +0100 @@ -0,0 +1,117 @@ +/* + * 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); + } +} + +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(&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: %s\n", l4sys_errtostr(err)); + return 1; + } + } + + /* 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 9952e8331ad5 -r ec1f8f18c306 dstest_pipe_server.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dstest_pipe_server.cc Wed Mar 24 23:44:53 2021 +0100 @@ -0,0 +1,58 @@ +/* + * 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.h" +#include "pages_conserving.h" +#include "pipe_opener_resource.h" +#include "resource_server.h" + + + +const unsigned int MEMORY_PAGES = 20; +const unsigned int PIPE_PAGES = 2; + +int main(void) +{ + /* Some memory plus infrastructure. */ + + Memory mem(MEMORY_PAGES); + PagesConserving pages(&mem, PIPE_PAGES); + PipeOpenerResource 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 9952e8331ad5 -r ec1f8f18c306 file.cc --- a/file.cc Wed Mar 24 23:18:06 2021 +0100 +++ b/file.cc Wed Mar 24 23:44:53 2021 +0100 @@ -28,6 +28,8 @@ #include "file_client.h" #include "opener_client.h" #include "opener_context_client.h" +#include "pipe_client.h" +#include "pipe_opener_client.h" #include "mapped_file_client.h" #include "file.h" @@ -229,4 +231,90 @@ return 0; } + + +/* Open two pipe endpoints using the given pipe server. */ + +long pipe_open(file_t *reader, file_t *writer, l4_cap_idx_t server) +{ + client_PipeOpener opener(server); + + file_init(reader); + file_init(writer); + + long err = opener.pipe(&reader->ref, &writer->ref); + if (err) + return err; + + err = pipe_next(writer) || pipe_next(reader); + + if (err) + { + file_close(reader); + file_close(writer); + } + + return err; +} + +/* Access the current region for a pipe endpoint. */ + +long pipe_current(file_t *pipe) +{ + client_Pipe _pipe(pipe->ref); + long err = _pipe.current_region(&pipe->data_end, &pipe->size); + char *memory = pipe->memory; + + if (err) + return err; + + pipe->end_pos = pipe->size; + + err = ipc_attach_dataspace(pipe->ref, file_span(pipe), (void **) &pipe->memory); + if (err) + return err; + + if (memory != NULL) + ipc_detach_dataspace(memory); + + return L4_EOK; +} + +/* Access the next region for a pipe endpoint, updating the eventual size of + the current region. */ + +long pipe_next(file_t *pipe) +{ + client_Pipe _pipe(pipe->ref); + long err = _pipe.next_region(&pipe->data_end, &pipe->size); + char *memory = pipe->memory; + + if (err) + return err; + + pipe->end_pos = pipe->size; + + err = ipc_attach_dataspace(pipe->ref, file_span(pipe), (void **) &pipe->memory); + if (err) + return err; + + if (memory != NULL) + ipc_detach_dataspace(memory); + + return L4_EOK; +} + +/* Set the size of the written region. */ + +long pipe_written(file_t *pipe, offset_t size) +{ + if (size <= pipe->size) + { + pipe->data_end = size; + return L4_EOK; + } + else + return -L4_EINVAL; +} + // vim: tabstop=2 expandtab shiftwidth=2 diff -r 9952e8331ad5 -r ec1f8f18c306 file.h --- a/file.h Wed Mar 24 23:18:06 2021 +0100 +++ b/file.h Wed Mar 24 23:44:53 2021 +0100 @@ -78,6 +78,18 @@ char *file_string_get(file_t *file, offset_t offset); int file_string_set(file_t *file, const char *data, offset_t offset, offset_t *written); + + +/* Pipe operations. */ + +long pipe_open(file_t *reader, file_t *writer, l4_cap_idx_t server); + +/* Pipe region operations. */ + +long pipe_current(file_t *pipe); +long pipe_next(file_t *pipe); +long pipe_written(file_t *pipe, offset_t size); + EXTERN_C_END // vim: tabstop=2 expandtab shiftwidth=2 diff -r 9952e8331ad5 -r ec1f8f18c306 files/pipe_accessor.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/files/pipe_accessor.cc Wed Mar 24 23:44:53 2021 +0100 @@ -0,0 +1,43 @@ +#include "pipe_accessor.h" + +#include + +PipeAccessor::PipeAccessor() +: Accessor(0) +{ +} + +/* Perform any closing operation on the file. */ + +void PipeAccessor::close() +{ +} + +/* Perform any opening operation on the file. */ + +void PipeAccessor::open() +{ +} + +/* Data transfer helper methods. */ + +void PipeAccessor::fill_populated(Flexpage *flexpage) +{ + offset_t filepos = flexpage->base_offset; + offset_t addr = flexpage->base_addr; + + /* Tag the region with file state. */ + + flexpage->region->fill(fileid, filepos); + + /* File the flexpage with zero. */ + + memset((void *) addr, 0, flexpage->size); +} + +void PipeAccessor::flush_populated(Flexpage *flexpage) +{ + flexpage->region->flush(); +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 9952e8331ad5 -r ec1f8f18c306 files/pipe_accessor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/files/pipe_accessor.h Wed Mar 24 23:44:53 2021 +0100 @@ -0,0 +1,25 @@ +#pragma once + +#include "accessor.h" + +/* A pipe accessor, providing flexpages for pipe sections. */ + +class PipeAccessor : public Accessor +{ +protected: + + /* Data transfer helper methods. */ + + virtual void fill_populated(Flexpage *flexpage); + + virtual void flush_populated(Flexpage *flexpage); + +public: + explicit PipeAccessor(); + + virtual void close(); + + virtual void open(); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 9952e8331ad5 -r ec1f8f18c306 files/pipe_paging.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/files/pipe_paging.cc Wed Mar 24 23:44:53 2021 +0100 @@ -0,0 +1,35 @@ +#include "pipe_paging.h" + +PipePaging::PipePaging() +{ +} + +/* Add a region to the sequence. */ + +void PipePaging::add_region(PageMapper *mapper) +{ + _regions.push_back(mapper); +} + +/* Return the first region in the sequence. */ + +PageMapper *PipePaging::first_region() +{ + return _regions.front(); +} + +/* Return the next region for the reader. If only a single region remains, with + the reader wishing to move to the next, return NULL. */ + +PageMapper *PipePaging::next_region() +{ + if (_regions.size() > 1) + { + _regions.pop_front(); + return _regions.front(); + } + else + return NULL; +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 9952e8331ad5 -r ec1f8f18c306 files/pipe_paging.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/files/pipe_paging.h Wed Mar 24 23:44:53 2021 +0100 @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include "page_mapper.h" + +/* Pipe paging support, maintaining the sequence of active regions or sections + in a pipe. */ + +class PipePaging +{ +protected: + std::list _regions; + +public: + explicit PipePaging(); + + virtual void add_region(PageMapper *mapper); + + virtual PageMapper *first_region(); + + virtual PageMapper *next_region(); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 9952e8331ad5 -r ec1f8f18c306 pager.cc --- a/pager.cc Wed Mar 24 23:18:06 2021 +0100 +++ b/pager.cc Wed Mar 24 23:44:53 2021 +0100 @@ -7,12 +7,16 @@ Pager::Pager(PageMapper *mapper, flags_t flags) : _start(0), _size(0), _mapper(mapper), _flags(flags) { - _mapper->attach(); + /* Some pagers may not be initialised with a mapper. */ + + if (_mapper != NULL) + _mapper->attach(); } void Pager::close() { - _mapper->detach(); + if (_mapper != NULL) + _mapper->detach(); } /* Flush data to the file. */ diff -r 9952e8331ad5 -r ec1f8f18c306 pages.h --- a/pages.h Wed Mar 24 23:18:06 2021 +0100 +++ b/pages.h Wed Mar 24 23:44:53 2021 +0100 @@ -20,15 +20,15 @@ explicit Pages(); - Flexpage *remove(); + virtual Flexpage *remove(); - bool reserve(PageOwner *owner, Flexpage *flexpage); + virtual bool reserve(PageOwner *owner, Flexpage *flexpage); - Flexpage *flexpage(); + virtual Flexpage *flexpage(); - void queue(PageOwner *owner, Flexpage *flexpage); + virtual void queue(PageOwner *owner, Flexpage *flexpage); - void release(Flexpage *flexpage); + virtual void release(Flexpage *flexpage); }; // vim: tabstop=4 expandtab shiftwidth=4 diff -r 9952e8331ad5 -r ec1f8f18c306 pages_conserving.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pages_conserving.cc Wed Mar 24 23:44:53 2021 +0100 @@ -0,0 +1,98 @@ +#include "pages_conserving.h" + +PagesConserving::PagesConserving(Memory *memory, unsigned int increment) +: Pages(memory), _increment(increment) +{ +} + +PagesConserving::PagesConserving() +: Pages(), _increment(1) +{ +} + + + +/* Refuse to obtain a new flexpage directly. All flexpages must be obtained from + the page queue. */ + +Flexpage *PagesConserving::flexpage() +{ + return NULL; +} + +/* Pretend to queue an entry associating the given 'owner' and 'flexpage'. + Since this collection "conserves" flexpages, they will not be queued unless + completely unused. */ + +void PagesConserving::queue(PageOwner *owner, Flexpage *flexpage) +{ + (void) owner; (void) flexpage; +} + +/* Pretend to reserve a flexpage already being used by 'owner' and 'flexpage'. + Since flexpages are not queued when in use, there is nothing to reserve. */ + +bool PagesConserving::reserve(PageOwner *owner, Flexpage *flexpage) +{ + (void) owner; (void) flexpage; + return true; +} + + + +/* Decrease the provision of flexpages to pipes. */ + +bool PagesConserving::decrease() +{ + // NOTE: Need to remove flexpages from the queue. + // NOTE: This might need to happen incrementally in case some pages are not + // NOTE: back in the queue for whatever reason. + + return true; +} + +/* Increase the provision of flexpages to pipes, returning whether allocation + succeeded. */ + +bool PagesConserving::increase() +{ + unsigned int regions = _increment; + std::list allocated; + std::list::iterator it; + + /* Allocate regions for the defined increment value. */ + + while (regions) + { + Region *r = _memory->region(); + + /* Free all allocated regions if not all regions can be allocated. */ + + if (r == NULL) + { + for (it = allocated.begin(); it != allocated.end(); it++) + _memory->release(r); + + return false; + } + + allocated.push_back(r); + regions--; + } + + /* Queue flexpages for the regions. */ + + for (it = allocated.begin(); it != allocated.end(); it++) + _queue.push(NULL, new Flexpage(*it)); + + return true; +} + +/* Return the allocation increment. */ + +offset_t PagesConserving::allocation() +{ + return _memory->region_size() * _increment; +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 9952e8331ad5 -r ec1f8f18c306 pages_conserving.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pages_conserving.h Wed Mar 24 23:44:53 2021 +0100 @@ -0,0 +1,37 @@ +#pragma once + +#include "pages.h" + + + +/* A page collection where the pages are "conserved", meaning that they are not + queued for reuse unless they are completely unused. */ + +class PagesConserving : public Pages +{ +protected: + unsigned int _increment; + +public: + explicit PagesConserving(Memory *memory, unsigned int increment=1); + + explicit PagesConserving(); + + /* Specialised methods. */ + + virtual Flexpage *flexpage(); + + virtual void queue(PageOwner *owner, Flexpage *flexpage); + + virtual bool reserve(PageOwner *owner, Flexpage *flexpage); + + /* Memory control methods. */ + + virtual bool decrease(); + + virtual bool increase(); + + virtual offset_t allocation(); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 9952e8331ad5 -r ec1f8f18c306 pipe_opener_resource.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pipe_opener_resource.cc Wed Mar 24 23:44:53 2021 +0100 @@ -0,0 +1,62 @@ +#include "pipe_opener_resource.h" +#include "pipe_opener_server.h" +#include "pipe_pager.h" +#include "resource_server.h" + + + +/* Support for providing access to pipes. */ + +PipeOpenerResource::PipeOpenerResource(PagesConserving *pages) +: _pages(pages) +{ +} + +int PipeOpenerResource::expected_items() +{ + return PipeOpener_expected_items; +} + +ipc_server_handler_type PipeOpenerResource::handler() +{ + return (ipc_server_handler_type) handle_PipeOpener; +} + + + +/* Pipe opener interface methods. */ + +long PipeOpenerResource::pipe(l4_cap_idx_t *reader, l4_cap_idx_t *writer) +{ + /* Both endpoints will employ a common paging coordinator. */ + + PipePaging *paging = new PipePaging(); + + /* Each endpoint will have its own pager. */ + + /* NOTE: Failure to open an endpoint should invalidate both, plus the + paging object. Also, any active server thread would need to be + cancelled. */ + + return open_endpoint(paging, false, reader) || open_endpoint(paging, true, writer); +} + +long PipeOpenerResource::open_endpoint(PipePaging *paging, bool writer, l4_cap_idx_t *endpoint) +{ + PipePager *pager = new PipePager(_pages, paging, writer); + + /* Start the endpoint server in a new thread. + If the thread does not start, the resource should be finalised. */ + + ResourceServer server(pager); + long err = server.start_thread(); + + /* Return the server capability to the caller. */ + + if (!err) + *endpoint = server.config()->server; + + return err; +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 9952e8331ad5 -r ec1f8f18c306 pipe_opener_resource.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pipe_opener_resource.h Wed Mar 24 23:44:53 2021 +0100 @@ -0,0 +1,34 @@ +#pragma once + +#include "pages_conserving.h" +#include "pipe_opener_interface.h" +#include "pipe_paging.h" +#include "resource.h" + +/* Support for providing access to pipes. */ + +class PipeOpenerResource : public Resource, public PipeOpener +{ +protected: + PagesConserving *_pages; + + long open_endpoint(PipePaging *paging, bool writer, l4_cap_idx_t *endpoint); + +public: + explicit PipeOpenerResource(PagesConserving *pages); + + /* Server details. */ + + int expected_items(); + + ipc_server_handler_type handler(); + + void *interface() + { return static_cast(this); } + + /* PipeOpener interface methods. */ + + long pipe(l4_cap_idx_t *reader, l4_cap_idx_t *writer); +}; + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 9952e8331ad5 -r ec1f8f18c306 pipe_pager.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pipe_pager.cc Wed Mar 24 23:44:53 2021 +0100 @@ -0,0 +1,125 @@ +#include "pipe_pager.h" +#include "pipe_object_server.h" + +/* Initialise a pager for a pipe with a shared page mapper for moderating + access to loaded pages. At first, no mapper will be configured: this must be + done by requesting a region. */ + +PipePager::PipePager(PagesConserving *pages, PipePaging *paging, bool writer) +: Pager(NULL, writer ? L4_FPAGE_RW : L4_FPAGE_RO), + _pages(pages), _paging(paging), _writer(writer) +{ + /* Set the size of each paged region to the amount allocation for such + regions. */ + + _size = _pages->allocation(); +} + +int PipePager::expected_items() +{ + return PipeObject_expected_items; +} + +ipc_server_handler_type PipePager::handler() +{ + return (ipc_server_handler_type) handle_PipeObject; +} + + + +/* Support paging. */ + +long PipePager::map(unsigned long offset, l4_addr_t hot_spot, flags_t flags, l4_snd_fpage_t *region) +{ + return Pager::map(offset, hot_spot, flags, region); +} + + + +/* Return details of the current region. */ + +long PipePager::current_region(offset_t *populated_size, offset_t *size) +{ + if (_mapper != NULL) + { + *populated_size = _mapper->get_data_size(); + *size = _size; + return L4_EOK; + } + else + return -L4_EIO; +} + +/* Obtain the next region and its details. */ + +long PipePager::next_region(offset_t *populated_size, offset_t *size) +{ + /* Obtain a new region if writing. */ + + if (_writer) + return next_region_for_writer(populated_size, size); + else + return next_region_for_reader(populated_size, size); +} + +long PipePager::next_region_for_reader(offset_t *populated_size, offset_t *size) +{ + /* Obtain the next region if a current region is defined. */ + + if (_mapper != NULL) + { + PageMapper *mapper = _paging->next_region(); + + /* Return an error if no next region currently exists. */ + + if (mapper == NULL) + return -L4_EIO; + + /* Detach and discard the current page mapper. */ + + _mapper->detach(); + delete _mapper; + + _mapper = mapper; + } + + /* Obtain the first region if no mapper is defined. */ + + else + _mapper = _paging->first_region(); + + /* Return the details of the now-current region. */ + + return current_region(populated_size, size); +} + +long PipePager::next_region_for_writer(offset_t *populated_size, offset_t *size) +{ + /* Set the populated size before moving on. */ + + if (_mapper != NULL) + _mapper->set_data_size(*populated_size); + + /* A guaranteed amount of memory is reserved for the pipe. */ + + if (!_pages->increase()) + return -L4_ENOMEM; + + /* Set the page mapper for the region. */ + + _mapper = new PageMapper(&_accessor, _pages); + _mapper->attach(); + + /* Record the mapper as the latest region in the accessor. */ + + _paging->add_region(_mapper); + + /* Set the region size to the allocated amount. */ + + *size = _size; + *populated_size = 0; + + return L4_EOK; +} + +// vim: tabstop=4 expandtab shiftwidth=4 diff -r 9952e8331ad5 -r ec1f8f18c306 pipe_pager.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pipe_pager.h Wed Mar 24 23:44:53 2021 +0100 @@ -0,0 +1,48 @@ +#pragma once + +#include "pipe_accessor.h" +#include "pipe_object_interface.h" +#include "pipe_paging.h" +#include "pager.h" +#include "pages_conserving.h" + +/* A pager abstraction for a pipe. */ + +class PipePager : public Pager, public PipeObject +{ +protected: + PipeAccessor _accessor; + PagesConserving *_pages; + PipePaging *_paging; + bool _writer; + + /* Helper methods. */ + + virtual long next_region_for_reader(offset_t *populated_size, offset_t *size); + + virtual long next_region_for_writer(offset_t *populated_size, offset_t *size); + +public: + explicit PipePager(PagesConserving *pages, PipePaging *paging, bool writer); + + /* Server details. */ + + int expected_items(); + + ipc_server_handler_type handler(); + + void *interface() + { return static_cast(this); } + + /* Pager methods. */ + + virtual long map(unsigned long offset, l4_addr_t hot_spot, flags_t flags, l4_snd_fpage_t *region); + + /* Pipe methods. */ + + virtual long current_region(offset_t *populated_size, offset_t *size); + + virtual long next_region(offset_t *populated_size, offset_t *size); +}; + +// vim: tabstop=4 expandtab shiftwidth=4