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 operation releases the 55 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