AuroraRuntime/Source/Process/AuProcessSectionViewReserved.Unix.cpp

393 lines
13 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuProcessSectionViewReserved.Unix.cpp
Date: 2022-11-15
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuProcessSectionViewReserved.Unix.hpp"
#include "Process.hpp"
#include <Source/IO/FS/FileStream.Unix.hpp>
#include "AuProcessSectionFileMapView.Unix.hpp"
#include <Source/IO/IPC/AuIPCHandle.hpp>
#include <Source/IO/IPC/AuIPCMemory.Unix.hpp>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
namespace Aurora::Process
{
ProcessSectionViewReserved::~ProcessSectionViewReserved()
{
if (this->pBaseAddress)
{
::munmap(this->pBaseAddress, this->uMaxLength);
}
}
AuUInt ProcessSectionViewReserved::GetStart()
{
return (AuUInt)this->pBaseAddress;
}
AuUInt ProcessSectionViewReserved::GetEnd()
{
return this->GetStart() + this->uMaxLength;
}
bool ProcessSectionViewReserved::Init(AuUInt uLength)
{
this->uMaxLength = uLength;
if (!(this->pBaseAddress = (char *)::mmap(0, uLength, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0)))
{
this->pBaseAddress = (char *)::mmap(0, uLength, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
}
return bool(this->pBaseAddress);
}
void ProcessSectionViewReserved::Release(AuUInt address)
{
auto uOffset = address - (AuUInt)this->pBaseAddress;
this->ReleaseAddress(uOffset);
}
void *ProcessSectionViewReserved::MapAddress(AuUInt uOffset, AuUInt uLength,
AuUInt prot, AuUInt share, int fd, AuUInt offset)
{
bool bCompleteBlock {};
AuUInt uFoundOffset {};
if (!this->GetAddress(uOffset, uLength, uFoundOffset, bCompleteBlock))
{
SysPushErrorMemory("Reserved address space has no available space");
return {};
}
auto pRet = ::mmap(this->pBaseAddress + uFoundOffset,
uLength,
prot,
share | MAP_FIXED,
fd,
offset);
if (!pRet)
{
SysPushErrorMemory("mmap failed");
ReleaseAddress(uFoundOffset);
return {};
}
return pRet;
}
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::Allocate(AuUInt uLength)
{
return this->AllocateEx(uLength, -1);
}
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::MapFileByPath(const AuString &str,
AuUInt64 uOffset,
AuUInt uLength,
AuFS::EFileOpenMode mode,
AuFS::EFileAdvisoryLockLevel sectionLock)
{
return this->MapFileByPathEx(-1, str, uOffset, uLength, mode, sectionLock);
}
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::MapFileByObject(const AuSPtr<IO::IIOHandle> &pIOHandle,
AuUInt64 uOffset,
AuUInt uLength,
AuFS::EFileOpenMode mode,
AuFS::EFileAdvisoryLockLevel processLockLevel)
{
return this->MapFileByObjectEx(-1, pIOHandle, uOffset, uLength, mode, processLockLevel);
}
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::MapIPCMemory(const AuString &handleString,
AuUInt64 uOffset,
AuUInt uLength,
AuFS::EFileOpenMode mode)
{
return this->MapIPCMemoryEx(-1, handleString, uOffset, uLength, mode);
}
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::AllocateEx(AuUInt uLength, AuUInt uOffset)
{
PageTable table {};
table.NX = true;
table.readable = true;
table.writable = true;
return this->AllocateEx2(uLength, uOffset, table);
}
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::AllocateEx2(AuUInt uLength, AuUInt uOffset, PageTable permissions)
{
if (!uLength)
{
SysPushErrorArg("invalid uLength");
return {};
}
AuUInt32 uProtFlags {};
if (!permissions.NX)
{
uProtFlags |= PROT_EXEC;
}
if (permissions.writable)
{
uProtFlags |= PROT_WRITE;
}
if (permissions.readable)
{
uProtFlags |= PROT_READ;
}
auto map = this->MapAddress(uOffset, uLength, uProtFlags, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
if (map == MAP_FAILED)
{
SysPushErrorIO();
return {};
}
auto pNewObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map),
uLength,
false);
if (!pNewObject)
{
SysPushErrorMem();
return {};
}
pNewObject->pSharedSectionHint = AuSharedFromThis();
return pNewObject;
}
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::MapFileByPathEx(AuUInt viewOffset,
const AuString &str,
AuUInt64 uOffset,
AuUInt uLength,
Aurora::IO::FS::EFileOpenMode mode,
Aurora::IO::FS::EFileAdvisoryLockLevel processLockLevel)
{
auto pHandle = AuIO::IOHandleShared();
if (!pHandle)
{
SysPushErrorMemory();
return nullptr;
}
AuIO::IIOHandle::HandleCreate createhandle(str);
createhandle.eAdvisoryLevel = AuFS::EFileAdvisoryLockLevel::eNoSafety;
createhandle.eMode = mode;
createhandle.bFailIfNonEmptyFile = false;
createhandle.bDirectIOMode = false;
createhandle.bAsyncHandle = false;
if (!pHandle->InitFromPath(createhandle))
{
return nullptr;
}
return this->MapFileByObjectEx(viewOffset, pHandle, uOffset, uLength, mode, processLockLevel);
}
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::MapFileByObjectEx(AuUInt viewOffset,
const AuSPtr<IO::IIOHandle> &pIOHandle,
AuUInt64 uOffset,
AuUInt uLength,
Aurora::IO::FS::EFileOpenMode mode,
Aurora::IO::FS::EFileAdvisoryLockLevel processLockLevel)
{
if (!pIOHandle)
{
return {};
}
if (!uLength)
{
SysPushErrorArg("invalid uLength");
return {};
}
if (this->IsAddressValid(viewOffset))
{
SysPushErrorMemory("Address space is in use");
return {};
}
int fd = ::dup(pIOHandle->GetOSHandle());
if (fd == -1)
{
SysPushErrorIO();
return {};
}
// TODO (Reece): lock garbage
int prot {};
switch (mode)
{
case AuFS::EFileOpenMode::eRead:
{
prot = PROT_READ;
break;
}
case AuFS::EFileOpenMode::eWrite:
case AuFS::EFileOpenMode::eReadWrite:
{
prot = PROT_READ | PROT_WRITE;
break;
}
default:
SysPushErrorGeneric();
return {};
};
auto map = this->MapAddress(viewOffset, uLength, prot, MAP_SHARED, fd, uOffset);
if (map == MAP_FAILED)
{
SysPushErrorIO();
::close(fd);
return {};
}
auto pNewObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map),
uLength,
false,
fd);
if (!pNewObject)
{
SysPushErrorMem();
::close(fd);
return {};
}
pNewObject->pSharedSectionHint = AuSharedFromThis();
return pNewObject;
}
AuSPtr<IProcessSectionMapView> ProcessSectionViewReserved::MapIPCMemoryEx(AuUInt viewOffset,
const AuString &handleString,
AuUInt64 uOffset,
AuUInt uLength,
Aurora::IO::FS::EFileOpenMode mode)
{
AuIPC::IPCHandle handle;
if (!uLength)
{
SysPushErrorArg("invalid uLength");
return {};
}
if (this->IsAddressValid(viewOffset))
{
SysPushErrorMemory("Address space is in use");
return {};
}
if (!handle.FromString(handleString))
{
SysPushErrorParseError("Invalid handle: {}", handleString);
return {};
}
auto val = handle.GetToken(AuIPC::EIPCHandleType::eIPCMemory, 0);
if (!val)
{
SysPushErrorParseError("Invalid handle: {}", handleString);
return {};
}
auto actualLength = val->token.word;
auto path = AuIPC::GetServerPath(val->token);
if (actualLength < uOffset + uLength)
{
SysPushErrorIO("Out of range");
return {};
}
int fd = ::shm_open(path.c_str(), O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1)
{
SysPushErrorIO();
return {};
}
// TODO (Reece): lock garbage ( ??? )
int prot {};
switch (mode)
{
case AuFS::EFileOpenMode::eRead:
{
prot = PROT_READ;
break;
}
case AuFS::EFileOpenMode::eWrite:
case AuFS::EFileOpenMode::eReadWrite:
{
prot = PROT_READ | PROT_WRITE;
break;
}
default:
SysPushErrorGeneric();
return {};
};
auto map = this->MapAddress(viewOffset, uLength, prot, MAP_SHARED, fd, uOffset);
if (map == MAP_FAILED)
{
SysPushErrorIO();
::close(fd);
return {};
}
auto pNewObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map),
uLength,
false,
fd);
if (!pNewObject)
{
SysPushErrorMem();
::close(fd);
return {};
}
pNewObject->pSharedSectionHint = AuSharedFromThis();
return pNewObject;
}
AuList<AuPair<AuUInt, AuUInt>> ProcessSectionViewReserved::GetAllocations()
{
AU_LOCK_GUARD(this->spinlock);
return this->allocations;
}
AUKN_SYM AuSPtr<IProcessSectionView> ReserveAddressSpace(AuUInt uLength)
{
auto &platform = AuSwInfo::GetPlatformInfo();
auto pSectionView = AuMakeShared<ProcessSectionViewReserved>();
if (!pSectionView)
{
SysPushErrorMemory();
return {};
}
if (!pSectionView->Init(uLength))
{
SysPushErrorMemory();
return {};
}
return pSectionView;
}
}