jens@0
|
1 |
/*
|
jens@0
|
2 |
* MemoryMap.cpp
|
jens@0
|
3 |
* Ottoman
|
jens@0
|
4 |
*
|
jens@0
|
5 |
* Created by Jens Alfke on 9/17/09.
|
jens@0
|
6 |
* Copyright 2009 Jens Alfke. All rights reserved.
|
jens@0
|
7 |
* BSD-Licensed: See the file "LICENSE.txt" for details.
|
jens@0
|
8 |
*/
|
jens@0
|
9 |
|
jens@0
|
10 |
#include "MemoryMap.h"
|
jens@0
|
11 |
|
jens@0
|
12 |
#include <errno.h>
|
jens@0
|
13 |
#include <stdio.h>
|
jens@0
|
14 |
#include <sys/mman.h>
|
jens@0
|
15 |
|
jens@0
|
16 |
namespace Mooseyard {
|
jens@0
|
17 |
|
jens@0
|
18 |
MemoryMap::~MemoryMap() {
|
jens@0
|
19 |
for (int i=0; i<_nRegions; i++)
|
jens@0
|
20 |
delete _regions[i];
|
jens@0
|
21 |
free(_regions);
|
jens@0
|
22 |
}
|
jens@0
|
23 |
|
jens@0
|
24 |
void MemoryMap::mapRegion (off_t pos, size_t length) {
|
jens@0
|
25 |
size_t end = pos+length;
|
jens@0
|
26 |
for (int i=0; i<_nRegions; i++) {
|
jens@0
|
27 |
Region *region = _regions[i];
|
jens@0
|
28 |
if (region->position() <= pos) {
|
jens@0
|
29 |
if (end <= region->end())
|
jens@0
|
30 |
return; // found an existing region covering this range
|
jens@0
|
31 |
else if (region->setLength(end - region->position()))
|
jens@0
|
32 |
return; // able to grow the existing region
|
jens@0
|
33 |
}
|
jens@0
|
34 |
}
|
jens@0
|
35 |
|
jens@0
|
36 |
// No existing region, so add a new one:
|
jens@0
|
37 |
Region *region = new Region(_file, pos,length);
|
jens@0
|
38 |
_regions = (Region**) realloc(_regions, (_nRegions+1)*sizeof(*_regions));
|
jens@0
|
39 |
_regions[_nRegions++] = region;
|
jens@0
|
40 |
}
|
jens@0
|
41 |
|
jens@0
|
42 |
const void* MemoryMap::_at (off_t pos) const {
|
jens@0
|
43 |
for (int i=0; i<_nRegions; i++) {
|
jens@0
|
44 |
const void *ptr = _regions[i]->mappedPosition(pos);
|
jens@0
|
45 |
if (ptr)
|
jens@0
|
46 |
return ptr;
|
jens@0
|
47 |
}
|
jens@0
|
48 |
return NULL;
|
jens@0
|
49 |
}
|
jens@0
|
50 |
|
jens@0
|
51 |
const void* MemoryMap::mappedPosition (off_t pos) const {
|
jens@0
|
52 |
const void *result = _at(pos);
|
jens@0
|
53 |
if (!result)
|
jens@0
|
54 |
throw File::Error("No memory mapped at this position");
|
jens@0
|
55 |
return result;
|
jens@0
|
56 |
}
|
jens@0
|
57 |
|
jens@0
|
58 |
|
jens@0
|
59 |
|
jens@0
|
60 |
|
jens@0
|
61 |
MemoryMap::Region::Region (File* file, off_t position, size_t length)
|
jens@0
|
62 |
:_file(file),
|
jens@0
|
63 |
_position(position),
|
jens@0
|
64 |
_length (length),
|
jens@0
|
65 |
_start( (const uint8_t*) ::mmap(NULL, length, PROT_READ, MAP_PRIVATE, file->_fd, position) )
|
jens@0
|
66 |
{
|
jens@0
|
67 |
printf("File#%i: Mapped (%6llu -- %6llu) --> %p\n", file->_fd, _position, end(), _start);
|
jens@0
|
68 |
if (_start==NULL || _start == MAP_FAILED) {
|
jens@0
|
69 |
_start = NULL;
|
jens@0
|
70 |
throw File::Error(errno, strerror(errno));
|
jens@0
|
71 |
}
|
jens@0
|
72 |
}
|
jens@0
|
73 |
|
jens@0
|
74 |
MemoryMap::Region::~Region() {
|
jens@0
|
75 |
if (_start) {
|
jens@0
|
76 |
printf("File#%i: Unmapped (%6llu -- %6llu) from %p\n", _file->_fd, _position, end(), _start);
|
jens@0
|
77 |
::munmap((void*)_start,_length);
|
jens@0
|
78 |
}
|
jens@0
|
79 |
}
|
jens@0
|
80 |
|
jens@0
|
81 |
bool MemoryMap::Region::setLength (size_t length) {
|
jens@0
|
82 |
if (length != _length) {
|
jens@0
|
83 |
printf("File#%i: Resiging (%6llu -- %6llu) from %lu to %lu ...",
|
jens@0
|
84 |
_file->_fd, _position, end(), _length,length);
|
jens@0
|
85 |
if (::mmap((void*)_start, length, PROT_READ, MAP_PRIVATE | MAP_FIXED, _file->_fd, _position) == MAP_FAILED) {
|
jens@0
|
86 |
printf("failed! errno=%i\n", errno);
|
jens@0
|
87 |
return false;
|
jens@0
|
88 |
}
|
jens@0
|
89 |
printf("OK\n");
|
jens@0
|
90 |
_length = length;
|
jens@0
|
91 |
}
|
jens@0
|
92 |
return true;
|
jens@0
|
93 |
}
|
jens@0
|
94 |
|
jens@0
|
95 |
const void* MemoryMap::Region::mappedPosition (off_t pos) {
|
jens@0
|
96 |
if (pos >= _position && pos < end())
|
jens@0
|
97 |
return _start + (pos-_position);
|
jens@0
|
98 |
else
|
jens@0
|
99 |
return NULL;
|
jens@0
|
100 |
}
|
jens@0
|
101 |
|
jens@0
|
102 |
|
jens@0
|
103 |
}
|