/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuIPCPrimitives.NT.cpp Date: 2022-4-13 Author: Reece ***/ #include #include "IPC.hpp" #include "AuIPCHandle.hpp" #include "AuIPCPrimitives.NT.hpp" #include #include #include 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 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::WaitOn(AuUInt32 timeout) { return this->mutex_.WaitOn(timeout); } Loop::ELoopSource IPCMutexProxy::GetType() { return this->mutex_.GetType(); } AUKN_SYM AuSPtr 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(mutex, handle); if (!object) { SysPushErrorMem(); AuWin32CloseHandle(mutex); return {}; } return object; } AUKN_SYM AuSPtr 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(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 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(); } AUKN_SYM AuSPtr 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(mutex, handle); if (!object) { SysPushErrorMem(); AuWin32CloseHandle(mutex); return {}; } return object; } AUKN_SYM AuSPtr 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(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 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::IsSignaled() { return this->semaphore_.IsSignaled(); } bool IPCSemaphoreProxy::WaitOn(AuUInt32 timeout) { return this->semaphore_.WaitOn(timeout); } Loop::ELoopSource IPCSemaphoreProxy::GetType() { return this->semaphore_.GetType(); } AUKN_SYM AuSPtr NewSemaphore(int startingValue) { IPC::IPCHandle handle; IPC::IPCToken token; token.NewId(); handle.PushId(EIPCHandleType::eIPCPrimitiveSemaphore, token); auto semaphore = ::CreateSemaphoreA(nullptr, startingValue, AuNumericLimits::max(), token.ToNTPath().c_str()); if ((!semaphore) || (semaphore == INVALID_HANDLE_VALUE)) { SysPushErrorIO(); return {}; } auto object = AuMakeShared(semaphore, handle); if (!object) { SysPushErrorMem(); AuWin32CloseHandle(semaphore); return {}; } return object; } AUKN_SYM AuSPtr 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(semaphore, handle); if (!object) { SysPushErrorMem(); AuWin32CloseHandle(semaphore); return {}; } return object; } }