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 for (unsigned int i = 0; i < 2; i++) 40 _regions[i] = NULL; 41 } 42 43 /* Detach one endpoint. */ 44 45 void PipePaging::detach() 46 { 47 if (!_endpoints) 48 return; 49 else 50 _endpoints--; 51 52 /* Return if the other endpoint is attached. */ 53 54 if (_endpoints) 55 return; 56 57 /* Discard all regions from the pipe. */ 58 59 for (unsigned int i = 0; i < 2; i++) 60 { 61 PageMapper *mapper = _regions[i]; 62 63 if (mapper != NULL) 64 { 65 mapper->detach(); 66 _regions[i] = NULL; 67 delete mapper; 68 } 69 } 70 71 /* Delete the page collection and related objects. */ 72 73 delete _pages; 74 delete _queue; 75 delete _memory; 76 } 77 78 /* Add a region to the sequence. */ 79 80 PageMapper *PipePaging::add_region() 81 { 82 /* If the writer already accesses a different region to the reader, no new 83 region is added. */ 84 85 if (_writing != _reading) 86 return NULL; 87 88 /* Select the other region of the pair being maintained. */ 89 90 _writing = 1 - _writing; 91 92 /* Make a new mapper for the region. */ 93 94 PageMapper *mapper = new PageMapper(&_accessors[_writing], _pages); 95 96 /* Initialise and record the mapper. */ 97 98 mapper->attach(); 99 mapper->set_data_size(0); 100 101 _regions[_writing] = mapper; 102 return mapper; 103 } 104 105 /* Return the current region for reading. */ 106 107 PageMapper *PipePaging::current_region() 108 { 109 return _regions[_reading]; 110 } 111 112 /* Return the next region for the reader if the writer is using a different one. 113 Otherwise, return NULL. */ 114 115 PageMapper *PipePaging::next_region() 116 { 117 /* If the reader already accesses the same region to the writer, no next 118 region can be obtained. */ 119 120 if (_reading == _writing) 121 return NULL; 122 123 /* Detach and discard the current page mapper. */ 124 125 PageMapper *mapper = _regions[_reading]; 126 127 if (mapper != NULL) 128 { 129 mapper->detach(); 130 _regions[_reading] = NULL; 131 delete mapper; 132 } 133 134 /* Return the next region. */ 135 136 _reading = 1 - _reading; 137 return _regions[_reading]; 138 } 139 140 // vim: tabstop=4 expandtab shiftwidth=4