1 /* 2 * A pipe paging coordinator, permitting memory sharing pipe endpoints. 3 * 4 * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License as 8 * published by the Free Software Foundation; either version 2 of 9 * the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA 20 */ 21 22 #include <mem/memory_incremental.h> 23 #include <mem/memory_preallocated.h> 24 25 #include "page_queue_partitioned.h" 26 #include "pipe_paging.h" 27 28 29 30 PipePaging::PipePaging(Memory *memory, offset_t size) 31 : _memory(NULL), _size(size) 32 { 33 /* Reserve space for two pipe regions. */ 34 35 _memory = new MemoryPreallocated(memory, round(size, memory->region_size()) * 2); 36 _queue = new PageQueuePartitioned(); 37 _pages = new Pages(_memory, _queue); 38 39 /* Reset the mappers associated with the regions. */ 40 41 for (unsigned int i = 0; i < 2; i++) 42 _regions[i] = NULL; 43 } 44 45 /* Return whether one or more endpoints have detached. */ 46 47 int PipePaging::closed() 48 { 49 return _endpoints < 2; 50 } 51 52 /* Detach one endpoint. */ 53 54 void PipePaging::detach() 55 { 56 if (!_endpoints) 57 return; 58 else 59 _endpoints--; 60 61 /* Return if the other endpoint is attached. */ 62 63 if (_endpoints) 64 return; 65 66 /* Discard all regions from the pipe. */ 67 68 for (unsigned int i = 0; i < 2; i++) 69 { 70 PageMapper *mapper = _regions[i]; 71 72 if (mapper != NULL) 73 { 74 mapper->detach(); 75 _regions[i] = NULL; 76 delete mapper; 77 } 78 } 79 80 /* Delete the page collection and related objects. */ 81 82 delete _pages; 83 delete _queue; 84 delete _memory; 85 } 86 87 /* Add a region to the sequence. */ 88 89 PageMapper *PipePaging::add_region() 90 { 91 /* If the writer already accesses a different region to the reader, no new 92 region is added. */ 93 94 if (_writing != _reading) 95 return NULL; 96 97 /* Select the other region of the pair being maintained. */ 98 99 _writing = 1 - _writing; 100 101 /* Make a new mapper for the region. */ 102 103 PageMapper *mapper = new PageMapper(&_accessors[_writing], _pages); 104 105 /* Initialise and record the mapper. */ 106 107 mapper->attach(); 108 mapper->set_data_size(0); 109 110 _regions[_writing] = mapper; 111 return mapper; 112 } 113 114 /* Return the current region for reading. */ 115 116 PageMapper *PipePaging::current_region() 117 { 118 return _regions[_reading]; 119 } 120 121 /* Return the next region for the reader if the writer is using a different one. 122 Otherwise, return NULL. */ 123 124 PageMapper *PipePaging::next_region() 125 { 126 /* If the reader already accesses the same region to the writer, no next 127 region can be obtained. */ 128 129 if (_reading == _writing) 130 return NULL; 131 132 /* Detach and discard the current page mapper. */ 133 134 PageMapper *mapper = _regions[_reading]; 135 136 if (mapper != NULL) 137 { 138 mapper->detach(); 139 _regions[_reading] = NULL; 140 delete mapper; 141 } 142 143 /* Select the next region. */ 144 145 _reading = 1 - _reading; 146 147 /* Return the next region's mapper. */ 148 149 return _regions[_reading]; 150 } 151 152 // vim: tabstop=4 expandtab shiftwidth=4