1 #include "ipc.h" 2 #include "page_mapper.h" 3 4 5 6 PageMapper::PageMapper(Accessor *accessor, Pages *pages) 7 : _accessor(accessor), _pages(pages), _attached(0) 8 { 9 } 10 11 /* Accounting methods. */ 12 13 /* Attach a pager, opening the accessor if required. */ 14 15 void PageMapper::attach() 16 { 17 std::lock_guard<std::mutex> guard(_lock); 18 19 if (!_attached) 20 _accessor->open(); 21 22 _attached += 1; 23 } 24 25 /* Detach a pager, purging active pages and closing the accessor if no more 26 pagers are attached. Return whether any pagers are still attached. */ 27 28 unsigned int PageMapper::detach() 29 { 30 std::lock_guard<std::mutex> guard(_lock); 31 32 if (_attached) 33 { 34 _attached -= 1; 35 36 if (!_attached) 37 { 38 _map.purge(this, _pages); 39 _accessor->close(); 40 } 41 } 42 43 return _attached; 44 } 45 46 /* Interface for the pager. */ 47 48 /* Return a flexpage providing access to the indicated file 'offset'. 49 50 The returned flexpage will either be an existing, compatible flexpage or a 51 completely new flexpage. 52 53 This method locks the accessor to prevent concurrent queries with the 54 same details, with the lock held until the queue or flush_all operations 55 release the lock. */ 56 57 Flexpage *PageMapper::get(offset_t offset) 58 { 59 _lock.lock(); 60 61 Flexpage *f = find(offset); 62 63 if (f == NULL) 64 f = flexpage(offset); 65 66 f->increment(); 67 return f; 68 } 69 70 /* Queue the given 'flexpage' in the page collection, making it available for 71 eventual reuse. 72 73 This method unlocks the accessor. */ 74 75 void PageMapper::queue(Flexpage *flexpage) 76 { 77 _pages->queue(this, flexpage); 78 79 _lock.unlock(); 80 } 81 82 /* Flush pages in the given range from 'start' with 'size'. */ 83 84 void PageMapper::flush_all(offset_t start, offset_t size) 85 { 86 std::lock_guard<std::mutex> guard(_lock); 87 88 _map.flush_all(start, size, this, _pages); 89 } 90 91 /* Return the maximum extent of the mapped resource. */ 92 93 offset_t PageMapper::get_data_size() 94 { 95 return _accessor->get_size(); 96 } 97 98 /* Internal flexpage retrieval methods. */ 99 100 /* Find an existing flexpage for 'offset'. Where the accessor has registered a 101 compatible flexpage, an attempt is made to reserve it in the page collection; 102 if this succeeds, the flexpage is returned. Otherwise, NULL is returned. */ 103 104 Flexpage *PageMapper::find(offset_t offset) 105 { 106 Flexpage *flexpage = _map.find(offset); 107 108 /* Between finding and reserving a flexpage, there is a possibility that 109 another accessor might acquire the flexpage, issue it, and even purge 110 it. */ 111 112 if ((flexpage != NULL) && _pages->reserve(this, flexpage)) 113 return flexpage; 114 else 115 return NULL; 116 } 117 118 /* Obtain a new flexpage for the file 'offset'. If the page collection is unable 119 to obtain a completely new flexpage, an existing flexpage is requested from 120 the page collection and recycled. 121 122 The obtained flexpage is filled with content. */ 123 124 Flexpage *PageMapper::flexpage(offset_t offset) 125 { 126 Flexpage *flexpage = _pages->flexpage(); 127 128 /* Obtain an existing flexpage and reuse it. */ 129 130 if (flexpage == NULL) 131 flexpage = _pages->remove(); 132 133 flexpage->reset(offset); 134 135 fill(flexpage); 136 _map.insert(flexpage); 137 return flexpage; 138 } 139 140 /* Interface for the page collection. */ 141 142 /* Remove the record of 'flexpage' in this accessor, flushing its content. */ 143 144 void PageMapper::remove(Flexpage *flexpage) 145 { 146 _map.remove(this, flexpage); 147 } 148 149 /* Data transfer methods. */ 150 151 void PageMapper::fill(Flexpage *flexpage) 152 { 153 _accessor->fill(flexpage); 154 } 155 156 void PageMapper::flush(Flexpage *flexpage, bool purge) 157 { 158 if (flexpage->decrement() || purge) 159 { 160 _accessor->flush(flexpage); 161 ipc_unmap_flexpage(flexpage); 162 flexpage->invalidate(); 163 } 164 } 165 166 // vim: tabstop=4 expandtab shiftwidth=4