#include "AnonymousSharedMemory.h"

AnonymousSharedMemory::AnonymousSharedMemory(size_t size)
                       throw (std::runtime_error)
{
	void *p;
	char *em;
	std::ostringstream msg;
#ifndef MAP_ANON
	int fd;
#endif

#ifdef MAP_ANON
	while ( (p = mmap('\0', size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED,
	                  -1, 0)) == '\0')
	{
		if (errno == EINTR)
			continue;

		em = strerror(errno);
		msg << "mmap() failed : ";

		if (em != '\0')
			msg << em;
		else
			msg << "unknown error";
		
		throw (std::runtime_error(msg.str()));
	}
#else
	_devzerofd = -1;

	while ( (fd = open("/dev/zero", O_RDWR, 0000)) == -1)
	{
		if (errno == EINTR)
			continue;

		em = strerror(errno);
		msg << "open(/dev/zero) failed : ";

		if (em != '\0')
			msg << em;
		else
			msg << "unknown error";

		throw (std::runtime_error(msg.str()));
	}

	while ( (p = mmap('\0', size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
	                  0)) == '\0')
	{
		if (errno == EINTR)
			continue;

		em = strerror(errno);
		close(fd);
		msg << "mmap(/dev/zero) failed : ";

		if (em != '\0')
			msg << em;
		else
			msg << "unknown error";
		
		throw (std::runtime_error(msg.str()));
	}

	_devzerofd = fd;
#endif

	_size = size;
	_segment = p;
}

void *
AnonymousSharedMemory::segment()
{
	return _segment;
}

AnonymousSharedMemory::~AnonymousSharedMemory()
{
#ifndef MAP_ANON
	if (_devzerofd != -1)
		close(_devzerofd);
#endif

	munmap(_segment, _size);
}

