Fixes
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
set(SRC_FILES
|
||||
"imp/cpp/IPC.cpp"
|
||||
"imp/cpp/JSON.cpp"
|
||||
"imp/cpp/IACore.cpp"
|
||||
"imp/cpp/Logger.cpp"
|
||||
|
||||
@ -28,15 +28,93 @@ namespace IACore
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
::UnmapViewOfFile(std::get<1>(handles));
|
||||
::CloseHandle(std::get<2>(handles));
|
||||
::CloseHandle(std::get<0>(handles));
|
||||
|
||||
if (std::get<0>(handles) != INVALID_HANDLE_VALUE)
|
||||
::CloseHandle(std::get<0>(handles));
|
||||
#elif IA_PLATFORM_UNIX
|
||||
::munmap(std::get<1>(handles), (SIZE_T) std::get<2>(handles));
|
||||
::close((INT32) ((UINT64) std::get<0>(handles)));
|
||||
const auto fd = (INT32) ((UINT64) std::get<0>(handles));
|
||||
if (fd != -1)
|
||||
::close(fd);
|
||||
#else
|
||||
# error "IACore FileOps does not support this platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
Expected<PCUINT8, String> FileOps::MapSharedMemory(IN CONST String &name, IN SIZE_T size, IN BOOL isOwner)
|
||||
{
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
int wchars_num = MultiByteToWideChar(CP_UTF8, 0, name.c_str(), -1, NULL, 0);
|
||||
std::wstring wName(wchars_num, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, name.c_str(), -1, &wName[0], wchars_num);
|
||||
|
||||
HANDLE hMap = NULL;
|
||||
if (isOwner)
|
||||
hMap = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, (DWORD) (size >> 32),
|
||||
(DWORD) (size & 0xFFFFFFFF), wName.c_str());
|
||||
else
|
||||
hMap = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, wName.c_str());
|
||||
|
||||
if (hMap == NULL)
|
||||
return MakeUnexpected(
|
||||
std::format("Failed to {} shared memory '{}'", isOwner ? "owner" : "consumer", name.c_str()));
|
||||
|
||||
const auto result = static_cast<PCUINT8>(MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, size));
|
||||
if (result == NULL)
|
||||
{
|
||||
CloseHandle(hMap);
|
||||
return MakeUnexpected(std::format("Failed to map view of shared memory '{}'", name.c_str()));
|
||||
}
|
||||
|
||||
s_mappedFiles[result] = std::make_tuple((PVOID) INVALID_HANDLE_VALUE, (PVOID) result, (PVOID) hMap);
|
||||
return result;
|
||||
|
||||
#elif IA_PLATFORM_UNIX
|
||||
int fd = -1;
|
||||
if (isOwner)
|
||||
{
|
||||
fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0666);
|
||||
if (fd != -1)
|
||||
{
|
||||
if (ftruncate(fd, size) == -1)
|
||||
{
|
||||
close(fd);
|
||||
shm_unlink(name.c_str());
|
||||
return MakeUnexpected(std::format("Failed to truncate shared memory '{}'", name.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
fd = shm_open(name.c_str(), O_RDWR, 0666);
|
||||
|
||||
if (fd == -1)
|
||||
return MakeUnexpected(
|
||||
std::format("Failed to {} shared memory '{}'", isOwner ? "owner" : "consumer", name.c_str()));
|
||||
|
||||
void *addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (addr == MAP_FAILED)
|
||||
{
|
||||
close(fd);
|
||||
return MakeUnexpected(std::format("Failed to mmap shared memory '{}'", name.c_str()));
|
||||
}
|
||||
|
||||
const auto result = static_cast<PCUINT8>(addr);
|
||||
|
||||
s_mappedFiles[result] = std::make_tuple((PVOID) ((UINT64) fd), (PVOID) addr, (PVOID) size);
|
||||
return result;
|
||||
|
||||
#else
|
||||
# error "IACore FileOps does not support this platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID FileOps::UnlinkSharedMemory(IN CONST String &name)
|
||||
{
|
||||
#if IA_PLATFORM_UNIX
|
||||
shm_unlink(name.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
Expected<PCUINT8, String> FileOps::MapFile(IN CONST FilePath &path, OUT SIZE_T &size)
|
||||
{
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
@ -192,7 +270,7 @@ namespace IACore
|
||||
result = "./" + result;
|
||||
return FilePath(result);
|
||||
#else
|
||||
# error "unreachable. previous checks must have stopped compilation beforehand .unsupported platform."
|
||||
# error "IACore FileOps does not support this platform"
|
||||
#endif
|
||||
}
|
||||
} // namespace IACore
|
||||
22
Src/IACore/imp/cpp/IPC.cpp
Normal file
22
Src/IACore/imp/cpp/IPC.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <IACore/IPC.hpp>
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
|
||||
}
|
||||
@ -18,6 +18,54 @@
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
BOOL SocketOps::Listen(IN SocketHandle sock, IN INT32 queueSize)
|
||||
{
|
||||
return listen(sock, queueSize) == 0;
|
||||
}
|
||||
|
||||
SocketHandle SocketOps::CreateUnixSocket()
|
||||
{
|
||||
return socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
}
|
||||
|
||||
BOOL SocketOps::BindUnixSocket(IN SocketHandle sock, IN PCCHAR path)
|
||||
{
|
||||
if (!IS_VALID_SOCKET(sock))
|
||||
return FALSE;
|
||||
|
||||
UNLINK_FILE(path);
|
||||
|
||||
sockaddr_un addr{};
|
||||
addr.sun_family = AF_UNIX;
|
||||
|
||||
size_t maxLen = sizeof(addr.sun_path) - 1;
|
||||
|
||||
strncpy(addr.sun_path, path, maxLen);
|
||||
|
||||
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) == -1)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL SocketOps::ConnectUnixSocket(IN SocketHandle sock, IN PCCHAR path)
|
||||
{
|
||||
if (!IS_VALID_SOCKET(sock))
|
||||
return FALSE;
|
||||
|
||||
sockaddr_un addr{};
|
||||
addr.sun_family = AF_UNIX;
|
||||
|
||||
size_t maxLen = sizeof(addr.sun_path) - 1;
|
||||
|
||||
strncpy(addr.sun_path, path, maxLen);
|
||||
|
||||
if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) == -1)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL SocketOps::IsPortAvailable(IN UINT16 port, IN INT32 type)
|
||||
{
|
||||
SocketHandle sock = socket(AF_INET, type, IPPROTO_UDP);
|
||||
|
||||
143
Src/IACore/inc/IACore/ADT/RingBuffer.hpp
Normal file
143
Src/IACore/inc/IACore/ADT/RingBuffer.hpp
Normal file
@ -0,0 +1,143 @@
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <IACore/PCH.hpp>
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
class RingBufferView
|
||||
{
|
||||
public:
|
||||
STATIC CONSTEXPR UINT16 PACKET_ID_SKIP = 0;
|
||||
|
||||
struct ControlBlock
|
||||
{
|
||||
alignas(64) Atomic<UINT32> WriteOffset{0};
|
||||
alignas(64) Atomic<UINT32> ReadOffset{0};
|
||||
UINT32 Capacity;
|
||||
|
||||
// Padding to ensure data starts on a cache line
|
||||
UINT8 _padding[64 - sizeof(UINT32) * 3];
|
||||
};
|
||||
|
||||
// All of the data in ring buffer will be stored as packets
|
||||
struct PacketHeader
|
||||
{
|
||||
UINT16 ID{};
|
||||
UINT16 PayloadSize{};
|
||||
};
|
||||
|
||||
public:
|
||||
INLINE RingBufferView(IN Span<UINT8> buffer);
|
||||
|
||||
INLINE BOOL Pop(OUT PacketHeader &outHeader, OUT Span<UINT8> outBuffer);
|
||||
INLINE BOOL Push(IN UINT16 packetID, IN Span<CONST UINT8> data);
|
||||
|
||||
INLINE ControlBlock *GetControlBlock();
|
||||
|
||||
private:
|
||||
PUINT8 m_dataPtr{};
|
||||
UINT32 m_capacity{};
|
||||
ControlBlock *m_controlBlock{};
|
||||
|
||||
private:
|
||||
INLINE VOID WritePacket(IN UINT32 offset, IN UINT16 id, IN PCVOID data, IN UINT16 dataSize);
|
||||
};
|
||||
} // namespace IACore
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
RingBufferView::RingBufferView(IN Span<UINT8> buffer)
|
||||
{
|
||||
IA_ASSERT(buffer.size() > sizeof(ControlBlock));
|
||||
|
||||
m_controlBlock = reinterpret_cast<ControlBlock *>(buffer.data());
|
||||
m_dataPtr = buffer.data() + sizeof(ControlBlock);
|
||||
m_controlBlock->Capacity = m_capacity = buffer.size() - sizeof(ControlBlock);
|
||||
}
|
||||
|
||||
BOOL RingBufferView::Pop(OUT PacketHeader &outHeader, OUT Span<UINT8> outBuffer)
|
||||
{
|
||||
UINT32 currentWriteOffset = m_controlBlock->WriteOffset.load(std::memory_order_acquire);
|
||||
UINT32 currentReadOffset = m_controlBlock->ReadOffset.load(std::memory_order_acquire);
|
||||
|
||||
if (currentReadOffset == currentWriteOffset)
|
||||
return false;
|
||||
|
||||
const auto header = reinterpret_cast<PacketHeader *>(m_dataPtr + currentReadOffset);
|
||||
|
||||
if (header->ID == PACKET_ID_SKIP)
|
||||
{
|
||||
m_controlBlock->ReadOffset.store(0, std::memory_order_release);
|
||||
return Pop(outHeader, outBuffer);
|
||||
}
|
||||
|
||||
outHeader = *header;
|
||||
if (outHeader.PayloadSize > outBuffer.size())
|
||||
return false;
|
||||
|
||||
memcpy(outBuffer.data(), m_dataPtr + currentReadOffset + sizeof(PacketHeader), outHeader.PayloadSize);
|
||||
m_controlBlock->ReadOffset.store(currentReadOffset + sizeof(PacketHeader) + outHeader.PayloadSize, std::memory_order_release);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL RingBufferView::Push(IN UINT16 packetID, IN Span<CONST UINT8> data)
|
||||
{
|
||||
IA_ASSERT(data.size() <= UINT16_MAX);
|
||||
|
||||
UINT32 currentWriteOffset = m_controlBlock->WriteOffset.load(std::memory_order_acquire);
|
||||
UINT32 currentReadOffset = m_controlBlock->ReadOffset.load(std::memory_order_acquire);
|
||||
|
||||
UINT32 requiredSpace = sizeof(PacketHeader) + data.size();
|
||||
if (currentWriteOffset + requiredSpace <= m_capacity)
|
||||
{
|
||||
WritePacket(currentWriteOffset, packetID, data.data(), static_cast<UINT16>(data.size()));
|
||||
m_controlBlock->WriteOffset.store(currentWriteOffset + requiredSpace, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
UINT32 remainingAtEnd = m_capacity - currentWriteOffset;
|
||||
if (requiredSpace < currentReadOffset)
|
||||
{
|
||||
if (remainingAtEnd >= sizeof(PacketHeader))
|
||||
{
|
||||
const auto p = PacketHeader{PACKET_ID_SKIP, 0};
|
||||
memcpy(m_dataPtr + currentWriteOffset, &p, sizeof(p));
|
||||
}
|
||||
|
||||
WritePacket(0, packetID, data.data(), static_cast<UINT16>(data.size()));
|
||||
m_controlBlock->WriteOffset.store(requiredSpace, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
RingBufferView::ControlBlock *RingBufferView::GetControlBlock()
|
||||
{
|
||||
return m_controlBlock;
|
||||
}
|
||||
|
||||
VOID RingBufferView::WritePacket(IN UINT32 offset, IN UINT16 id, IN PCVOID data, IN UINT16 dataSize)
|
||||
{
|
||||
PacketHeader h = {id, dataSize};
|
||||
memcpy(m_dataPtr + offset, &h, sizeof(PacketHeader));
|
||||
memcpy(m_dataPtr + offset + sizeof(PacketHeader), data, dataSize);
|
||||
}
|
||||
} // namespace IACore
|
||||
@ -30,6 +30,10 @@ namespace IACore
|
||||
STATIC VOID UnmapFile(IN PCUINT8 mappedPtr);
|
||||
STATIC Expected<PCUINT8, String> MapFile(IN CONST FilePath &path, OUT SIZE_T &size);
|
||||
|
||||
// @param `isOwner` TRUE to allocate/truncate. FALSE to just open.
|
||||
STATIC Expected<PCUINT8, String> MapSharedMemory(IN CONST String &name, IN SIZE_T size, IN BOOL isOwner);
|
||||
STATIC VOID UnlinkSharedMemory(IN CONST String &name);
|
||||
|
||||
STATIC Expected<StreamReader, String> StreamFromFile(IN CONST FilePath &path);
|
||||
STATIC Expected<StreamWriter, String> StreamToFile(IN CONST FilePath &path, IN BOOL overwrite = false);
|
||||
|
||||
|
||||
34
Src/IACore/inc/IACore/IPC.hpp
Normal file
34
Src/IACore/inc/IACore/IPC.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <IACore/PCH.hpp>
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
class IPC_Node
|
||||
{
|
||||
public:
|
||||
|
||||
};
|
||||
|
||||
class IPC_Server
|
||||
{
|
||||
public:
|
||||
|
||||
};
|
||||
}
|
||||
@ -21,19 +21,24 @@
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
|
||||
# include <winsock2.h>
|
||||
# include <ws2tcpip.h>
|
||||
# include <afunix.h>
|
||||
# pragma comment(lib, "ws2_32.lib")
|
||||
# define CLOSE_SOCKET(s) closesocket(s)
|
||||
# define IS_VALID_SOCKET(s) (s != INVALID_SOCKET)
|
||||
# define UNLINK_FILE(p) DeleteFileA(p)
|
||||
using SocketHandle = SOCKET;
|
||||
|
||||
#elif IA_PLATFORM_UNIX
|
||||
|
||||
# include <sys/un.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# define CLOSE_SOCKET(s) close(s)
|
||||
# define IS_VALID_SOCKET(s) (s >= 0)
|
||||
# define INVALID_SOCKET -1
|
||||
# define UNLINK_FILE(p) unlink(p)
|
||||
using SocketHandle = int;
|
||||
|
||||
#else
|
||||
@ -72,6 +77,13 @@ namespace IACore
|
||||
return IsPortAvailable(port, SOCK_DGRAM);
|
||||
}
|
||||
|
||||
STATIC BOOL Listen(IN SocketHandle sock, IN INT32 queueSize = 5);
|
||||
|
||||
STATIC SocketHandle CreateUnixSocket();
|
||||
|
||||
STATIC BOOL BindUnixSocket(IN SocketHandle sock, IN PCCHAR path);
|
||||
STATIC BOOL ConnectUnixSocket(IN SocketHandle sock, IN PCCHAR path);
|
||||
|
||||
private:
|
||||
STATIC BOOL IsPortAvailable(IN UINT16 port, IN INT32 type);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user