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, unsigned long flags) 58 { 59 _lock.lock(); 60 61 Flexpage *f = find(offset); 62 63 if (f == NULL) 64 f = flexpage(offset); 65 66 /* Record a new user of the flexpage and upgrade the access flags. */ 67 68 f->increment(); 69 f->upgrade(flags); 70 return f; 71 } 72 73 /* Queue the given 'flexpage' in the page collection, making it available for 74 eventual reuse. 75 76 This method unlocks the accessor. */ 77 78 void PageMapper::queue(Flexpage *flexpage) 79 { 80 _pages->queue(this, flexpage); 81 82 _lock.unlock(); 83 } 84 85 /* Flush pages in the given range from 'start' with 'size'. */ 86 87 void PageMapper::flush_all(offset_t start, offset_t size) 88 { 89 std::lock_guard<std::mutex> guard(_lock); 90 91 _map.flush_all(start, size, this, _pages); 92 } 93 94 /* Return the maximum extent of the mapped resource. */ 95 96 offset_t PageMapper::get_data_size() 97 { 98 return _accessor->get_size(); 99 } 100 101 /* Internal flexpage retrieval methods. */ 102 103 /* Find an existing flexpage for 'offset'. Where the accessor has registered a 104 compatible flexpage, an attempt is made to reserve it in the page collection; 105 if this succeeds, the flexpage is returned. Otherwise, NULL is returned. */ 106 107 Flexpage *PageMapper::find(offset_t offset) 108 { 109 Flexpage *flexpage = _map.find(offset); 110 111 /* Between finding and reserving a flexpage, there is a possibility that 112 another accessor might acquire the flexpage, issue it, and even purge 113 it. */ 114 115 if ((flexpage != NULL) && _pages->reserve(this, flexpage)) 116 return flexpage; 117 else 118 return NULL; 119 } 120 121 /* Obtain a new flexpage for the file 'offset'. If the page collection is unable 122 to obtain a completely new flexpage, an existing flexpage is requested from 123 the page collection and recycled. 124 125 The obtained flexpage is filled with content. */ 126 127 Flexpage *PageMapper::flexpage(offset_t offset) 128 { 129 Flexpage *flexpage = _pages->flexpage(); 130 131 /* Obtain an existing flexpage and reuse it. */ 132 133 if (flexpage == NULL) 134 flexpage = _pages->remove(); 135 136 flexpage->reset(offset); 137 138 fill(flexpage); 139 _map.insert(flexpage); 140 return flexpage; 141 } 142 143 /* Interface for the page collection. */ 144 145 /* Remove the record of 'flexpage' in this accessor, flushing its content. */ 146 147 void PageMapper::remove(Flexpage *flexpage) 148 { 149 _map.remove(this, flexpage); 150 } 151 152 /* Data transfer methods. */ 153 154 void PageMapper::fill(Flexpage *flexpage) 155 { 156 _accessor->fill(flexpage); 157 } 158 159 void PageMapper::flush(Flexpage *flexpage, bool purge) 160 { 161 if (flexpage->decrement() || purge) 162 { 163 _accessor->flush(flexpage); 164 ipc_unmap_flexpage(flexpage); 165 flexpage->invalidate(); 166 } 167 } 168 169 // vim: tabstop=4 expandtab shiftwidth=4