Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

open-axiom repository from github

24005 views
1
// Copyright (C) 2010-2013, Gabriel Dos Reis.
2
// All rights reserved.
3
//
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions are
6
// met:
7
//
8
// - Redistributions of source code must retain the above copyright
9
// notice, this list of conditions and the following disclaimer.
10
//
11
// - Redistributions in binary form must reproduce the above copyright
12
// notice, this list of conditions and the following disclaimer in
13
// the documentation and/or other materials provided with the
14
// distribution.
15
//
16
// - Neither the name of The Numerical Algorithms Group Ltd. nor the
17
// names of its contributors may be used to endorse or promote products
18
// derived from this software without specific prior written permission.
19
//
20
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
24
// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32
// --%: Gabriel Dos Reis.
33
34
#include <open-axiom/storage>
35
#include <open-axiom/FileMapping>
36
#ifdef HAVE_SYS_TYPES_H
37
# include <sys/types.h>
38
#endif
39
#ifdef HAVE_SYS_STAT_H
40
# include <sys/stat.h>
41
#endif
42
#include <sys/types.h>
43
#ifdef HAVE_FCNTL_H
44
# include <fcntl.h>
45
#endif
46
#ifdef HAVE_UNISTD_H
47
# include <unistd.h>
48
#endif
49
#ifdef HAVE_SYS_MMAN_H
50
# include <sys/mman.h>
51
#endif
52
#ifdef OPENAXIOM_MS_WINDOWS_HOST
53
# include <windows.h>
54
#endif
55
#include <errno.h>
56
#include <stdlib.h>
57
#include <string.h>
58
59
namespace OpenAxiom {
60
// ----------------
61
// -- SystemError --
62
// ----------------
63
SystemError::SystemError(const std::string& s) : text(s) { }
64
65
SystemError::~SystemError() { }
66
67
const std::string&
68
SystemError::message() const {
69
return text;
70
}
71
72
void
73
filesystem_error(const std::string& s) {
74
throw SystemError(s);
75
}
76
77
namespace Memory {
78
// Return storage page allocation unit in byte count.
79
size_t page_size() {
80
#if defined(OPENAXIOM_MS_WINDOWS_HOST)
81
SYSTEM_INFO si = { };
82
GetSystemInfo(&si);
83
return si.dwPageSize;
84
#elif defined(HAVE_UNISTD_H)
85
return sysconf(_SC_PAGESIZE);
86
#else
87
// Well, we have to return a number.
88
return 4096;
89
#endif
90
}
91
92
// Subroutine of os_acquire_raw_memory. Attempt to acquire
93
// storage from the host OS. Return null on failure.
94
static inline Pointer
95
os_allocate_read_write_raw_memory(size_t nbytes) {
96
#if defined(OPENAXIOM_MS_WINDOWS_HOST)
97
return VirtualAlloc(Pointer(), nbytes,
98
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
99
#elif defined(HAVE_SYS_MMAN_H)
100
Pointer p = mmap(Pointer(), nbytes, PROT_READ | PROT_WRITE,
101
MAP_PRIVATE | OPENAXIOM_MM_ANONYMOUS_MAP_FLAG,
102
-1, 0);
103
return p == MAP_FAILED ? Pointer() : p;
104
#else
105
return malloc(byte_count);
106
#endif
107
}
108
109
Pointer
110
os_acquire_raw_memory(size_t nbytes) {
111
Pointer p = os_allocate_read_write_raw_memory(nbytes);
112
if (p == nullptr)
113
throw SystemError("cannot acquire more memory");
114
return memset(p, nbytes, 0);
115
}
116
117
void
118
os_release_raw_memory(Pointer p, size_t n) {
119
#if defined(OPENAXIOM_MS_WINDOWS_HOST)
120
VirtualFree(p, 0, MEM_RELEASE);
121
#elif defined(HAVE_SYS_MMAN_H)
122
munmap(p, n);
123
#else
124
free(p);
125
#endif
126
}
127
128
// -------------
129
// -- Storage --
130
// -------------
131
struct Storage::Handle {
132
size_t extent; // count of allocated bytes
133
void* start; // beginning of usable address.
134
};
135
136
static inline Pointer
137
storage_end(Storage::Handle* h) {
138
return Storage::byte_address(h) + h->extent;
139
}
140
141
// Acquire storage chunk of at least `n' bytes.
142
// The result is a pointer to a storage object. That object
143
// `result' is constructed such that `begin(result)' points
144
// to the next allocatable address.
145
template<typename T>
146
static T*
147
acquire_storage_with_header(size_t n) {
148
n = Storage::round_up(n, page_size());
149
T* h = static_cast<T*>(os_acquire_raw_memory(n));
150
h->extent = n;
151
h->start = h + 1;
152
return h;
153
}
154
155
void
156
Storage::release(Handle* h) {
157
os_release_raw_memory(h, h->extent);
158
}
159
160
Pointer
161
Storage::begin(Handle* h) {
162
return h->start;
163
}
164
165
// -------------------------
166
// -- SinglyLinkedStorage --
167
// -------------------------
168
struct OneWayLinkHeader : Storage::Handle {
169
Handle* previous;
170
};
171
172
SinglyLinkedStorage::Handle*&
173
SinglyLinkedStorage::previous(Handle* h) {
174
return static_cast<OneWayLinkHeader*>(h)->previous;
175
}
176
177
// -------------------------
178
// -- DoublyLinkedStorage --
179
// -------------------------
180
struct TwoWayLinkHeader : Storage::Handle {
181
Handle* previous;
182
Handle* next;
183
};
184
185
static inline TwoWayLinkHeader*
186
two_way_link(Storage::Handle* h) {
187
return static_cast<TwoWayLinkHeader*>(h);
188
}
189
190
DoublyLinkedStorage::Handle*&
191
DoublyLinkedStorage::previous(Handle* h) {
192
return two_way_link(h)->previous;
193
}
194
195
DoublyLinkedStorage::Handle*&
196
DoublyLinkedStorage::next(Handle* h) {
197
return two_way_link(h)->next;
198
}
199
200
DoublyLinkedStorage::Handle*
201
DoublyLinkedStorage::acquire(size_t n, size_t a) {
202
// Add enough padding space for specified alignment.
203
const size_t overhead = round_up(sizeof (TwoWayLinkHeader), a);
204
TwoWayLinkHeader* h =
205
acquire_storage_with_header<TwoWayLinkHeader>(overhead + n);
206
h->start = byte_address (h) + overhead;
207
h->previous = nullptr;
208
h->next = nullptr;
209
return h;
210
}
211
212
// ------------------
213
// -- BlockStorage --
214
// ------------------
215
struct BlockHeader : OneWayLinkHeader {
216
Byte* available;
217
};
218
219
static inline BlockHeader*
220
block_header(BlockStorage::Handle* h) {
221
return static_cast<BlockHeader*>(h);
222
}
223
224
BlockStorage::Handle*
225
BlockStorage::acquire(size_t n, size_t a) {
226
const size_t overhead = round_up(sizeof (BlockHeader), a);
227
BlockHeader* h =
228
acquire_storage_with_header<BlockHeader>(overhead + n);
229
// Remember the next available address to allocate from.
230
h->available = byte_address(h) + overhead;
231
// That is also where the actual object storage starts.
232
h->start = h->available;
233
h->previous = nullptr;
234
return h;
235
}
236
237
Pointer
238
BlockStorage::next_address(Handle* h) {
239
return block_header(h)->available;
240
}
241
242
size_t
243
BlockStorage::room(Handle* h) {
244
return byte_address(storage_end(h)) - block_header(h)->available;
245
}
246
247
Pointer
248
BlockStorage::book(Handle* h, size_t n) {
249
BlockHeader* block = block_header(h);
250
void* const p = block->available;
251
block->available += n;
252
return p;
253
}
254
255
256
// -----------------
257
// -- FileMapping --
258
// -----------------
259
FileMapping::FileMapping(std::string path)
260
: start(), extent() {
261
#if defined(OPENAXIOM_MS_WINDOWS_HOST)
262
HANDLE file = CreateFile(path.c_str(), GENERIC_READ, 0, 0,
263
OPEN_EXISTING,
264
FILE_ATTRIBUTE_NORMAL, 0);
265
if (file == INVALID_HANDLE_VALUE)
266
filesystem_error("could not access file " + path);
267
HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0);
268
if (mapping == 0)
269
filesystem_error("could not map file " + path);
270
start = static_cast<Byte*>
271
(MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0));
272
extent = GetFileSize(file, 0);
273
CloseHandle(mapping);
274
CloseHandle(file);
275
#elif defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_MMAN_H) && defined(HAVE_FCNTL_H)
276
struct stat s;
277
errno = 0;
278
if (stat(path.c_str(), &s) < 0)
279
filesystem_error("could not access file " + path);
280
else if (!S_ISREG(s.st_mode))
281
filesystem_error(path + " is not a regular file");
282
int fd = open(path.c_str(), O_RDONLY);
283
if (fd < 0)
284
filesystem_error("could not open " + path);
285
start = static_cast<Byte*>
286
(mmap(Pointer(), s.st_size, PROT_READ, MAP_PRIVATE, fd, 0));
287
close(fd);
288
if (start == MAP_FAILED)
289
filesystem_error("could not map file " + path);
290
extent = s.st_size;
291
#else
292
# error "Don't know how to map a file on this platform"
293
#endif // OPENAXIOM_MS_WINDOWS_HOST
294
}
295
296
FileMapping::FileMapping(FileMapping&& f)
297
: start(f.start), extent(f.extent) {
298
f.start = nullptr;
299
f.extent = 0;
300
}
301
302
FileMapping::~FileMapping() {
303
if (start != nullptr) {
304
#if defined(OPENAXIOM_MS_WINDOWS_HOST)
305
UnmapViewOfFile(start);
306
#elif defined(HAVE_SYS_MMAN_H)
307
munmap(start, extent);
308
#else
309
# error "Don't know how to unmap a file on this platform"
310
#endif
311
}
312
}
313
}
314
}
315
316