src/MemoryMap.cpp
author Jens Alfke <jens@mooseyard.com>
Sun Sep 20 15:14:12 2009 -0700 (2009-09-20)
changeset 0 31a43d94cc26
child 2 851de24ecb61
permissions -rw-r--r--
First official checkin.
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
}