jmemorymap.cpp 5.3 KB
/***************************************************************************
 *   Copyright (C) 2005 by Jeff Ferr                                       *
 *   root@sat                                                              *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "Stdafx.h"
#include "jmemorymap.h"
#include "jmemoryexception.h"

namespace jshared {

MemoryMap::MemoryMap(std::string filename_, jmemory_flags_t flags_, jmemory_permission_t perms_, bool private_):
	jcommon::Object()
{
	jcommon::Object::SetClassName("jshared::MemoryMap");

	_permission = perms_;

#ifdef _WIN32
#else
	_is_open = false;
	
	uint32_t f = 0;

	if ((flags_ & JMF_OPEN) != 0) {
		f = (jmemory_flags_t)(f | 0);
	}

	if ((flags_ & JMF_CREAT) != 0) {
		f = (jmemory_flags_t)(f | O_CREAT | O_EXCL | O_TRUNC);
	}

	_fd = open(filename_.c_str(), f | O_RDWR | O_LARGEFILE, (mode_t)0600); 
	
	if (_fd < 0) {
		if ((f | JMF_CREAT) != 0) {
			throw MemoryException("Error creating a shared file");
		} else {
			throw MemoryException("Error opening a shared file");
		}
	}
	
	if ((flags_ & JMF_CREAT) != 0) {
		if (write(_fd, "", 1) < 0) {
			throw MemoryException("Error creating shared memory");
		}
	}

	if (fstat(_fd, &_stats) < 0) {
		throw MemoryException("Error getting stats of shared file");
	}

	uint32_t t = 0;

	if ((perms_ & JMP_EXEC) != 0) {
		t = (jmemory_permission_t)(t | PROT_EXEC);
	}

	if ((perms_ & JMP_READ) != 0) {
		t = (jmemory_permission_t)(t | PROT_READ);
	}

	if ((perms_ & JMP_WRITE) != 0) {
		t = (jmemory_permission_t)(t | PROT_WRITE);
	}

	if ((perms_ & JMP_READ_WRITE) != 0) {
		t = (jmemory_permission_t)(t | PROT_READ | PROT_WRITE);
	}

	if (private_ == true) {
		_start = mmap((caddr_t)0, _stats.st_size, t, MAP_PRIVATE, _fd, 0);
	} else {
		_start = mmap((caddr_t)0, _stats.st_size, t, MAP_SHARED, _fd, 0);
	}

	if (_start == MAP_FAILED) {
		throw MemoryException("Creating memory map failed");
	}
	
	_is_open = true;
#endif
}

MemoryMap::~MemoryMap()
{
	Release();
}

int64_t MemoryMap::Get(char *data_, int64_t size_, int64_t offset_)
{
#ifdef _WIN32
	return 0LL;
#else
	// TODO:: tratar mmap2 com offset
	if (size_ > _stats.st_size) {
		// throw MemoryException("Size cause overflow in memory");
		
		size_ = _stats.st_size;
	}

	memcpy(data_, _start, size_);
	
    return size_;
#endif
}

int64_t MemoryMap::Put(const char *data_, int64_t size_, int64_t offset_)
{
#ifdef _WIN32
	return 0LL;
#else
	// TODO:: tratar mmap2 com offset
	if (size_ > _stats.st_size) {
		throw MemoryException("Size cause overflow in memory");
	}

	memcpy(_start, data_, size_);
	
	return size_;
#endif
}

jmemory_permission_t MemoryMap::GetPermission()
{
	return _permission;
}
	
void MemoryMap::SetPermission(jmemory_permission_t perms_)
{
	_permission = perms_;

#ifdef _WIN32
#else
	unsigned int t = 0;

	if ((_permission & JMP_EXEC) != 0) {
		t = (jmemory_permission_t)(t | PROT_EXEC);
	}

	if ((_permission & JMP_READ) != 0) {
		t = (jmemory_permission_t)(t | PROT_READ);
	}

	if ((_permission & JMP_WRITE) != 0) {
		t = (jmemory_permission_t)(t | PROT_WRITE);
	}

	if ((_permission & JMP_READ_WRITE) != 0) {
		t = (jmemory_permission_t)(t | PROT_READ | PROT_WRITE);
	}

	if ((_permission & JMP_NONE) != 0) {
		t = (jmemory_permission_t)(t | PROT_NONE);
	}

	if (mprotect(_start, _stats.st_size, t) < 0) {
		throw MemoryException("Set permission failed");
	}
#endif
}

int64_t MemoryMap::GetSize()
{
#ifdef _WIN32
	return 0LL;
#else
	return (int64_t)_stats.st_size;
#endif
}

void MemoryMap::Release()
{
	if (_is_open == false) {
		return;
	}
	
#ifdef _WIN32
#else
	int r = munmap(_start, _stats.st_size);
	
	if (r < 0) {
		if (errno == EINVAL) {
			throw MemoryException("We don't like start or length or offset");
		} else if (errno == EAGAIN) {
			throw MemoryException("The file has been locked, or too much memory has been locked");
		} else if (errno == ENOMEM) {
			throw MemoryException("No memory is available, or the process's maximum number of mappings would have been exceeded");
		// } else if (errno == SIGSEGV) {
		// 	throw MemoryException("Attempted write into a region specified to mmap as read-only");
		} else {
			throw MemoryException("Release failed");
		}
	}

	if (close(_fd) < 0) {
	}
#endif
}

}