#include "SharedMemory.h"

#include "RandomUtils.h"

#ifdef __linux__
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif

void SharedMemory::allocate(const std::string& namePrefix, std::size_t size)
{
	createFile(namePrefix);

	if (!mIsValid)
	{
		return;
	}

#ifdef __linux__
	int ret{-1};
	do {
		ret = ftruncate(mFileDescriptor, size);
	} while (ret < 0 && errno == EINTR);

	if (ret < 0)
	{
		close(mFileDescriptor);
		mIsValid = false;
	}
#endif
}

int SharedMemory::getFileDescriptor() const
{
	return mFileDescriptor;
}

bool SharedMemory::isValid() const
{
	return mIsValid;
}

void SharedMemory::createFile(const std::string& namePrefix)
{
#ifdef __linux__
	unsigned retries = 100;
	do {
		const auto name = getRandomName(namePrefix);
		--retries;

		const int fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
		if (fd >= 0)
		{
			shm_unlink(name.c_str());
			mFileDescriptor = fd;
			mIsValid = true;
			break;
		}
	} while (retries > 0 && errno == EEXIST);
#endif
}

std::string SharedMemory::getRandomName(const std::string& namePrefix) const
{
	std::string randomSuffix;
	for (const auto entry : RandomUtils::getRandomVecUnsigned(6))
	{
		randomSuffix += std::to_string(entry);
	}
	return namePrefix + randomSuffix;
}
