AuroraRuntime/Source/IO/IPC/AuIPCPrimitives.NT.cpp

396 lines
9.7 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuIPCPrimitives.NT.cpp
Date: 2022-4-13
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "IPC.hpp"
#include "AuIPCHandle.hpp"
#include "AuIPCPrimitives.NT.hpp"
#include <Source/IO/Loop/LSMutex.hpp>
#include <Source/IO/Loop/LSSemaphore.hpp>
#include <Source/IO/Loop/LSEvent.hpp>
namespace Aurora::IO::IPC
{
#define IMPLEMENT_HANDLE \
IPC::IPCHandle handle_; \
AuString ExportToString() override \
{ \
return handle_.ToString(); \
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Mutexes
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct IPCMutexProxy : IPCMutex, Loop::ILoopSourceEx
{
IPCMutexProxy(HANDLE h, const IPCHandle &handle);
~IPCMutexProxy();
PROXY_INTERNAL_INTERFACE(mutex_)
IMPLEMENT_HANDLE
bool Unlock() override;
bool IsSignaledNoSpinIfUserland() override;
bool IsSignaled() override;
bool WaitOn(AuUInt32 timeout) override;
Loop::ELoopSource GetType() override;
private:
Loop::LSMutex mutex_;
};
IPCMutexProxy::IPCMutexProxy(HANDLE h, const IPCHandle &handle) : handle_(handle), mutex_(h)
{
}
IPCMutexProxy::~IPCMutexProxy()
{
}
bool IPCMutexProxy::Unlock()
{
return this->mutex_.Unlock();
}
bool IPCMutexProxy::IsSignaled()
{
return this->mutex_.IsSignaled();
}
bool IPCMutexProxy::IsSignaledNoSpinIfUserland()
{
return this->IsSignaled();
}
bool IPCMutexProxy::WaitOn(AuUInt32 timeout)
{
return this->mutex_.WaitOn(timeout);
}
Loop::ELoopSource IPCMutexProxy::GetType()
{
return this->mutex_.GetType();
}
AUKN_SYM AuSPtr<IPCMutex> NewMutex()
{
IPC::IPCHandle handle;
IPC::IPCToken token;
token.NewId();
handle.PushId(EIPCHandleType::eIPCPrimitiveMutex, token);
auto mutex = CreateMutexA(nullptr, false, token.ToNTPath().c_str());
if (mutex == INVALID_HANDLE_VALUE)
{
SysPushErrorIO();
return {};
}
auto object = AuMakeShared<IPCMutexProxy>(mutex, handle);
if (!object)
{
SysPushErrorMem();
AuWin32CloseHandle(mutex);
return {};
}
return object;
}
AUKN_SYM AuSPtr<IPCMutex> ImportMutex(const AuString &handleString)
{
IPCHandle handle;
if (!handle.FromString(handleString))
{
SysPushErrorParseError();
return {};
}
auto token = handle.GetToken(EIPCHandleType::eIPCPrimitiveMutex, 0);
if (!token)
{
SysPushErrorParseError();
return {};
}
auto mutex = OpenMutexA(MUTEX_ALL_ACCESS, false, token->token.ToNTPath().c_str());
if (mutex == INVALID_HANDLE_VALUE)
{
SysPushErrorIO();
return {};
}
auto object = AuMakeShared<IPCMutexProxy>(mutex, handle);
if (!object)
{
SysPushErrorMem();
AuWin32CloseHandle(mutex);
return {};
}
return object;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Events
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct IPCEventProxy : IPCEvent, Loop::ILoopSourceEx
{
IPCEventProxy(HANDLE h, const IPCHandle &handle);
~IPCEventProxy();
PROXY_INTERNAL_INTERFACE(event_)
IMPLEMENT_HANDLE
bool Set() override;
bool Reset() override;
bool IsSignaledNoSpinIfUserland() override;
bool IsSignaled() override;
bool WaitOn(AuUInt32 timeout) override;
Loop::ELoopSource GetType() override;
private:
Loop::LSEvent event_;
};
IPCEventProxy::IPCEventProxy(HANDLE h, const IPCHandle &handle) : event_(h), handle_(handle)
{
}
IPCEventProxy::~IPCEventProxy()
{
}
bool IPCEventProxy::Set()
{
return this->event_.Set();
}
bool IPCEventProxy::Reset()
{
return this->event_.Reset();
}
bool IPCEventProxy::IsSignaled()
{
return this->event_.IsSignaled();
}
bool IPCEventProxy::WaitOn(AuUInt32 timeout)
{
return this->event_.WaitOn(timeout);
}
Loop::ELoopSource IPCEventProxy::GetType()
{
return this->event_.GetType();
}
bool IPCEventProxy::IsSignaledNoSpinIfUserland()
{
return this->IsSignaled();
}
AUKN_SYM AuSPtr<IPCEvent> NewEvent(bool triggered, bool atomicRelease)
{
IPC::IPCHandle handle;
IPC::IPCToken token;
token.NewId();
handle.PushId(EIPCHandleType::eIPCPrimitiveEvent, token);
auto mutex = ::CreateEventA(nullptr, !atomicRelease, triggered, token.ToNTPath().c_str());
if ((!mutex) ||
mutex == INVALID_HANDLE_VALUE)
{
SysPushErrorIO();
return {};
}
auto object = AuMakeShared<IPCEventProxy>(mutex, handle);
if (!object)
{
SysPushErrorMem();
AuWin32CloseHandle(mutex);
return {};
}
return object;
}
AUKN_SYM AuSPtr<IPCEvent> ImportEvent(const AuString &handleString)
{
IPCHandle handle;
if (!handle.FromString(handleString))
{
SysPushErrorParseError();
return {};
}
auto token = handle.GetToken(EIPCHandleType::eIPCPrimitiveEvent, 0);
if (!token)
{
SysPushErrorParseError();
return {};
}
auto eventE = ::OpenEventA(EVENT_ALL_ACCESS, false, token->token.ToNTPath().c_str());
if ((!eventE) ||
(eventE == INVALID_HANDLE_VALUE))
{
SysPushErrorIO();
return {};
}
auto object = AuMakeShared<IPCEventProxy>(eventE, handle);
if (!object)
{
SysPushErrorMem();
AuWin32CloseHandle(eventE);
return {};
}
return object;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Semaphores
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct IPCSemaphoreProxy : IPCSemaphore, Loop::ILoopSourceEx
{
IPCSemaphoreProxy(HANDLE h, const IPCHandle &handle);
~IPCSemaphoreProxy();
PROXY_INTERNAL_INTERFACE(semaphore_)
IMPLEMENT_HANDLE
bool AddOne() override;
bool AddMany(AuUInt32 uCount) override;
bool IsSignaledNoSpinIfUserland() override;
bool IsSignaled() override;
bool WaitOn(AuUInt32 timeout) override;
Loop::ELoopSource GetType() override;
private:
Loop::LSSemaphore semaphore_;
};
IPCSemaphoreProxy::IPCSemaphoreProxy(HANDLE h, const IPCHandle &handle) : handle_(handle), semaphore_(h)
{
}
IPCSemaphoreProxy::~IPCSemaphoreProxy()
{
}
bool IPCSemaphoreProxy::AddOne()
{
return this->semaphore_.AddOne();
}
bool IPCSemaphoreProxy::AddMany(AuUInt32 uCount)
{
return this->semaphore_.AddMany(uCount);
}
bool IPCSemaphoreProxy::IsSignaled()
{
return this->semaphore_.IsSignaled();
}
bool IPCSemaphoreProxy::IsSignaledNoSpinIfUserland()
{
return this->IsSignaled();
}
bool IPCSemaphoreProxy::WaitOn(AuUInt32 timeout)
{
return this->semaphore_.WaitOn(timeout);
}
Loop::ELoopSource IPCSemaphoreProxy::GetType()
{
return this->semaphore_.GetType();
}
AUKN_SYM AuSPtr<IPCSemaphore> NewSemaphore(int startingValue)
{
IPC::IPCHandle handle;
IPC::IPCToken token;
token.NewId();
handle.PushId(EIPCHandleType::eIPCPrimitiveSemaphore, token);
auto semaphore = ::CreateSemaphoreA(nullptr, startingValue, AuNumericLimits<LONG>::max(), token.ToNTPath().c_str());
if ((!semaphore) ||
(semaphore == INVALID_HANDLE_VALUE))
{
SysPushErrorIO();
return {};
}
auto object = AuMakeShared<IPCSemaphoreProxy>(semaphore, handle);
if (!object)
{
SysPushErrorMem();
AuWin32CloseHandle(semaphore);
return {};
}
return object;
}
AUKN_SYM AuSPtr<IPCSemaphore> ImportSemaphore(const AuString &handleString)
{
IPCHandle handle;
if (!handle.FromString(handleString))
{
SysPushErrorParseError();
return {};
}
auto token = handle.GetToken(EIPCHandleType::eIPCPrimitiveSemaphore, 0);
if (!token)
{
SysPushErrorParseError();
return {};
}
auto semaphore = ::OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, false, token->token.ToNTPath().c_str());
if ((!semaphore) ||
(semaphore == INVALID_HANDLE_VALUE))
{
SysPushErrorIO();
return {};
}
auto object = AuMakeShared<IPCSemaphoreProxy>(semaphore, handle);
if (!object)
{
SysPushErrorMem();
AuWin32CloseHandle(semaphore);
return {};
}
return object;
}
}