[+] (Linux only) IPCEvent, IPCSemaphore

This commit is contained in:
Reece Wilson 2022-04-14 20:40:35 +01:00
parent 37cb35d997
commit 44839e6234
20 changed files with 468 additions and 53 deletions

View File

@ -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;
};
}

16
Include/Aurora/IPC/IPC.hpp Executable file
View File

@ -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
{
}

View File

@ -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
***/

View File

@ -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
***/

View File

@ -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
***/

View File

@ -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
***/

View File

@ -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
***/

View File

@ -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
***/

View File

@ -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<Loop::ILoopSource> 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<IPCEvent> NewEvent(bool triggered, bool atomicRelease);
AUKN_SYM AuSPtr<IPCEvent> ImportEvent(const AuString &handle);
AUKN_SYM AuSPtr<IPCSemaphore> NewSemaphore(int startingValue);
AUKN_SYM AuSPtr<IPCSemaphore> ImportSemaphore(const AuString &handle);
AUKN_SYM AuSPtr<IPCMutex> NewMutex();
AUKN_SYM AuSPtr<IPCMutex> ImportMutex(const AuString &handle);
AUKN_SYM AuSPtr<IPCPipe> NewPipe();
AUKN_SYM AuSPtr<IPCPipe> ImportPipe(const AuString &handle);
}

View File

@ -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<ILoopSource> &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<ILoopSource> &source, AuUInt32 timeoutMS) = 0;
@ -106,7 +108,6 @@ namespace Aurora::Loop
*/
virtual bool AddCallback(const AuSPtr<ILoopSourceSubscriber> &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<AuSPtr<ILoopSource>> 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<ILoopQueue> NewLoopQueue();

View File

@ -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

View File

@ -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"

View File

@ -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 <Source/RuntimeInternal.hpp>
#include "IPC.hpp"
#include "IPCHandle.hpp"
#include "IPCPrimitives.Linux.hpp"
#include <Source/Loop/LSEvent.hpp>
#include <Source/Loop/LSSemaphore.hpp>
#include <Source/IPC/IPC.hpp>
#include <Source/IPC/IPCHandle.hpp>
#include <Source/IO/UNIX/FDIpcServer.hpp>
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<AuUInt> GetHandles() override \
{ \
return Base.GetHandles(); \
} \
virtual AuList<AuUInt> 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<IPCEvent> NewEvent(bool triggered, bool atomicRelease)
{
auto object = AuMakeShared<IPCEventProxy>(triggered, atomicRelease);
if (!object)
{
SysPushErrorMem();
return {};
}
return object;
}
AUKN_SYM AuSPtr<IPCEvent> 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<IPCEventProxy>(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<IPCSemaphore> NewSemaphore(int startingValue)
{
auto object = AuMakeShared<IPCSemaphoreProxy>(startingValue);
if (!object)
{
SysPushErrorMem();
return {};
}
return object;
}
AUKN_SYM AuSPtr<IPCSemaphore> 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<IPCSemaphoreProxy>(fd, 0xC001C0DE);
if (!object)
{
SysPushErrorMem();
::close(fd);
return {};
}
return object;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Mutexes
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
AUKN_SYM AuSPtr<IPCMutex> NewMutex()
{
SysPushErrorUnimplemented();
return {};
}
AUKN_SYM AuSPtr<IPCMutex> ImportMutex(const AuString &handle)
{
SysPushErrorUnimplemented();
return {};
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Pipes
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
AUKN_SYM AuSPtr<IPCPipe> NewPipe()
{
SysPushErrorUnimplemented();
return {};
}
AUKN_SYM AuSPtr<IPCPipe> ImportPipe(const AuString &handle)
{
SysPushErrorUnimplemented();
return {};
}
}

View File

@ -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
{
}

16
Source/IPC/IPCPrimitives.NT.cpp Executable file
View File

@ -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 <Source/RuntimeInternal.hpp>
#include "IPC.hpp"
#include "IPCHandle.hpp"
#include "IPCPrimitives.NT.hpp"
namespace Aurora::IPC
{
}

13
Source/IPC/IPCPrimitives.NT.hpp Executable file
View File

@ -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
{
}

View File

@ -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()

View File

@ -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;

View File

@ -16,12 +16,17 @@ 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));
}
}

View File

@ -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;