399 lines
9.8 KiB
C++
399 lines
9.8 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_)
|
|
PROXY_LOOPSOURCE_EXT_APIS(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_)
|
|
PROXY_LOOPSOURCE_EXT_APIS(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_)
|
|
PROXY_LOOPSOURCE_EXT_APIS(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()*/ 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;
|
|
}
|
|
} |