Dash Core  0.12.2.1
P2P Digital Currency
pagelocker.h
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2015 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #ifndef BITCOIN_SUPPORT_PAGELOCKER_H
7 #define BITCOIN_SUPPORT_PAGELOCKER_H
8 
9 #include "support/cleanse.h"
10 
11 #include <map>
12 
13 #include <boost/thread/mutex.hpp>
14 #include <boost/thread/once.hpp>
15 
27 template <class Locker>
29 {
30 public:
32  {
33  // Determine bitmask for extracting page from address
34  assert(!(page_size & (page_size - 1))); // size must be power of two
35  page_mask = ~(page_size - 1);
36  }
37 
39  {
40  }
41 
42 
43  // For all pages in affected range, increase lock count
44  void LockRange(void* p, size_t size)
45  {
46  boost::mutex::scoped_lock lock(mutex);
47  if (!size)
48  return;
49  const size_t base_addr = reinterpret_cast<size_t>(p);
50  const size_t start_page = base_addr & page_mask;
51  const size_t end_page = (base_addr + size - 1) & page_mask;
52  for (size_t page = start_page; page <= end_page; page += page_size) {
53  Histogram::iterator it = histogram.find(page);
54  if (it == histogram.end()) // Newly locked page
55  {
56  locker.Lock(reinterpret_cast<void*>(page), page_size);
57  histogram.insert(std::make_pair(page, 1));
58  } else // Page was already locked; increase counter
59  {
60  it->second += 1;
61  }
62  }
63  }
64 
65  // For all pages in affected range, decrease lock count
66  void UnlockRange(void* p, size_t size)
67  {
68  boost::mutex::scoped_lock lock(mutex);
69  if (!size)
70  return;
71  const size_t base_addr = reinterpret_cast<size_t>(p);
72  const size_t start_page = base_addr & page_mask;
73  const size_t end_page = (base_addr + size - 1) & page_mask;
74  for (size_t page = start_page; page <= end_page; page += page_size) {
75  Histogram::iterator it = histogram.find(page);
76  assert(it != histogram.end()); // Cannot unlock an area that was not locked
77  // Decrease counter for page, when it is zero, the page will be unlocked
78  it->second -= 1;
79  if (it->second == 0) // Nothing on the page anymore that keeps it locked
80  {
81  // Unlock page and remove the count from histogram
82  locker.Unlock(reinterpret_cast<void*>(page), page_size);
83  histogram.erase(it);
84  }
85  }
86  }
87 
88  // Get number of locked pages for diagnostics
90  {
91  boost::mutex::scoped_lock lock(mutex);
92  return histogram.size();
93  }
94 
95 private:
96  Locker locker;
97  boost::mutex mutex;
99  // map of page base address to lock count
100  typedef std::map<size_t, int> Histogram;
102 };
103 
104 
110 {
111 public:
115  bool Lock(const void* addr, size_t len);
119  bool Unlock(const void* addr, size_t len);
120 };
121 
133 class LockedPageManager : public LockedPageManagerBase<MemoryPageLocker>
134 {
135 public:
137  {
140  }
141 
142 private:
144 
145  static void CreateInstance()
146  {
147  // Using a local static instance guarantees that the object is initialized
148  // when it's first needed and also deinitialized after all objects that use
149  // it are done with it. I can think of one unlikely scenario where we may
150  // have a static deinitialization order/problem, but the check in
151  // LockedPageManagerBase's destructor helps us detect if that ever happens.
152  static LockedPageManager instance;
153  LockedPageManager::_instance = &instance;
154  }
155 
157  static boost::once_flag init_flag;
158 };
159 
160 //
161 // Functions for directly locking/unlocking memory objects.
162 // Intended for non-dynamically allocated structures.
163 //
164 template <typename T>
165 void LockObject(const T& t)
166 {
167  LockedPageManager::Instance().LockRange((void*)(&t), sizeof(T));
168 }
169 
170 template <typename T>
171 void UnlockObject(const T& t)
172 {
173  memory_cleanse((void*)(&t), sizeof(T));
174  LockedPageManager::Instance().UnlockRange((void*)(&t), sizeof(T));
175 }
176 
177 #endif // BITCOIN_SUPPORT_PAGELOCKER_H
static LockedPageManager * _instance
Definition: pagelocker.h:156
boost::mutex mutex
Definition: pagelocker.h:97
std::map< size_t, int > Histogram
Definition: pagelocker.h:100
bool Unlock(const void *addr, size_t len)
Definition: pagelocker.cpp:59
void UnlockObject(const T &t)
Definition: pagelocker.h:171
void memory_cleanse(void *ptr, size_t len)
Definition: cleanse.cpp:10
void LockRange(void *p, size_t size)
Definition: pagelocker.h:44
LockedPageManagerBase(size_t page_size)
Definition: pagelocker.h:31
bool Lock(const void *addr, size_t len)
Definition: pagelocker.cpp:50
void UnlockRange(void *p, size_t size)
Definition: pagelocker.h:66
static void CreateInstance()
Definition: pagelocker.h:145
static LockedPageManager & Instance()
Definition: pagelocker.h:136
static boost::once_flag init_flag
Definition: pagelocker.h:157
void LockObject(const T &t)
Definition: pagelocker.h:165