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_preallocated.h> 23 24 #include "page_queue_partitioned.h" 25 #include "pipe_paging.h" 26 27 #include "notifier_client.h" 28 29 30 31 PipePaging::PipePaging(Memory *memory, offset_t size) 32 : NotificationSupport(2), _memory(NULL), _size(size) 33 { 34 /* Reserve space for two pipe regions. */ 35 36 _memory = new MemoryPreallocated(memory, round(size, memory->region_size()) * 2); 37 _queue = new PageQueuePartitioned(); 38 _pages = new Pages(_memory, _queue); 39 40 /* Reset the mappers associated with the regions. */ 41 42 for (unsigned int i = 0; i < 2; i++) 43 _regions[i] = NULL; 44 } 45 46 /* Return whether one or more endpoints have detached. */ 47 48 int PipePaging::closed() 49 { 50 return _active_endpoints < 2; 51 } 52 53 void PipePaging::discard_region(unsigned int i) 54 { 55 PageMapper *mapper = _regions[i]; 56 57 if (mapper != NULL) 58 { 59 mapper->detach(); 60 _regions[i] = NULL; 61 delete mapper; 62 } 63 } 64 65 /* Detach one endpoint. */ 66 67 void PipePaging::detach() 68 { 69 if (!_active_endpoints) 70 return; 71 else 72 _active_endpoints--; 73 74 /* Return if the other endpoint is attached. */ 75 76 if (_active_endpoints) 77 return; 78 79 /* Discard all regions from the pipe. */ 80 81 for (unsigned int i = 0; i < 2; i++) 82 discard_region(i); 83 84 /* Release notifiers. */ 85 86 release_notifiers(); 87 88 /* Delete the page collection and related objects. */ 89 90 delete _pages; 91 delete _queue; 92 delete _memory; 93 } 94 95 /* Add a region to the sequence. */ 96 97 PageMapper *PipePaging::add_region() 98 { 99 /* If the writer already accesses a different region to the reader, no new 100 region is added. */ 101 102 if (_writing != _reading) 103 return NULL; 104 105 /* Select the other region of the pair being maintained. */ 106 107 _writing = 1 - _writing; 108 109 /* Make a new mapper for the region. */ 110 111 PageMapper *mapper = new PageMapper(&_accessors[_writing], _pages); 112 113 /* Initialise and record the mapper. */ 114 115 mapper->attach(); 116 mapper->set_data_size(0); 117 118 _regions[_writing] = mapper; 119 120 /* Let the writer notify the reader. */ 121 122 notify_others(PipePaging::WRITER, NOTIFY_CONTENT_AVAILABLE); 123 124 /* Return the next region's mapper. */ 125 126 return mapper; 127 } 128 129 /* Return the current region for reading. */ 130 131 PageMapper *PipePaging::current_region() 132 { 133 return _regions[_reading]; 134 } 135 136 /* Return the next region for the reader if the writer is using a different one. 137 Otherwise, return NULL. */ 138 139 PageMapper *PipePaging::next_region() 140 { 141 /* If the reader already accesses the same region to the writer, no next 142 region can be obtained. */ 143 144 if (_reading == _writing) 145 return NULL; 146 147 /* Detach and discard the current page mapper. */ 148 149 discard_region(_reading); 150 151 /* Select the next region. */ 152 153 _reading = 1 - _reading; 154 155 /* Let the reader notify the writer. */ 156 157 notify_others(PipePaging::READER, NOTIFY_SPACE_AVAILABLE); 158 159 /* Return the next region's mapper. */ 160 161 return _regions[_reading]; 162 } 163 164 // vim: tabstop=4 expandtab shiftwidth=4