/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: IPCPrimitives.Linux.cpp Date: 2022-4-13 Author: Reece ***/ #include #include "IPC.hpp" #include "IPCHandle.hpp" #include "IPCPrimitives.Linux.hpp" #include #include #include #include #include #include namespace Aurora::IO::IPC { #define IMPLEMENT_HANDLE \ IPC::IPCHandle handle_; \ AuString ExportToString() override \ { \ return handle_.ToString(); \ } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Events ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// struct IPCEventProxy : IPCEvent, Loop::ILoopSourceEx { IPCEventProxy(bool triggered, bool atomicRelease); IPCEventProxy(int handle, bool triggered, bool atomicRelease); ~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(bool triggered, bool atomicRelease) : event_(triggered, atomicRelease, true) { if (this->event_.HasValidHandle()) { if (!IO::UNIX::FDServe(triggered, atomicRelease, false, true, this->GetHandle(), this->handle_)) { this->event_.~LSEvent(); } } } IPCEventProxy::IPCEventProxy(int handle, bool triggered, bool atomicRelease) : event_(handle, triggered, atomicRelease) { if (this->event_.HasValidHandle()) { if (!IO::UNIX::FDServe(triggered, atomicRelease, false, true, this->GetHandle(), this->handle_)) { this->event_.~LSEvent(); } } } IPCEventProxy::~IPCEventProxy() { IO::UNIX::FDServeEnd(this->handle_); } 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) { auto object = AuMakeShared(triggered, atomicRelease); if (!object) { SysPushErrorMem(); return {}; } if (!object->HasValidHandle()) { SysPushErrorIO(); return {}; } return object; } AUKN_SYM AuSPtr ImportEvent(const AuString &handle) { IPC::IPCHandle decodedHandle; if (!decodedHandle.FromString(handle)) { SysPushErrorParseError("Invalid handle: {}", handle); return {}; } int fd {-1}; if (!IO::UNIX::FDAccept(decodedHandle, fd)) { SysPushErrorNested(); return {}; } auto object = AuMakeShared(fd, decodedHandle.flags[0], decodedHandle.flags[1]); if (!object) { SysPushErrorMem(); ::close(fd); return {}; } if (!object->HasValidHandle()) { SysPushErrorIO(); return {}; } return object; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Semaphores ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// struct IPCSemaphoreProxy : IPCSemaphore, Loop::ILoopSourceEx { IPCSemaphoreProxy(AuUInt32 initialCount); IPCSemaphoreProxy(int handle, int tag); ~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(AuUInt32 initialCount) : semaphore_(initialCount) { if (this->semaphore_.HasValidHandle()) { if (!IO::UNIX::FDServe(true, true, true, true, this->GetHandle(), this->handle_)) { this->semaphore_.~LSSemaphore(); } } } IPCSemaphoreProxy::IPCSemaphoreProxy(int handle, int tag) : semaphore_(handle, tag) { if (this->semaphore_.HasValidHandle()) { if (!IO::UNIX::FDServe(true, true, true, true, this->GetHandle(), this->handle_)) { this->semaphore_.~LSSemaphore(); } } } IPCSemaphoreProxy::~IPCSemaphoreProxy() { IO::UNIX::FDServeEnd(this->handle_); } 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) { auto object = AuMakeShared(startingValue); if (!object) { SysPushErrorMem(); return {}; } if (!object->HasValidHandle()) { SysPushErrorIO(); return {}; } return object; } AUKN_SYM AuSPtr ImportSemaphore(const AuString &handle) { IPC::IPCHandle decodedHandle; if (!decodedHandle.FromString(handle)) { SysPushErrorParseError("Invalid handle: {}", handle); return {}; } int fd {-1}; if (!IO::UNIX::FDAccept(decodedHandle, fd)) { SysPushErrorNested(); return {}; } auto object = AuMakeShared(fd, 0xC001C0DE); if (!object) { SysPushErrorMem(); ::close(fd); return {}; } if (!object->HasValidHandle()) { SysPushErrorIO(); return {}; } return object; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Mutexes ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// struct IPCMutexProxy : IPCMutex, Loop::ILoopSourceEx { IPCMutexProxy(); IPCMutexProxy(int 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() : mutex_() { if (this->mutex_.HasValidHandle()) { if (!IO::UNIX::FDServe(false, false, true, true, this->GetHandle(), this->handle_)) { this->mutex_.~LSMutex(); } } } IPCMutexProxy::IPCMutexProxy(int handle) : mutex_(handle) { if (this->mutex_.HasValidHandle()) { if (!IO::UNIX::FDServe(false, false, true, true, this->GetHandle(), this->handle_)) { this->mutex_.~LSMutex(); } } } IPCMutexProxy::~IPCMutexProxy() { IO::UNIX::FDServeEnd(this->handle_); } 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() { auto object = AuMakeShared(); if (!object) { SysPushErrorMem(); return {}; } if (!object->HasValidHandle()) { SysPushErrorIO(); return {}; } return object; } AUKN_SYM AuSPtr ImportMutex(const AuString &handle) { IPC::IPCHandle decodedHandle; if (!decodedHandle.FromString(handle)) { SysPushErrorParseError("Invalid handle: {}", handle); return {}; } int fd {-1}; if (!IO::UNIX::FDAccept(decodedHandle, fd)) { SysPushErrorNested(); return {}; } auto object = AuMakeShared(fd); if (!object) { SysPushErrorMem(); ::close(fd); return {}; } if (!object->HasValidHandle()) { SysPushErrorIO(); return {}; } return object; } }