diff --git a/Src/IACore/inc/IACore/File.hpp b/Src/IACore/inc/IACore/File.hpp index 256759f..4625bf6 100644 --- a/Src/IACore/inc/IACore/File.hpp +++ b/Src/IACore/inc/IACore/File.hpp @@ -250,7 +250,7 @@ namespace IACore size_ = static_cast(size.QuadPart); // 3. Create Mapping Object - hMapping_ = ::CreateFileMappingA(hFile_, nullptr, PAGE_READONLY, 0, 0, nullptr); + hMapping_ = ::CreateFileMappingA(hFile_, nullptr, PAGE_READWRITE, 0, 0, nullptr); if (!hMapping_) { Close(); @@ -258,7 +258,7 @@ namespace IACore } // 4. Map View - data_ = ::MapViewOfFile(hMapping_, FILE_MAP_READ, 0, 0, 0); + data_ = ::MapViewOfFile(hMapping_, FILE_MAP_ALL_ACCESS, 0, 0, 0); if (!data_) { Close(); @@ -267,7 +267,7 @@ namespace IACore #else // LINUX / POSIX // 1. Open File - fd_ = ::open(filepath.c_str(), O_RDONLY); + fd_ = ::open(filepath.c_str(), O_RDWR); if (fd_ == -1) return false; @@ -283,7 +283,7 @@ namespace IACore // 3. mmap // PROT_READ: Read only // MAP_PRIVATE: Copy-on-write (safe if you accidentally modify, though we return const) - data_ = ::mmap(nullptr, size_, PROT_READ, MAP_PRIVATE, fd_, 0); + data_ = ::mmap(nullptr, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd_, 0); if (data_ == MAP_FAILED) { data_ = nullptr; diff --git a/Src/IACore/inc/IACore/PCH.hpp b/Src/IACore/inc/IACore/PCH.hpp index 9375ebd..af67102 100644 --- a/Src/IACore/inc/IACore/PCH.hpp +++ b/Src/IACore/inc/IACore/PCH.hpp @@ -26,6 +26,8 @@ # include # include # include +# include +# include # include # include # include @@ -534,6 +536,9 @@ using StringStream = std::stringstream; using HRClock = std::chrono::high_resolution_clock; using HRTimePoint = std::chrono::time_point; +using Mutex = std::mutex; +using LockGuard = std::lock_guard; + template using FormatterString = std::format_string; #endif diff --git a/Src/IACore/inc/IACore/Process.hpp b/Src/IACore/inc/IACore/Process.hpp index 299ab63..a03b0e5 100644 --- a/Src/IACore/inc/IACore/Process.hpp +++ b/Src/IACore/inc/IACore/Process.hpp @@ -40,6 +40,35 @@ namespace IACore #endif } + // --------------------------------------------------------------------- + // Async Execution + // --------------------------------------------------------------------- + + // Returns a jthread. + // - Store it if you want to wait for it later (join). + // - If you destroy the returned jthread immediately, it will BLOCK (join) by design. + // - If you want "fire and forget", call .detach() on the returned thread. + STATIC std::jthread RunAsync(String cmd, String args, Function onOutputLine, + Function)> onComplete) + { + // We capture arguments by VALUE (=) to ensure the thread owns its own copies of the strings. + return std::jthread([=, cmd = std::move(cmd), args = std::move(args)]() mutable { + tl::expected result = tl::make_unexpected("Not started"); + +#if IA_PLATFORM_WINDOWS + result = RunWindows(cmd, args, onOutputLine); +#else + result = RunPosix(cmd, args, onOutputLine); +#endif + + // Report final result to the callback + if (onComplete) + { + onComplete(std::move(result)); + } + }); + } + private: // --------------------------------------------------------------------- // Output Buffering Helper diff --git a/Src/IACore/inc/IACore/SocketOps.hpp b/Src/IACore/inc/IACore/SocketOps.hpp new file mode 100644 index 0000000..0db9df3 --- /dev/null +++ b/Src/IACore/inc/IACore/SocketOps.hpp @@ -0,0 +1,96 @@ +// 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 . + +#pragma once + +#include + +#if IA_PLATFORM_WINDOWS + +# include +# pragma comment(lib, "ws2_32.lib") +# define CLOSE_SOCKET(s) closesocket(s) +# define IS_VALID_SOCKET(s) (s != INVALID_SOCKET) +using SocketHandle = SOCKET; + +#elif IA_PLATFORM_UNIX + +# include +# include +# include +# define CLOSE_SOCKET(s) close(s) +# define IS_VALID_SOCKET(s) (s >= 0) +# define INVALID_SOCKET -1 +using SocketHandle = int; + +#else + +# warning "IACore SocketOps is not supported on this platform." + +#endif + +namespace IACore +{ + class SocketOps + { + public: + STATIC VOID Initialize() + { +#if IA_PLATFORM_WINDOWS + WSADATA wsaData; + WSAStartup(MAKEWORD(2, 2), &wsaData); +#endif + } + + STATIC VOID Terminate() + { +#if IA_PLATFORM_WINDOWS + WSACleanup(); +#endif + } + + STATIC BOOL IsPortAvailableTCP(IN UINT16 port) + { + return IsPortAvailable(port, SOCK_STREAM); + } + + STATIC BOOL IsPortAvailableUDP(IN UINT16 port) + { + return IsPortAvailable(port, SOCK_DGRAM); + } + + private: + STATIC BOOL IsPortAvailable(IN UINT16 port, IN INT32 type) + { + SocketHandle sock = socket(AF_INET, type, IPPROTO_UDP); + if (!IS_VALID_SOCKET(sock)) + return false; + + sockaddr_in addr{}; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + bool isFree = false; + if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) == 0) + isFree = true; + + CLOSE_SOCKET(sock); + + return isFree; + } + }; +} // namespace IACore \ No newline at end of file