diff --git a/Include/Aurora/IPC/IExportableIPC.hpp b/Include/Aurora/IPC/IExportableIPC.hpp new file mode 100755 index 00000000..04960d20 --- /dev/null +++ b/Include/Aurora/IPC/IExportableIPC.hpp @@ -0,0 +1,16 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: IExportableIPC.hpp + Date: 2022-4-14 + Author: Reece +***/ +#pragma once + +namespace Aurora::IPC +{ + struct IExportableIPC + { + virtual AuString ExportToString() = 0; + }; +} \ No newline at end of file diff --git a/Include/Aurora/IPC/IPC.hpp b/Include/Aurora/IPC/IPC.hpp new file mode 100755 index 00000000..14937868 --- /dev/null +++ b/Include/Aurora/IPC/IPC.hpp @@ -0,0 +1,16 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: IPC.hpp + Date: 2022-4-14 + Author: Reece +***/ +#pragma once + +#include "IExportableIPC.hpp" +#include "Primitives.hpp" + +namespace Aurora::IPC +{ + +} \ No newline at end of file diff --git a/Include/Aurora/IPC/IPCCV.hpp b/Include/Aurora/IPC/IPCCV.hpp deleted file mode 100644 index 2fbcede1..00000000 --- a/Include/Aurora/IPC/IPCCV.hpp +++ /dev/null @@ -1,7 +0,0 @@ -/*** - Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. - - File: IPCCV.hpp - Date: 2021-8-27 - Author: Reece -***/ diff --git a/Include/Aurora/IPC/IPCEvent.hpp b/Include/Aurora/IPC/IPCEvent.hpp deleted file mode 100644 index 3f1d31de..00000000 --- a/Include/Aurora/IPC/IPCEvent.hpp +++ /dev/null @@ -1,7 +0,0 @@ -/*** - Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. - - File: IPCEvent.hpp - Date: 2021-8-28 - Author: Reece -***/ diff --git a/Include/Aurora/IPC/IPCMemory.hpp b/Include/Aurora/IPC/IPCMemory.hpp deleted file mode 100644 index 0ff7fd42..00000000 --- a/Include/Aurora/IPC/IPCMemory.hpp +++ /dev/null @@ -1,7 +0,0 @@ -/*** - Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. - - File: IPCMemory.hpp - Date: 2021-8-27 - Author: Reece -***/ diff --git a/Include/Aurora/IPC/IPCMutex.hpp b/Include/Aurora/IPC/IPCMutex.hpp deleted file mode 100644 index bbea18e3..00000000 --- a/Include/Aurora/IPC/IPCMutex.hpp +++ /dev/null @@ -1,7 +0,0 @@ -/*** - Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. - - File: IPCMutex.hpp - Date: 2021-8-27 - Author: Reece -***/ diff --git a/Include/Aurora/IPC/IPCPipe.hpp b/Include/Aurora/IPC/IPCPipe.hpp deleted file mode 100644 index 073ac7f7..00000000 --- a/Include/Aurora/IPC/IPCPipe.hpp +++ /dev/null @@ -1,7 +0,0 @@ -/*** - Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. - - File: IPCPipeServer.hpp - Date: 2021-8-28 - Author: Reece -***/ diff --git a/Include/Aurora/IPC/IPCSemaphore.hpp b/Include/Aurora/IPC/IPCSemaphore.hpp deleted file mode 100644 index de59d80a..00000000 --- a/Include/Aurora/IPC/IPCSemaphore.hpp +++ /dev/null @@ -1,7 +0,0 @@ -/*** - Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. - - File: IPCSemaphore.hpp - Date: 2021-8-27 - Author: Reece -***/ diff --git a/Include/Aurora/IPC/Primitives.hpp b/Include/Aurora/IPC/Primitives.hpp new file mode 100755 index 00000000..ee22a2e9 --- /dev/null +++ b/Include/Aurora/IPC/Primitives.hpp @@ -0,0 +1,43 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: Primitives.hpp + Date: 2022-4-14 + Author: Reece +***/ +#pragma once + +namespace Aurora::IPC +{ + struct IPCEvent : Loop::ILSEvent, IExportableIPC + { + }; + + struct IPCSemaphore : Loop::ILSSemaphore, IExportableIPC + { + }; + + struct IPCMutex : Loop::ILSMutex, IExportableIPC + { + }; + + 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); + + AUKN_SYM AuSPtr NewSemaphore(int startingValue); + AUKN_SYM AuSPtr ImportSemaphore(const AuString &handle); + + 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/Loop/ILoopQueue.hpp b/Include/Aurora/Loop/ILoopQueue.hpp index 9e86d28b..a1b6c0a0 100644 --- a/Include/Aurora/Loop/ILoopQueue.hpp +++ b/Include/Aurora/Loop/ILoopQueue.hpp @@ -9,8 +9,8 @@ namespace Aurora::Loop { - // This is like a CF RunLoop with the input parameters of NT's WaitMultipleObjects - // This shouldn't be too much heavier than CF's libevent/NT abstraction in the style of a kevent interface with objects + // ILoopQueue's are comparable to a CoreFoundation RunLoop with the input parameters of NT's WaitMultipleObjects and RegisterWaitForSingleObject + // This shouldn't be too much heavier than CF's libevent/NT abstraction struct ILoopQueue { @@ -25,6 +25,7 @@ namespace Aurora::Loop * @param source * @return * @note thread safe / nonblocking | can be called alongside any other function marked as such + * @warning it is unsafe to add an ILoopSource more than once. */ virtual bool SourceAdd(const AuSPtr &source) = 0; @@ -36,6 +37,7 @@ namespace Aurora::Loop * @param timeoutMS * @return * @note thread safe / nonblocking | can be called alongside any other function marked as such + * @warning it is unsafe to add an ILoopSource more than once. */ virtual bool SourceAddWithTimeout(const AuSPtr &source, AuUInt32 timeoutMS) = 0; @@ -106,7 +108,6 @@ namespace Aurora::Loop */ virtual bool AddCallback(const AuSPtr &subscriber) = 0; - /** * @brief Nonblocking check for alert objects in the loop queue * @return @@ -116,13 +117,19 @@ namespace Aurora::Loop /** * @brief Nonblocking wait-any for all objects in the loop queue - * @warning (may yield to ILoopSourceSubscriber delegate on the current context) + * @warning may yield to ILoopSourceSubscriber delegate on the current context * @warning (technically unsafe, use alloc-unsafe extended version to acknowledge unlocked sources) * @return * @note thread safe / nonblocking | can be called alongside any other function marked as such */ virtual AuUInt32 PumpNonblocking() = 0; + /** + * @brief Nonblocking wait-any for all objects in the loop queue + * @warning may yield to ILoopSourceSubscriber delegate on the current context + * @return + * @note thread safe / nonblocking | can be called alongside any other function marked as such + */ virtual AuList> PumpNonblockingEx() = 0; /** @@ -205,8 +212,6 @@ namespace Aurora::Loop * @brief Hints that the calling program understands the kernel shouldnt schedule tne entire source list, and instead, we should long poll */ virtual void ChugHint(bool value) = 0; - - // TODO: once Win32 is finished and linux is looking alright, readd the removed functions }; AUKN_SYM AuSPtr NewLoopQueue(); diff --git a/Include/Aurora/Loop/ILoopSource.hpp b/Include/Aurora/Loop/ILoopSource.hpp index 24e8c750..d6b51676 100644 --- a/Include/Aurora/Loop/ILoopSource.hpp +++ b/Include/Aurora/Loop/ILoopSource.hpp @@ -23,7 +23,6 @@ namespace Aurora::Loop */ virtual ELoopSource GetType() = 0; - /** * @breif Blocks the current thread for the kernel primitives * @warning Are you looking for LoopQueues? You can even reduce async threads down to kernel ILoopQueue's diff --git a/Include/Aurora/Runtime.hpp b/Include/Aurora/Runtime.hpp index 29b9ea7b..4f02ea64 100644 --- a/Include/Aurora/Runtime.hpp +++ b/Include/Aurora/Runtime.hpp @@ -63,6 +63,7 @@ #include "Async/Async.hpp" #include "Processes/Processes.hpp" #include "Loop/Loop.hpp" +#include "IPC/IPC.hpp" #include "SWInfo/SWInfo.hpp" #include "Exit/Exit.hpp" #include "CmdLine/CmdLine.hpp" diff --git a/Source/IPC/IPCPrimitives.Linux.cpp b/Source/IPC/IPCPrimitives.Linux.cpp new file mode 100755 index 00000000..ed6bdf5f --- /dev/null +++ b/Source/IPC/IPCPrimitives.Linux.cpp @@ -0,0 +1,323 @@ +/*** + 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 + +namespace Aurora::IPC +{ + #define PROXY_INTERNAL_INTERFACE(Base)\ + virtual void OnPresleep() override \ + { \ + Base.OnPresleep(); \ + }; \ + virtual bool OnTrigger(AuUInt handle) override \ + { \ + return Base.OnTrigger(handle); \ + } \ + virtual void OnFinishSleep() override \ + { \ + Base.OnFinishSleep(); \ + } \ + virtual bool Singular() override \ + { \ + return Base.Singular(); \ + } \ + virtual AuUInt GetHandle() override \ + { \ + return Base.GetHandle(); \ + } \ + virtual AuList GetHandles() override \ + { \ + return Base.GetHandles(); \ + } \ + virtual AuList GetWriteHandles() override \ + { \ + return Base.GetWriteHandles(); \ + } \ + virtual AuUInt GetWriteHandle() override \ + { \ + return Base.GetWriteHandle(); \ + } + + #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 event_.Set(); + } + + bool IPCEventProxy::Reset() + { + return event_.Reset(); + } + + bool IPCEventProxy::IsSignaled() + { + return event_.IsSignaled(); + } + + bool IPCEventProxy::WaitOn(AuUInt32 timeout) + { + return event_.WaitOn(timeout); + } + + Loop::ELoopSource IPCEventProxy::GetType() + { + return event_.GetType(); + } + + AUKN_SYM AuSPtr NewEvent(bool triggered, bool atomicRelease) + { + auto object = AuMakeShared(triggered, atomicRelease); + if (!object) + { + SysPushErrorMem(); + 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 {}; + } + + 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 semaphore_.AddOne(); + } + + bool IPCSemaphoreProxy::IsSignaled() + { + return semaphore_.IsSignaled(); + } + + bool IPCSemaphoreProxy::WaitOn(AuUInt32 timeout) + { + return semaphore_.WaitOn(timeout); + } + + Loop::ELoopSource IPCSemaphoreProxy::GetType() + { + return semaphore_.GetType(); + } + + AUKN_SYM AuSPtr NewSemaphore(int startingValue) + { + auto object = AuMakeShared(startingValue); + if (!object) + { + SysPushErrorMem(); + 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 {}; + } + + return object; + } + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Mutexes + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + AUKN_SYM AuSPtr NewMutex() + { + SysPushErrorUnimplemented(); + return {}; + } + + AUKN_SYM AuSPtr ImportMutex(const AuString &handle) + { + SysPushErrorUnimplemented(); + return {}; + } + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // 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/IPCPrimitives.Linux.hpp b/Source/IPC/IPCPrimitives.Linux.hpp new file mode 100755 index 00000000..e2aebe43 --- /dev/null +++ b/Source/IPC/IPCPrimitives.Linux.hpp @@ -0,0 +1,13 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: IPCPrimitives.Linux.hpp + Date: 2022-4-13 + Author: Reece +***/ +#pragma once + +namespace Aurora::IPC +{ + +} \ No newline at end of file diff --git a/Source/IPC/IPCPrimitives.NT.cpp b/Source/IPC/IPCPrimitives.NT.cpp new file mode 100755 index 00000000..7250047c --- /dev/null +++ b/Source/IPC/IPCPrimitives.NT.cpp @@ -0,0 +1,16 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: IPCPrimitives.NT.cpp + Date: 2022-4-13 + Author: Reece +***/ +#include +#include "IPC.hpp" +#include "IPCHandle.hpp" +#include "IPCPrimitives.NT.hpp" + +namespace Aurora::IPC +{ + +} \ No newline at end of file diff --git a/Source/IPC/IPCPrimitives.NT.hpp b/Source/IPC/IPCPrimitives.NT.hpp new file mode 100755 index 00000000..817e7ea8 --- /dev/null +++ b/Source/IPC/IPCPrimitives.NT.hpp @@ -0,0 +1,13 @@ +/*** + Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. + + File: IPCPrimitives.NT.hpp + Date: 2022-4-13 + Author: Reece +***/ +#pragma once + +namespace Aurora::IPC +{ + +} \ No newline at end of file diff --git a/Source/Loop/LSEvent.Linux.cpp b/Source/Loop/LSEvent.Linux.cpp index 34f703b2..466d39e2 100644 --- a/Source/Loop/LSEvent.Linux.cpp +++ b/Source/Loop/LSEvent.Linux.cpp @@ -16,12 +16,17 @@ namespace Aurora::Loop Init(triggered); } + LSEvent::LSEvent(int handle, bool triggered, bool atomicRelease) : atomicRelease_(atomicRelease) + { + this->handle = handle; + } + LSEvent::~LSEvent() { if ((this->handle != 0) && (this->handle != -1)) { - close(this->handle); + close(AuExchange(this->handle, -1)); } } @@ -39,7 +44,7 @@ namespace Aurora::Loop void LSEvent::Init(bool init) { - handle = eventfd(init ? 1 : 0, EFD_NONBLOCK); + this->handle = eventfd(init ? 1 : 0, EFD_NONBLOCK); } bool LSEvent::Set() diff --git a/Source/Loop/LSEvent.Linux.hpp b/Source/Loop/LSEvent.Linux.hpp index bed8708c..133c38e8 100644 --- a/Source/Loop/LSEvent.Linux.hpp +++ b/Source/Loop/LSEvent.Linux.hpp @@ -13,6 +13,7 @@ namespace Aurora::Loop struct LSEvent : public ILSEvent, public LSHandle { LSEvent(bool triggered, bool atomicRelease, bool permitMultipleTriggers); + LSEvent(int handle, bool triggered, bool atomicRelease); ~LSEvent(); bool Set() override; diff --git a/Source/Loop/LSSemaphore.Linux.cpp b/Source/Loop/LSSemaphore.Linux.cpp index 5c1e0359..a8583050 100644 --- a/Source/Loop/LSSemaphore.Linux.cpp +++ b/Source/Loop/LSSemaphore.Linux.cpp @@ -16,15 +16,20 @@ namespace Aurora::Loop Init(initialCount); } + LSSemaphore::LSSemaphore(int handle, int tag) + { + this->handle = handle; + } + LSSemaphore::~LSSemaphore() { if ((this->handle != 0) && (this->handle != -1)) { - ::close(this->handle); + ::close(AuExchange(this->handle, -1)); } } - + void LSSemaphore::Init(AuUInt32 initialCount) { handle = eventfd(initialCount, EFD_SEMAPHORE | EFD_NONBLOCK); diff --git a/Source/Loop/LSSemaphore.Linux.hpp b/Source/Loop/LSSemaphore.Linux.hpp index 1c4aa4e0..a3860284 100644 --- a/Source/Loop/LSSemaphore.Linux.hpp +++ b/Source/Loop/LSSemaphore.Linux.hpp @@ -13,6 +13,7 @@ namespace Aurora::Loop struct LSSemaphore : public ILSSemaphore, public LSHandle { LSSemaphore(AuUInt32 initialCount); + LSSemaphore(int handle, int tag); ~LSSemaphore(); bool AddOne() override;