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