Electroneum
Toggle main menu visibility
Loading...
Searching...
No Matches
mlocker.cpp
Go to the documentation of this file.
1
// Copyright (c) 2018, The Monero Project
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification, are
6
// permitted provided that the following conditions are met:
7
//
8
// 1. Redistributions of source code must retain the above copyright notice, this list of
9
// conditions and the following disclaimer.
10
//
11
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
12
// of conditions and the following disclaimer in the documentation and/or other
13
// materials provided with the distribution.
14
//
15
// 3. Neither the name of the copyright holder nor the names of its contributors may be
16
// used to endorse or promote products derived from this software without specific
17
// prior written permission.
18
//
19
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
#if defined __GNUC__ && !defined _WIN32
30
#define HAVE_MLOCK 1
31
#endif
32
33
#include <unistd.h>
34
#if defined HAVE_MLOCK
35
#include <sys/mman.h>
36
#endif
37
#include "
misc_log_ex.h
"
38
#include "
syncobj.h
"
39
#include "
mlocker.h
"
40
41
#include <atomic>
42
43
#undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
44
#define ELECTRONEUM_DEFAULT_LOG_CATEGORY "mlocker"
45
46
// did an mlock operation previously fail? we only
47
// want to log an error once and be done with it
48
static
std::atomic<bool> previously_failed{
false
};
49
50
static
size_t
query_page_size()
51
{
52
#if defined HAVE_MLOCK
53
long
ret = sysconf(_SC_PAGESIZE);
54
if
(ret <= 0)
55
{
56
MERROR
(
"Failed to determine page size"
);
57
return
0;
58
}
59
return
ret;
60
#else
61
#warning Missing query_page_size implementation
62
#endif
63
return
0;
64
}
65
66
static
void
do_lock(
void
*ptr,
size_t
len)
67
{
68
#if defined HAVE_MLOCK
69
int
ret = mlock(ptr, len);
70
if
(ret < 0 && !previously_failed.exchange(
true
))
71
MERROR
(
"Error locking page at "
<< ptr <<
": "
<< strerror(errno) <<
", subsequent mlock errors will be silenced"
);
72
#else
73
#warning Missing do_lock implementation
74
#endif
75
}
76
77
static
void
do_unlock(
void
*ptr,
size_t
len)
78
{
79
#if defined HAVE_MLOCK
80
int
ret = munlock(ptr, len);
81
// check whether we previously failed, but don't set it, this is just
82
// to pacify the errors of mlock()ing failed, in which case unlocking
83
// is also not going to work of course
84
if
(ret < 0 && !previously_failed.load())
85
MERROR
(
"Error unlocking page at "
<< ptr <<
": "
<< strerror(errno));
86
#else
87
#warning Missing implementation of page size detection
88
#endif
89
}
90
91
namespace
epee
92
{
93
size_t
mlocker::page_size = 0;
94
size_t
mlocker::num_locked_objects = 0;
95
96
boost::mutex &mlocker::mutex()
97
{
98
static
boost::mutex *vmutex =
new
boost::mutex();
99
return
*vmutex;
100
}
101
std::map<size_t, unsigned int> &mlocker::map()
102
{
103
static
std::map<size_t, unsigned int> *vmap =
new
std::map<size_t, unsigned int>();
104
return
*vmap;
105
}
106
107
size_t
mlocker::get_page_size
()
108
{
109
CRITICAL_REGION_LOCAL
(mutex());
110
if
(page_size == 0)
111
page_size = query_page_size();
112
return
page_size;
113
}
114
115
mlocker::mlocker
(
void
*ptr,
size_t
len): ptr(ptr), len(len)
116
{
117
lock
(ptr, len);
118
}
119
120
mlocker::~mlocker
()
121
{
122
try
{
unlock
(ptr, len); }
123
catch
(...) {
/* ignore and do not propagate through the dtor */
}
124
}
125
126
void
mlocker::lock
(
void
*ptr,
size_t
len)
127
{
128
TRY_ENTRY
();
129
130
size_t
page_size =
get_page_size
();
131
if
(page_size == 0)
132
return
;
133
134
CRITICAL_REGION_LOCAL
(mutex());
135
const
size_t
first = ((
uintptr_t
)ptr) / page_size;
136
const
size_t
last = (((
uintptr_t
)ptr) + len - 1) / page_size;
137
for
(
size_t
page = first; page <= last; ++page)
138
lock_page(page);
139
++num_locked_objects;
140
141
CATCH_ENTRY_L1
(
"mlocker::lock"
,
void
());
142
}
143
144
void
mlocker::unlock
(
void
*ptr,
size_t
len)
145
{
146
TRY_ENTRY
();
147
148
size_t
page_size =
get_page_size
();
149
if
(page_size == 0)
150
return
;
151
CRITICAL_REGION_LOCAL
(mutex());
152
const
size_t
first = ((
uintptr_t
)ptr) / page_size;
153
const
size_t
last = (((
uintptr_t
)ptr) + len - 1) / page_size;
154
for
(
size_t
page = first; page <= last; ++page)
155
unlock_page(page);
156
--num_locked_objects;
157
158
CATCH_ENTRY_L1
(
"mlocker::lock"
,
void
());
159
}
160
161
size_t
mlocker::get_num_locked_pages
()
162
{
163
CRITICAL_REGION_LOCAL
(mutex());
164
return
map().size();
165
}
166
167
size_t
mlocker::get_num_locked_objects
()
168
{
169
CRITICAL_REGION_LOCAL
(mutex());
170
return
num_locked_objects;
171
}
172
173
void
mlocker::lock_page(
size_t
page)
174
{
175
std::pair<std::map<size_t, unsigned int>::iterator,
bool
> p = map().insert(std::make_pair(page, 1));
176
if
(p.second)
177
{
178
do_lock((
void
*)(page * page_size), page_size);
179
}
180
else
181
{
182
++p.first->second;
183
}
184
}
185
186
void
mlocker::unlock_page(
size_t
page)
187
{
188
std::map<size_t, unsigned int>::iterator i = map().find(page);
189
if
(i == map().end())
190
{
191
MERROR
(
"Attempt to unlock unlocked page at "
<< (
void
*)(page * page_size));
192
}
193
else
194
{
195
if
(!--i->second)
196
{
197
map().erase(i);
198
do_unlock((
void
*)(page * page_size), page_size);
199
}
200
}
201
}
202
}
epee::mlocker::get_num_locked_objects
static size_t get_num_locked_objects()
Definition
mlocker.cpp:167
epee::mlocker::get_num_locked_pages
static size_t get_num_locked_pages()
Definition
mlocker.cpp:161
epee::mlocker::lock
static void lock(void *ptr, size_t len)
Definition
mlocker.cpp:126
epee::mlocker::unlock
static void unlock(void *ptr, size_t len)
Definition
mlocker.cpp:144
epee::mlocker::~mlocker
~mlocker()
Definition
mlocker.cpp:120
epee::mlocker::get_page_size
static size_t get_page_size()
Definition
mlocker.cpp:107
epee::mlocker::mlocker
mlocker(void *ptr, size_t len)
Definition
mlocker.cpp:115
misc_log_ex.h
MERROR
#define MERROR(x)
Definition
misc_log_ex.h:73
CATCH_ENTRY_L1
#define CATCH_ENTRY_L1(lacation, return_val)
Definition
misc_log_ex.h:166
TRY_ENTRY
#define TRY_ENTRY()
Definition
misc_log_ex.h:151
mlocker.h
epee
Definition
ado_db_helper.h:67
uintptr_t
_W64 unsigned int uintptr_t
Definition
stdint.h:165
syncobj.h
CRITICAL_REGION_LOCAL
#define CRITICAL_REGION_LOCAL(x)
Definition
syncobj.h:228
contrib
epee
src
mlocker.cpp
Generated on
for Electroneum by
1.17.0