From 499aaeedab30ee055dbca16d2c3f5bbca3922ff2 Mon Sep 17 00:00:00 2001 From: J Reece Wilson Date: Fri, 15 Apr 2022 11:01:43 +0100 Subject: [PATCH] [+] IPCMutex, IPCSharedMemory [*] Refactor headers --- Include/Aurora/IPC/IPC.hpp | 4 +- Include/Aurora/IPC/IPCPipe.hpp | 21 +++ .../IPC/{Primitives.hpp => IPCPrimitives.hpp} | 11 -- Include/Aurora/IPC/IPCSharedMemory.hpp | 20 ++ Source/Console/ConsoleStd/ConsoleStd.cpp | 0 Source/IO/FS/FS.Unix.cpp | 0 Source/IPC/IPCHandle.cpp | 52 ++++- Source/IPC/IPCHandle.hpp | 5 +- Source/IPC/IPCMemory.Unix.cpp | 178 ++++++++++++++++++ Source/IPC/IPCMemory.Unix.hpp | 13 ++ Source/IPC/IPCPipe.Unix.cpp | 30 +++ Source/IPC/IPCPipe.Unix.hpp | 13 ++ Source/IPC/IPCPrimitives.Linux.cpp | 174 ++++++++++++++--- Source/Loop/LSMutex.Linux.cpp | 7 +- Source/Loop/LSMutex.Linux.hpp | 1 + 15 files changed, 486 insertions(+), 43 deletions(-) create mode 100755 Include/Aurora/IPC/IPCPipe.hpp rename Include/Aurora/IPC/{Primitives.hpp => IPCPrimitives.hpp} (65%) create mode 100755 Include/Aurora/IPC/IPCSharedMemory.hpp mode change 100644 => 100755 Source/Console/ConsoleStd/ConsoleStd.cpp mode change 100644 => 100755 Source/IO/FS/FS.Unix.cpp create mode 100755 Source/IPC/IPCMemory.Unix.cpp create mode 100755 Source/IPC/IPCMemory.Unix.hpp create mode 100755 Source/IPC/IPCPipe.Unix.cpp create mode 100755 Source/IPC/IPCPipe.Unix.hpp diff --git a/Include/Aurora/IPC/IPC.hpp b/Include/Aurora/IPC/IPC.hpp index 14937868..2c13e032 100755 --- a/Include/Aurora/IPC/IPC.hpp +++ b/Include/Aurora/IPC/IPC.hpp @@ -8,7 +8,9 @@ #pragma once #include "IExportableIPC.hpp" -#include "Primitives.hpp" +#include "IPCPrimitives.hpp" +#include "IPCPipe.hpp" +#include "IPCSharedMemory.hpp" namespace Aurora::IPC { diff --git a/Include/Aurora/IPC/IPCPipe.hpp b/Include/Aurora/IPC/IPCPipe.hpp new file mode 100755 index 00000000..472586db --- /dev/null +++ b/Include/Aurora/IPC/IPCPipe.hpp @@ -0,0 +1,21 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: IPCPipe.hpp + Date: 2022-4-14 + Author: Reece +***/ +#pragma once + +namespace Aurora::IPC +{ + struct IPCPipe : IExportableIPC + { + virtual AuSPtr ToLoopQueue() = 0; + virtual bool Read(const Memory::MemoryViewStreamWrite &write, bool nonblock = true) = 0; + virtual bool Write(const Memory::MemoryViewStreamRead &read, bool nonblock = true) = 0; + }; + + AUKN_SYM AuSPtr NewPipe(); + AUKN_SYM AuSPtr ImportPipe(const AuString &handle); +} \ No newline at end of file diff --git a/Include/Aurora/IPC/Primitives.hpp b/Include/Aurora/IPC/IPCPrimitives.hpp similarity index 65% rename from Include/Aurora/IPC/Primitives.hpp rename to Include/Aurora/IPC/IPCPrimitives.hpp index ee22a2e9..2445fab9 100755 --- a/Include/Aurora/IPC/Primitives.hpp +++ b/Include/Aurora/IPC/IPCPrimitives.hpp @@ -21,13 +21,6 @@ namespace Aurora::IPC { }; - struct IPCPipe : IExportableIPC - { - virtual AuSPtr ToLoopQueue() = 0; - virtual bool Read(const Memory::MemoryViewStreamWrite &write, bool nonblock = true) = 0; - virtual bool Write(const Memory::MemoryViewStreamRead &read, bool nonblock = true) = 0; - }; - AUKN_SYM AuSPtr NewEvent(bool triggered, bool atomicRelease); AUKN_SYM AuSPtr ImportEvent(const AuString &handle); @@ -36,8 +29,4 @@ namespace Aurora::IPC AUKN_SYM AuSPtr NewMutex(); AUKN_SYM AuSPtr ImportMutex(const AuString &handle); - - AUKN_SYM AuSPtr NewPipe(); - AUKN_SYM AuSPtr ImportPipe(const AuString &handle); - } \ No newline at end of file diff --git a/Include/Aurora/IPC/IPCSharedMemory.hpp b/Include/Aurora/IPC/IPCSharedMemory.hpp new file mode 100755 index 00000000..b1492821 --- /dev/null +++ b/Include/Aurora/IPC/IPCSharedMemory.hpp @@ -0,0 +1,20 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: IPCSharedMemory.hpp + Date: 2022-4-14 + Author: Reece +***/ +#pragma once + +namespace Aurora::IPC +{ + struct IPCSharedMemory : IExportableIPC + { + virtual Memory::MemoryViewWrite GetMemory() = 0; + virtual AuUInt GetLength() = 0; + }; + + AUKN_SYM AuSPtr NewSharedMemory(AuUInt length); + AUKN_SYM AuSPtr ImportSharedMemory(const AuString &handle); +} \ No newline at end of file diff --git a/Source/Console/ConsoleStd/ConsoleStd.cpp b/Source/Console/ConsoleStd/ConsoleStd.cpp old mode 100644 new mode 100755 diff --git a/Source/IO/FS/FS.Unix.cpp b/Source/IO/FS/FS.Unix.cpp old mode 100644 new mode 100755 diff --git a/Source/IPC/IPCHandle.cpp b/Source/IPC/IPCHandle.cpp index f379e03c..46904dd3 100755 --- a/Source/IPC/IPCHandle.cpp +++ b/Source/IPC/IPCHandle.cpp @@ -24,6 +24,12 @@ namespace Aurora::IPC this->flags[2] = c; this->flags[3] = d; + this->word = 0; + NewId(); + } + + void IPCHandle::NewId() + { #if defined(AURORA_IS_POSIX_DERIVED) this->cookie = AuRng::RngU32(); this->pid = getpid(); @@ -33,6 +39,13 @@ namespace Aurora::IPC #endif } + void IPCHandle::NewId(AuUInt len) + { + AuMemset(this->flags, 0, sizeof(this->flags)); + this->word = len; + NewId(); + } + bool IPCHandle::FromString(const AuString &in) { if (in.size() < 4) @@ -46,12 +59,30 @@ namespace Aurora::IPC this->flags[3] = in[3] == 'Y'; #if defined(AURORA_IS_MODERNNT_DERIVED) - if (in.size() != 4 + 16) + if (in.size() < 4 + 16) { return false; } AuMemcpy(path, &in[4], 16); + + if (in.size() > 4 + 16) + { + auto word = strtoll(in.c_str() + 4 + 16, &endPtr, 10); + if (errno == ERANGE) + { + return false; + } + + if (*endPtr != '\00') + { + return false; + } + + this->word = word; + + return true; + } #endif #if defined(AURORA_IS_POSIX_DERIVED) @@ -76,6 +107,19 @@ namespace Aurora::IPC return false; } + if (*endPtr != '_') + { + return false; + } + + this->word = word; + + word = strtoll(endPtr + 1, &endPtr, 10); + if (errno == ERANGE) + { + return false; + } + if (*endPtr != '\00') { return false; @@ -112,11 +156,17 @@ namespace Aurora::IPC #if defined(AURORA_IS_MODERNNT_DERIVED) AuMemcpy(&ret[4], this->path, 16); + if (this->word) + { + ret += AuToString(this->word); + } #endif #if defined(AURORA_IS_POSIX_DERIVED) ret += AuToString(this->cookie); ret += '_'; + ret += AuToString(this->word); + ret += '_'; ret += AuToString(this->pid); #endif diff --git a/Source/IPC/IPCHandle.hpp b/Source/IPC/IPCHandle.hpp index ecc25335..7c20ac84 100755 --- a/Source/IPC/IPCHandle.hpp +++ b/Source/IPC/IPCHandle.hpp @@ -12,7 +12,7 @@ namespace Aurora::IPC struct IPCHandle { bool flags[4]; - + AuUInt word; union { char path[16]; @@ -23,7 +23,10 @@ namespace Aurora::IPC }; }; + void NewId(); + void NewId(AuUInt len); void NewId(bool a, bool b, bool c, bool d); + bool FromString(const AuString &in); AuString ToString() const; AuString ToNTPath() const; diff --git a/Source/IPC/IPCMemory.Unix.cpp b/Source/IPC/IPCMemory.Unix.cpp new file mode 100755 index 00000000..7e9063c9 --- /dev/null +++ b/Source/IPC/IPCMemory.Unix.cpp @@ -0,0 +1,178 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: IPCMemory.Unix.cpp + Date: 2022-4-14 + Author: Reece +***/ +#include +#include "IPC.hpp" +#include "IPCHandle.hpp" +#include "IPCMemory.Unix.hpp" + +#include +#include + +#include +#include /* For mode constants */ +#include /* For O_* constants */ + +namespace Aurora::IPC +{ + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Shared memory + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + struct IPCSharedMemoryImpl : IPCSharedMemory + { + IPCSharedMemoryImpl(int fd, void *ptr, const IPC::IPCHandle &handle, bool owns); + ~IPCSharedMemoryImpl(); + + virtual Memory::MemoryViewWrite GetMemory() override; + virtual AuUInt GetLength() override; + + virtual AuString ExportToString() override; + + private: + IPC::IPCHandle handle_; + bool owns_; + int fd_{}; + void *base_{}; + AuUInt len_ {}; + }; + + static AuString GetServerPath(const IPC::IPCHandle &handle) + { + AuString path; + path += "/AURORA_"; + path += AuToString(AuUInt32(handle.cookie)); + path += "_"; + path += AuToString(AuUInt32(handle.pid)); + return path; + } + + IPCSharedMemoryImpl::IPCSharedMemoryImpl(int fd, void *ptr, const IPC::IPCHandle &handle, bool owns) : + fd_(fd), base_(ptr), len_(handle.word), owns_(owns), handle_(handle) + { + + } + + IPCSharedMemoryImpl::~IPCSharedMemoryImpl() + { + if (this->base_) + { + ::munmap(this->base_, this->len_); + } + + #if 0 + if (this->owns_) + { + int er = ::shm_unlink(GetServerPath(this->handle_).c_str()); + if (er == -1) + { + SysPushErrorIO("Couldn't clean up UNIX shared memory IPC file..."); + // TODO: maybe we should remap and null... just to be safe + } + } + #endif + + int fd {-1}; + if ((fd = AuExchange(this->fd_, -1)) != -1) + { + ::close(fd); + } + } + + Memory::MemoryViewWrite IPCSharedMemoryImpl::GetMemory() + { + return AuMemoryViewWrite(this->base_, this->len_); + } + + AuUInt IPCSharedMemoryImpl::GetLength() + { + return this->len_; + } + + AuString IPCSharedMemoryImpl::ExportToString() + { + return this->handle_.ToString(); + } + + AUKN_SYM AuSPtr NewSharedMemory(AuUInt length) + { + IPC::IPCHandle handle; + handle.NewId(length); + + auto path = GetServerPath(handle); + int fd = ::shm_open(path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + if (fd == -1) + { + SysPushErrorIO(); + return {}; + } + + if (::ftruncate(fd, length) == -1) + { + SysPushErrorMem(); + ::close(fd); + return {}; + } + + auto map = ::mmap(nullptr, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) + { + SysPushErrorIO(); + ::close(fd); + return {}; + } + + auto object = AuMakeShared(fd, map, handle, true); + if (!object) + { + SysPushErrorMem(); + ::munmap(map, length); + ::close(fd); + return {}; + } + + return object; + } + + AUKN_SYM AuSPtr ImportSharedMemory(const AuString &handleString) + { + IPC::IPCHandle handle; + + if (!handle.FromString(handleString)) + { + SysPushErrorParseError(); + return {}; + } + + auto path = GetServerPath(handle); + int fd = ::shm_open(path.c_str(), O_RDWR, S_IRUSR | S_IWUSR); + if (fd == -1) + { + SysPushErrorIO(); + return {}; + } + + auto map = ::mmap(nullptr, handle.word, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (map == MAP_FAILED) + { + SysPushErrorIO(); + ::close(fd); + return {}; + } + + auto object = AuMakeShared(fd, map, handle, false); + if (!object) + { + SysPushErrorMem(); + ::munmap(map, handle.word); + ::close(fd); + return {}; + } + + return object; + } +} \ No newline at end of file diff --git a/Source/IPC/IPCMemory.Unix.hpp b/Source/IPC/IPCMemory.Unix.hpp new file mode 100755 index 00000000..097b7f03 --- /dev/null +++ b/Source/IPC/IPCMemory.Unix.hpp @@ -0,0 +1,13 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: IPCMemory.Unix.hpp + Date: 2022-4-14 + Author: Reece +***/ +#pragma once + +namespace Aurora::IPC +{ + +} \ No newline at end of file diff --git a/Source/IPC/IPCPipe.Unix.cpp b/Source/IPC/IPCPipe.Unix.cpp new file mode 100755 index 00000000..17d608f6 --- /dev/null +++ b/Source/IPC/IPCPipe.Unix.cpp @@ -0,0 +1,30 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: IPCPipe.Linux.cpp + Date: 2022-4-14 + Author: Reece +***/ +#include +#include "IPC.hpp" +#include "IPCHandle.hpp" +#include "IPCPipe.Unix.hpp" + +namespace Aurora::IPC +{ + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Pipes + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + AUKN_SYM AuSPtr NewPipe() + { + SysPushErrorUnimplemented(); + return {}; + } + + AUKN_SYM AuSPtr ImportPipe(const AuString &handle) + { + SysPushErrorUnimplemented(); + return {}; + } +} \ No newline at end of file diff --git a/Source/IPC/IPCPipe.Unix.hpp b/Source/IPC/IPCPipe.Unix.hpp new file mode 100755 index 00000000..d1315ef3 --- /dev/null +++ b/Source/IPC/IPCPipe.Unix.hpp @@ -0,0 +1,13 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: IPCPipe.Unix.hpp + Date: 2022-4-14 + Author: Reece +***/ +#pragma once + +namespace Aurora::IPC +{ + +} \ No newline at end of file diff --git a/Source/IPC/IPCPrimitives.Linux.cpp b/Source/IPC/IPCPrimitives.Linux.cpp index ed6bdf5f..c7a61f61 100755 --- a/Source/IPC/IPCPrimitives.Linux.cpp +++ b/Source/IPC/IPCPrimitives.Linux.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -52,6 +53,10 @@ namespace Aurora::IPC virtual AuUInt GetWriteHandle() override \ { \ return Base.GetWriteHandle(); \ + } \ + bool HasValidHandle() \ + { \ + return Base.HasValidHandle(); \ } #define IMPLEMENT_HANDLE \ @@ -115,27 +120,27 @@ namespace Aurora::IPC bool IPCEventProxy::Set() { - return event_.Set(); + return this->event_.Set(); } bool IPCEventProxy::Reset() { - return event_.Reset(); + return this->event_.Reset(); } bool IPCEventProxy::IsSignaled() { - return event_.IsSignaled(); + return this->event_.IsSignaled(); } bool IPCEventProxy::WaitOn(AuUInt32 timeout) { - return event_.WaitOn(timeout); + return this->event_.WaitOn(timeout); } Loop::ELoopSource IPCEventProxy::GetType() { - return event_.GetType(); + return this->event_.GetType(); } AUKN_SYM AuSPtr NewEvent(bool triggered, bool atomicRelease) @@ -147,6 +152,12 @@ namespace Aurora::IPC return {}; } + if (!object->HasValidHandle()) + { + SysPushErrorIO(); + return {}; + } + return object; } @@ -175,6 +186,12 @@ namespace Aurora::IPC return {}; } + if (!object->HasValidHandle()) + { + SysPushErrorIO(); + return {}; + } + return object; } @@ -230,22 +247,22 @@ namespace Aurora::IPC bool IPCSemaphoreProxy::AddOne() { - return semaphore_.AddOne(); + return this->semaphore_.AddOne(); } bool IPCSemaphoreProxy::IsSignaled() { - return semaphore_.IsSignaled(); + return this->semaphore_.IsSignaled(); } bool IPCSemaphoreProxy::WaitOn(AuUInt32 timeout) { - return semaphore_.WaitOn(timeout); + return this->semaphore_.WaitOn(timeout); } Loop::ELoopSource IPCSemaphoreProxy::GetType() { - return semaphore_.GetType(); + return this->semaphore_.GetType(); } AUKN_SYM AuSPtr NewSemaphore(int startingValue) @@ -257,6 +274,12 @@ namespace Aurora::IPC return {}; } + if (!object->HasValidHandle()) + { + SysPushErrorIO(); + return {}; + } + return object; } @@ -285,6 +308,12 @@ namespace Aurora::IPC return {}; } + if (!object->HasValidHandle()) + { + SysPushErrorIO(); + return {}; + } + return object; } @@ -292,32 +321,121 @@ namespace Aurora::IPC // 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() { - SysPushErrorUnimplemented(); - return {}; + auto object = AuMakeShared(); + if (!object) + { + SysPushErrorMem(); + return {}; + } + + if (!object->HasValidHandle()) + { + SysPushErrorIO(); + return {}; + } + + return object; } AUKN_SYM AuSPtr ImportMutex(const AuString &handle) { - SysPushErrorUnimplemented(); - return {}; - } - - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Pipes - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + IPC::IPCHandle decodedHandle; - AUKN_SYM AuSPtr NewPipe() - { - SysPushErrorUnimplemented(); - return {}; - } + if (!decodedHandle.FromString(handle)) + { + SysPushErrorParseError("Invalid handle: {}", handle); + return {}; + } - AUKN_SYM AuSPtr ImportPipe(const AuString &handle) - { - SysPushErrorUnimplemented(); - 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; } - } \ No newline at end of file diff --git a/Source/Loop/LSMutex.Linux.cpp b/Source/Loop/LSMutex.Linux.cpp index 093f5a37..3c79413a 100644 --- a/Source/Loop/LSMutex.Linux.cpp +++ b/Source/Loop/LSMutex.Linux.cpp @@ -17,12 +17,17 @@ namespace Aurora::Loop Init(); } + LSMutex::LSMutex(int handle) + { + this->handle = handle; + } + LSMutex::~LSMutex() { if ((this->handle != 0) && (this->handle != -1)) { - ::close(this->handle); + ::close(AuExchange(this->handle, -1)); } } diff --git a/Source/Loop/LSMutex.Linux.hpp b/Source/Loop/LSMutex.Linux.hpp index f70a8f32..e7856bbc 100644 --- a/Source/Loop/LSMutex.Linux.hpp +++ b/Source/Loop/LSMutex.Linux.hpp @@ -13,6 +13,7 @@ namespace Aurora::Loop struct LSMutex : public ILSMutex, public LSHandle { LSMutex(); + LSMutex(int handle); ~LSMutex(); bool Unlock() override;