From 7ffaa826a49c1ce8db96eec49ce28a69f8a86d50 Mon Sep 17 00:00:00 2001 From: Marco Edoardo Santimaria Date: Fri, 19 Jun 2026 11:02:29 +0200 Subject: [PATCH 1/4] Code cleanup and refactor --- CMakeLists.txt | 6 +- include/IOWrapper.hpp | 7 +- include/OsPath.hpp | 125 ++-------- include/PyCapioException.hpp | 30 +-- include/ScandirIteratorWrapper.hpp | 80 ++----- include/_libcapio_impl.hpp | 358 ++++++++++++++++++++++++++++ include/libcapio.hpp | 370 +++-------------------------- src/OsPath.cpp | 102 ++++++++ src/PyCapioException.cpp | 29 +++ src/ScandirIteratorWrapper.cpp | 74 ++++++ src/pycapio.cpp | 14 +- 11 files changed, 662 insertions(+), 533 deletions(-) create mode 100644 include/_libcapio_impl.hpp create mode 100644 src/OsPath.cpp create mode 100644 src/PyCapioException.cpp create mode 100644 src/ScandirIteratorWrapper.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 89753b1..5fde628 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,9 @@ install( # PYBIND11 TARGET ######################## -pybind11_add_module(_pycapio src/pycapio.cpp) +file(GLOB PYCAPIO_SOURCES "${CMAKE_SOURCE_DIR}/src/*.cpp") + +pybind11_add_module(_pycapio ${PYCAPIO_SOURCES}) # patch server_println by copying server_println.hpp from server/utils/server_println.hpp to posix/utils/server_println.hpp file(COPY "${capio_SOURCE_DIR}/capio/server/include/utils/server_println.hpp" @@ -70,12 +72,14 @@ file(COPY "${capio_SOURCE_DIR}/capio/server/include/utils/server_println.hpp" message(WARNING "WARN: patch for server_println.hpp copied to posix has been applied!") target_compile_definitions(_pycapio PRIVATE PYCAPIO_BINDINGS) +target_compile_definitions(_pycapio PRIVATE CAPIO_VERSION="${CMAKE_PROJECT_VERSION}") message(STATUS "CAPIO_PREFIX = ${capio_SOURCE_DIR}") target_include_directories(_pycapio PRIVATE ${capio_SOURCE_DIR}/capio ${capio_SOURCE_DIR}/capio/posix + ${CMAKE_SOURCE_DIR}/include ) target_compile_options( diff --git a/include/IOWrapper.hpp b/include/IOWrapper.hpp index a1089b3..6f982a0 100644 --- a/include/IOWrapper.hpp +++ b/include/IOWrapper.hpp @@ -1,3 +1,8 @@ +// TODO: This file should be split into header and source file. however, it is not yet possible +// due to the fact that CAPIO within its POSIX component is a header only target, with global +// variables not declared inline. As soon as the POSIX component is refactored, it will be +// possible to move this file as a .cpp file + #ifndef LIBCAPIO_IOWRAPPER_HPP #define LIBCAPIO_IOWRAPPER_HPP #include @@ -58,7 +63,7 @@ template class IOWrapper { const auto write_size = libcapio_write(_file_descriptor, text.data(), text.size()); if (write_size != static_cast(text.size())) { throw PyCapioException("write failed: received from libcapio offset: " + - std::to_string(write_size)); + std::to_string(write_size)); } return write_size; } diff --git a/include/OsPath.hpp b/include/OsPath.hpp index d772327..346e227 100644 --- a/include/OsPath.hpp +++ b/include/OsPath.hpp @@ -1,112 +1,33 @@ -#ifndef LIBCAPIO__CAPIOOSPATH_HPP -#define LIBCAPIO__CAPIOOSPATH_HPP +#pragma once -#include +#include #include +#include class OsPath { public: /** - * LIBCAPIO METHODS + * LIBCAPIO METHODS **/ - - static bool exists(const std::string &path) { - struct stat statbuf{}; - if (libcapio_stat(path.c_str(), &statbuf) == -1 && errno == ENOENT) { - return false; - } - return true; - } - - static bool isfile(const std::string &path) { - struct stat statbuf{}; - if (libcapio_stat(path.c_str(), &statbuf) == -1 && errno == ENOENT) { - return false; - } - - return (statbuf.st_mode & S_IFMT) == S_IFREG; - } - - static bool isdir(const std::string &path) { return !isfile(path); } - - static uintmax_t getsize(const std::string &path) { - struct stat statbuf{}; - if (libcapio_stat(path.c_str(), &statbuf) == -1 && errno == ENOENT) { - return 0; - } - return statbuf.st_size; - } + static bool exists(const std::string &path); + static bool isfile(const std::string &path); + static bool isdir(const std::string &path); + static uintmax_t getsize(const std::string &path); /** - * NON LIBCAPIO METHODS + * NON LIBCAPIO METHODS **/ - - static std::string basename(const std::string &path) { - return std::filesystem::path(path).filename().string(); - } - - static std::string dirname(const std::string &path) { - return std::filesystem::path(path).parent_path().string(); - } - - static std::string abspath(const std::string &path) { - return std::filesystem::absolute(path).string(); - } - - static std::pair splitext(const std::string &path) { - std::filesystem::path p(path); - return {p.stem().string(), p.extension().string()}; - } - - static bool isabs(const std::string &p) { return std::filesystem::path(p).is_absolute(); } - - static std::string normpath(const std::string &p) { - return std::filesystem::path(p).lexically_normal().string(); - } - - static std::string relpath(const std::string &path, const std::string &start = ".") { - return std::filesystem::relative(path, start).string(); - } - - static double getmtime(const std::string &path) { - auto ftime = std::filesystem::last_write_time(path); - auto sctp = std::chrono::time_point_cast(ftime); - return static_cast(sctp.time_since_epoch().count()); - } - - static bool samefile(const std::string &p1, const std::string &p2) { - return std::filesystem::equivalent(p1, p2); - } - - static std::pair split(const std::string &p) { - std::filesystem::path path(p); - return {path.parent_path().string(), path.filename().string()}; - } - - // On Unix, normcase simply returns the path unchanged. - static std::string normcase(const std::string &p) { return p; } - - static std::string realpath(const std::string &path) { - try { - return std::filesystem::canonical(path).string(); - } catch (const std::filesystem::filesystem_error &) { - return ""; - } - } - - static std::string join(const std::string &path1, const std::string &path2) { - if (path1.empty() && path2.empty()) { - return ""; - } - if (path1.empty() && !path2.empty()) { - return path2; - } - if (path2.empty() && !path1.empty()) { - return path1; - } - - return std::filesystem::path(path1) / path2; - } -}; - -#endif // LIBCAPIO__CAPIOOSPATH_HPP + static std::string basename(const std::string &path); + static std::string dirname(const std::string &path); + static std::string abspath(const std::string &path); + static std::pair splitext(const std::string &path); + static bool isabs(const std::string &p); + static std::string normpath(const std::string &p); + static std::string relpath(const std::string &path, const std::string &start = "."); + static double getmtime(const std::string &path); + static bool samefile(const std::string &p1, const std::string &p2); + static std::pair split(const std::string &p); + static std::string normcase(const std::string &p); + static std::string realpath(const std::string &path); + static std::string join(const std::string &path1, const std::string &path2); +}; \ No newline at end of file diff --git a/include/PyCapioException.hpp b/include/PyCapioException.hpp index 67dca88..60083b8 100644 --- a/include/PyCapioException.hpp +++ b/include/PyCapioException.hpp @@ -1,36 +1,18 @@ #ifndef PYCAPIO_EXCEPTION_HPP #define PYCAPIO_EXCEPTION_HPP + #include -#include -#include -#include -#include #include class PyCapioException : public std::exception { std::string _message; - static std::string capture_python_stack() { - try { - const auto traceback = pybind11::module_::import("traceback"); - const auto io = pybind11::module_::import("io"); - auto string_io = io.attr("StringIO")(); - traceback.attr("print_stack")(pybind11::none(), pybind11::none(), string_io); - return string_io.attr("getvalue")().cast(); - } catch (const pybind11::error_already_set &e) { - return std::string("[failed to capture Python stack: ") + e.what() + "]"; - } catch (...) { - return "[failed to capture Python stack: unknown error]"; - } - } + static std::string capture_python_stack(); public: - explicit PyCapioException(const std::string &error_message) - : _message("PyCapioException: " + error_message + "\nPython stack trace:\n" + - capture_python_stack()) { - std::cerr << _message << std::endl; - } + explicit PyCapioException(const std::string &error_message); - [[nodiscard]] const char *what() const noexcept override { return _message.c_str(); } + [[nodiscard]] const char *what() const noexcept override; }; -#endif // PYCAPIO_EXCEPTION_HPP + +#endif // PYCAPIO_EXCEPTION_HPP \ No newline at end of file diff --git a/include/ScandirIteratorWrapper.hpp b/include/ScandirIteratorWrapper.hpp index 288eeb5..c22ccbf 100644 --- a/include/ScandirIteratorWrapper.hpp +++ b/include/ScandirIteratorWrapper.hpp @@ -1,8 +1,10 @@ -#ifndef LIBCAPIO__CAPIOSCANDIRITERATORWRAPPER_HPP -#define LIBCAPIO__CAPIOSCANDIRITERATORWRAPPER_HPP -#include "libcapio.hpp" +#ifndef LIBCAPIO_SCANDIR_ITERATOR_WRAPPER_HPP +#define LIBCAPIO_SCANDIR_ITERATOR_WRAPPER_HPP +#include #include +#include +#include class CapioDirEntry { std::filesystem::path base_path; @@ -11,24 +13,14 @@ class CapioDirEntry { unsigned char type_; public: - CapioDirEntry(const std::filesystem::path &base, const dirent64 &ent) - : base_path(base), name_(ent.d_name), ino_(ent.d_ino), type_(ent.d_type) {} - - [[nodiscard]] std::string name() const { return name_; } - - [[nodiscard]] std::string path() const { return (base_path / name_).string(); } - - [[nodiscard]] uint64_t inode() const { return ino_; } - - [[nodiscard]] bool is_dir([[maybe_unused]] bool follow_symlinks = true) const { - return type_ == DT_DIR; - } - - [[nodiscard]] bool is_file([[maybe_unused]] bool follow_symlinks = true) const { - return type_ == DT_REG; - } - - [[nodiscard]] bool is_symlink() const { return type_ == DT_LNK; } + CapioDirEntry(const std::filesystem::path &base, const dirent64 &ent); + + [[nodiscard]] std::string name() const; + [[nodiscard]] std::string path() const; + [[nodiscard]] uint64_t inode() const; + [[nodiscard]] bool is_dir(bool follow_symlinks = true) const; + [[nodiscard]] bool is_file(bool follow_symlinks = true) const; + [[nodiscard]] bool is_symlink() const; }; class ScandirIteratorWrapper { @@ -37,46 +29,12 @@ class ScandirIteratorWrapper { bool finished = false; public: - ScandirIteratorWrapper(const std::filesystem::path &path) : path(path) { - - if (!libcapio_initialized) { - throw PyCapioException("libcapio not initialized"); - } - - file_descriptor = libcapio_open(path.string().c_str(), O_RDONLY); - if (file_descriptor < 0) { - throw PyCapioException("libcapio_open failed"); - } - } - - ~ScandirIteratorWrapper() { close(); } - - CapioDirEntry next() { - if (finished) { - throw pybind11::stop_iteration(); - } - - dirent64 ent{}; - if (libcapio_readdir(file_descriptor, &ent) == 0) { - finished = true; - throw pybind11::stop_iteration(); - } - - if (strcmp(ent.d_name, ".") == 0 || strcmp(ent.d_name, "..") == 0) { - return next(); - } - - return {path, ent}; - } - - ScandirIteratorWrapper &iter() { return *this; } + explicit ScandirIteratorWrapper(const std::filesystem::path &path); + ~ScandirIteratorWrapper(); - void close() { - if (file_descriptor != -1) { - libcapio_close(file_descriptor); - file_descriptor = -1; - } - } + CapioDirEntry next(); + ScandirIteratorWrapper &iter(); + void close(); }; -#endif // LIBCAPIO__CAPIOSCANDIRITERATORWRAPPER_HPP +#endif // LIBCAPIO_SCANDIR_ITERATOR_WRAPPER_HPP \ No newline at end of file diff --git a/include/_libcapio_impl.hpp b/include/_libcapio_impl.hpp new file mode 100644 index 0000000..f89d52c --- /dev/null +++ b/include/_libcapio_impl.hpp @@ -0,0 +1,358 @@ +// TODO: This file should be split into header and source file. however, it is not yet possible +// due to the fact that CAPIO within its POSIX component is a header only target, with global +// variables not declared inline. As soon as the POSIX component is refactored, it will be +// possible to move this file as a .cpp file + +#ifndef PYCAPIO_PYCAPIO_HPP +#define PYCAPIO_PYCAPIO_HPP + +#ifndef __LIBCAPIO +#define __LIBCAPIO +#include "PyCapioException.hpp" + +#include +#include +#include +#endif + +/** + * Capio log level. + * if -1, and capio logging is enable everything is logged, otherwise, only + * logs up to CAPIO_MAX_LOG_LEVEL function calls + */ +inline bool syscall_no_intercept_flag; +#define syscall_no_intercept syscall + +#include "libcapio.hpp" + +#include +#include + +#include "common/syscall.hpp" + +#include "utils/clone.hpp" +#include "utils/filesystem.hpp" +#include "utils/snapshot.hpp" + +#include "common/logger.hpp" + +#include "handlers.hpp" + +static thread_local std::string libcapio_preamble; +static int capio_server_thread_id = -1; +static bool libcapio_initialized = false; + +// ----------------------------------------------------------------------------- +// StartupSemaphore Implementation +// ----------------------------------------------------------------------------- + +inline StartupSemaphore::StartupSemaphore(const std::string &workflow_name) + : lock_to_check(workflow_name + ".lock") { + fp = shm_open(lock_to_check.c_str(), O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); +} + +inline StartupSemaphore::~StartupSemaphore() { + if (fp != -1) { + close(fp); + shm_unlink(lock_to_check.c_str()); + } +} + +inline StartupSemaphore::operator bool() const { return fp != -1; } + +// ----------------------------------------------------------------------------- +// CAPIO Server +// ----------------------------------------------------------------------------- + +inline int bootstrap_capio_server(const std::filesystem::path &CAPIO_DIR, + const std::string &CAPIO_WORKFLOW_NAME, + const std::string &capio_server_exec_path, + const std::string &capio_cl_config, + const int await_server_timeout_seconds) { + bool server_is_started = false; + int server_thread_id = -1; + + std::string shm_name = "/dev/shm/" + CAPIO_WORKFLOW_NAME; + if (std::filesystem::exists(shm_name)) { + std::cout << libcapio_preamble << " CAPIO server is already started" << std::endl; + server_is_started = true; + } + + // check if server instance exists. If not, boot a server instance + if (!server_is_started) { + const StartupSemaphore boot_lock(CAPIO_WORKFLOW_NAME); + if (boot_lock) { + static constexpr char NO_CONFIG_FLAG[] = "--no-config"; + static constexpr char CONFIG_FLAG[] = "--config"; + static constexpr char BACKEND_FLAG[] = "--backend"; + static constexpr char NO_BACKEND_AFTER[] = "none"; + + std::cout << libcapio_preamble << " Booting up CAPIO server instance" << std::endl; + + std::vector newEnv; + for (char **env = environ; *env != nullptr; ++env) { + newEnv.emplace_back(*env); + } + + newEnv.emplace_back("CAPIO_DIR=" + CAPIO_DIR.string()); + newEnv.emplace_back("CAPIO_LOG_LEVEL=-1"); + newEnv.emplace_back("CAPIO_WORKFLOW_NAME=" + CAPIO_WORKFLOW_NAME); + + std::vector envPtrs; + for (auto &s : newEnv) { + envPtrs.push_back(&s[0]); + } + envPtrs.push_back(nullptr); + + // resolve capio_server executable if not provided as absolute path to a binary from + // PATH + std::string resolved_capio_server_exec_path = capio_server_exec_path; + if (capio_server_exec_path == "capio_server") { + const auto path = std::getenv("PATH"); + std::stringstream ss(path); + std::string item; + + while (std::getline(ss, item, ':')) { + std::filesystem::path check(item); + check /= capio_server_exec_path; + if (std::filesystem::exists(check)) { + resolved_capio_server_exec_path = check; + break; + } + } + } + + // Fail if capio_server binary executable does not exists + if (!std::filesystem::exists(resolved_capio_server_exec_path)) { + throw PyCapioException("Could not locate capio_server executable in PATH!"); + } + + char *args[6] = {const_cast(resolved_capio_server_exec_path.c_str()), + capio_cl_config.empty() ? const_cast(NO_CONFIG_FLAG) + : const_cast(CONFIG_FLAG), + capio_cl_config.empty() ? nullptr + : const_cast(capio_cl_config.c_str()), + const_cast(BACKEND_FLAG), + const_cast(NO_BACKEND_AFTER), + nullptr}; + + server_thread_id = fork(); + + if (server_thread_id == 0) { + execve(args[0], args, envPtrs.data()); + throw PyCapioException(libcapio_preamble + capio_server_exec_path + "\n" + + " EXECVE failure: " + std::string(strerror(errno))); + } + + if (server_thread_id > 0) { + std::cout << libcapio_preamble + << " Started CAPIO server with PID: " << server_thread_id << std::endl; + sleep(await_server_timeout_seconds); + // jump to attaching to shm queues and await normal execution + } else { + std::cerr << libcapio_preamble + << "Failed to FORK server thread. Error: " + + std::string(std::strerror(errno)) + << std::endl; + } + } else { + std::this_thread::sleep_for(std::chrono::milliseconds(3000)); + } + } + return server_thread_id; +} + +inline int libcapio_init(const std::filesystem::path &CAPIO_DIR, const std::string &CAPIO_APP_NAME, + const std::string &CAPIO_WORKFLOW_NAME, + const std::string &capio_server_exec_path, + const std::string &capio_cl_config, + const int await_server_timeout_seconds) { + + if (libcapio_preamble.empty()) { + char host_name[HOST_NAME_MAX]{0}; + if (gethostname(host_name, HOST_NAME_MAX) == -1) { + std::cout << "WARN: gethostname failed: " << std::strerror(errno) << std::endl; + } + const auto pid = getpid(); + libcapio_preamble = "[[LIBCAPIO::" + std::string(host_name) + "::" + CAPIO_APP_NAME + + "::" + std::to_string(pid) + "]] "; + } + + START_LOG(gettid(), "libcapio_init(CAPIO_DIR=%s, CAPIO_APP_NAME=%s, CAPIO_WORKFLOW_NAME=%s)", + CAPIO_DIR.c_str(), CAPIO_APP_NAME.c_str(), CAPIO_WORKFLOW_NAME.c_str()); + +#ifdef CAPIO_LOG + std::cout << libcapio_preamble << " WARNING: LIBCAPIO HAS BEEN COMPILED IN DEBUG MODE!" + << std::endl; +#endif + + if (getenv("CAPIO_APP_NAME") == nullptr) { + setenv("CAPIO_APP_NAME", CAPIO_APP_NAME.c_str(), 1); + } + + if (getenv("CAPIO_DIR") == nullptr) { + setenv("CAPIO_DIR", CAPIO_DIR.string().c_str(), 1); + } + + if (std::getenv("CAPIO_WORKFLOW_NAME") == nullptr) { + setenv("CAPIO_WORKFLOW_NAME", CAPIO_WORKFLOW_NAME.c_str(), 1); + } + + if (libcapio_initialized) { + return capio_server_thread_id; + } + + const auto thread_id = + bootstrap_capio_server(CAPIO_DIR, CAPIO_WORKFLOW_NAME, capio_server_exec_path, + capio_cl_config, await_server_timeout_seconds); + if (thread_id > 0) { + capio_server_thread_id = thread_id; + } + + init_client(gettid()); + init_filesystem(); + initialize_new_thread(); + + START_SYSCALL_LOGGING(); + + if (const auto silent = std::getenv("SILENT"); + silent != nullptr && std::string(silent) == "OFF") { + std::cout << libcapio_preamble << " CAPIO_DIR: " << getenv("CAPIO_DIR") << std::endl; + std::cout << libcapio_preamble << " CAPIO_APP_NAME: " << getenv("CAPIO_APP_NAME") + << std::endl; + std::cout << libcapio_preamble << " CAPIO_WORKFLOW_NAME: " << getenv("CAPIO_WORKFLOW_NAME") + << std::endl; + std::cout << libcapio_preamble << " PID - TID: " << std::to_string(getpid()) << " - " + << std::to_string(gettid()) << std::endl + << std::endl; + } + + LOG("\n\n"); + libcapio_initialized = true; + return capio_server_thread_id; +} + +inline void libcapio_teardown(const bool teardown_server) { + START_LOG(gettid(), "libcapio_teardown()"); + if (libcapio_initialized) { + exit_handler(NULL, NULL, NULL, NULL, NULL, NULL, NULL); + if (teardown_server && capio_server_thread_id > 0) { + kill(capio_server_thread_id, SIGTERM); + capio_server_thread_id = -1; + } + libcapio_initialized = false; + } + + LOG("\n\n"); +} + +// ----------------------------------------------------------------------------- +// POSIX Syscall Wrappers +// ----------------------------------------------------------------------------- + +inline int libcapio_open(const char *path, int flags, mode_t mode) { + START_LOG(gettid(), "call(path=%s)", path); + long result; + openat_handler(AT_FDCWD, reinterpret_cast(path), flags, NULL, NULL, NULL, &result); + LOG("open_handler result = %d", result); + + if (result == CAPIO_POSIX_SYSCALL_REQUEST_SKIP) { + LOG("Delegating to glibc"); + return open(path, flags, mode); + } + + if (result == CAPIO_POSIX_SYSCALL_ERRNO) { + LOG("Error has occurred while opening file from server side! errno=%s", strerror(errno)); + } + + LOG("\n\n"); + return static_cast(result); +} + +inline long libcapio_read(const int fd, char *buf, const size_t size) { + START_LOG(gettid(), "call(fd=%d, size=%ld)", fd, size); + long result; + read_handler(fd, reinterpret_cast(buf), size, NULL, NULL, NULL, &result); + if (result == CAPIO_POSIX_SYSCALL_REQUEST_SKIP) { + return read(fd, buf, size); + } + + LOG("\n\n"); + return result; +} + +inline long libcapio_write(const int fd, const char *buf, const size_t size) { + START_LOG(gettid(), "call(fd=%d, size=%ld)", fd, size); + long result; + write_handler(fd, reinterpret_cast(buf), size, NULL, NULL, NULL, &result); + if (result == CAPIO_POSIX_SYSCALL_REQUEST_SKIP) { + return write(fd, buf, size); + } + + LOG("\n\n"); + return result; +} + +inline long libcapio_close(const int fd) { + START_LOG(gettid(), "call(fd=%ld)", fd); + long result; + close_handler(fd, NULL, NULL, NULL, NULL, NULL, &result); + + LOG("\n\n"); + return result; +} + +inline long libcapio_readdir(const int fd, dirent64 *entry) { + START_LOG(gettid(), "call(fd=%d)", fd); + long result; + getdents_handler_impl(fd, reinterpret_cast(entry), sizeof(linux_dirent64), &result, true); + + if (result == CAPIO_POSIX_SYSCALL_REQUEST_SKIP) { + throw PyCapioException("ERROR: libcapio readdir on non CAPIO directory not yet supported"); + } + + LOG("\n\n"); + return result; +} + +inline long libcapio_mkdir(const char *path, int mode) { + START_LOG(gettid(), "call(path=%s)", path); + long result; + mkdir_handler(reinterpret_cast(path), mode, NULL, NULL, NULL, NULL, &result); + + if (result == CAPIO_POSIX_SYSCALL_REQUEST_SKIP) { + throw PyCapioException("ERROR: libcapio readdir on non CAPIO directory not yet supported"); + } + + LOG("\n\n"); + return result; +} + +inline long libcapio_lseek(int fd, long offset, int whence) { + START_LOG(gettid(), "call(fd=%d, offset=%d, whence=%d)", fd, offset, whence); + long result; + lseek_handler(fd, offset, whence, NULL, NULL, NULL, &result); + + if (result == CAPIO_POSIX_SYSCALL_REQUEST_SKIP) { + throw PyCapioException("ERROR: libcapio readdir on non CAPIO directory not yet supported"); + } + + LOG("\n\n"); + return result; +} + +inline long libcapio_stat(const char *path, struct stat *statbuf) { + START_LOG(gettid(), "call(path=%s)", path); + long result; + lstat_handler(reinterpret_cast(path), reinterpret_cast(statbuf), NULL, NULL, NULL, + NULL, &result); + + if (result == CAPIO_POSIX_SYSCALL_REQUEST_SKIP) { + throw PyCapioException("ERROR: libcapio stat on non CAPIO directory not yet supported"); + } + + LOG("\n\n"); + return result; +} + +#endif // PYCAPIO_PYCAPIO_HPP diff --git a/include/libcapio.hpp b/include/libcapio.hpp index 2148e11..a7ce23b 100644 --- a/include/libcapio.hpp +++ b/include/libcapio.hpp @@ -1,348 +1,42 @@ -#ifndef PYCAPIO_PYCAPIO_HPP -#define PYCAPIO_PYCAPIO_HPP - -#ifndef __LIBCAPIO -#define __LIBCAPIO -#include "PyCapioException.hpp" - -#include -#include -#include -#endif - -/** - * Capio log level. - * if -1, and capio logging is enable everything is logged, otherwise, only - * logs up to CAPIO_MAX_LOG_LEVEL function calls - */ -inline bool syscall_no_intercept_flag; -#define syscall_no_intercept syscall -#define CAPIO_VERSION "" - +#ifndef PYCAPIO_LIBCAPIO_HPP +#define PYCAPIO_LIBCAPIO_HPP #include -#include - -#include "common/syscall.hpp" - -#include "utils/clone.hpp" -#include "utils/filesystem.hpp" -#include "utils/snapshot.hpp" - -#include "common/logger.hpp" - -#include "handlers.hpp" +#include -static thread_local std::string libcapio_preamble; +#include "common/constants.hpp" class StartupSemaphore final { int fp; const std::string lock_to_check; public: - explicit StartupSemaphore(const std::string &workflow_name) - : lock_to_check(workflow_name + ".lock") { - fp = shm_open(lock_to_check.c_str(), O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); - } - - ~StartupSemaphore() { - if (fp != -1) { - close(fp); - shm_unlink(lock_to_check.c_str()); - } - } - - explicit operator bool() const { return fp != -1; } + explicit StartupSemaphore(const std::string &workflow_name); + ~StartupSemaphore(); + explicit operator bool() const; }; -static int capio_server_thread_id = -1; -static bool libcapio_initialized = false; - -inline int bootstrap_capio_server(const std::filesystem::path &CAPIO_DIR, - const std::string &CAPIO_WORKFLOW_NAME, - const std::string &capio_server_exec_path, - const std::string &capio_cl_config, - const int await_server_timeout_seconds) { - bool server_is_started = false; - int server_thread_id = -1; - - std::string shm_name = "/dev/shm/" + CAPIO_WORKFLOW_NAME; - if (std::filesystem::exists(shm_name)) { - std::cout << libcapio_preamble << " CAPIO server is already started" << std::endl; - server_is_started = true; - } - - // check if server instance exists. If not, boot a server instance - if (!server_is_started) { - const StartupSemaphore boot_lock(CAPIO_WORKFLOW_NAME); - if (boot_lock) { - static constexpr char NO_CONFIG_FLAG[] = "--no-config"; - static constexpr char CONFIG_FLAG[] = "--config"; - static constexpr char BACKEND_FLAG[] = "--backend"; - static constexpr char NO_BACKEND_AFTER[] = "none"; - - std::cout << libcapio_preamble << " Booting up CAPIO server instance" << std::endl; - - std::vector newEnv; - for (char **env = environ; *env != nullptr; ++env) { - newEnv.emplace_back(*env); - } - - newEnv.emplace_back("CAPIO_DIR=" + CAPIO_DIR.string()); - newEnv.emplace_back("CAPIO_LOG_LEVEL=-1"); - newEnv.emplace_back("CAPIO_WORKFLOW_NAME=" + CAPIO_WORKFLOW_NAME); - - std::vector envPtrs; - for (auto &s : newEnv) { - envPtrs.push_back(&s[0]); - } - envPtrs.push_back(nullptr); - - // resolve capio_server executable if not provided as absolute path to a binary from - // PATH - std::string resolved_capio_server_exec_path = capio_server_exec_path; - if (capio_server_exec_path == "capio_server") { - const auto path = std::getenv("PATH"); - std::stringstream ss(path); - std::string item; - - while (std::getline(ss, item, ':')) { - std::filesystem::path check(item); - check /= capio_server_exec_path; - if (std::filesystem::exists(check)) { - resolved_capio_server_exec_path = check; - break; - } - } - } - - // Fail if capio_server binary executable does not exists - if (!std::filesystem::exists(resolved_capio_server_exec_path)) { - throw PyCapioException("Could not locate capio_server executable in PATH!"); - } - - char *args[6] = {const_cast(resolved_capio_server_exec_path.c_str()), - capio_cl_config.empty() ? const_cast(NO_CONFIG_FLAG) - : const_cast(CONFIG_FLAG), - capio_cl_config.empty() ? nullptr - : const_cast(capio_cl_config.c_str()), - const_cast(BACKEND_FLAG), - const_cast(NO_BACKEND_AFTER), - nullptr}; - - server_thread_id = fork(); - - if (server_thread_id == 0) { - execve(args[0], args, envPtrs.data()); - throw PyCapioException(libcapio_preamble + capio_server_exec_path + "\n" + - " EXECVE failure: " + std::string(strerror(errno))); - } - - if (server_thread_id > 0) { - std::cout << libcapio_preamble - << " Started CAPIO server with PID: " << server_thread_id << std::endl; - sleep(await_server_timeout_seconds); - // jump to attaching to shm queues and await normal execution - } else { - std::cerr << libcapio_preamble - << "Failed to FORK server thread. Error: " + - std::string(std::strerror(errno)) - << std::endl; - } - } else { - std::this_thread::sleep_for(std::chrono::milliseconds(3000)); - } - } - return server_thread_id; -} - -inline int libcapio_init(const std::filesystem::path &CAPIO_DIR = ".", - const std::string &CAPIO_APP_NAME = CAPIO_DEFAULT_APP_NAME, - const std::string &CAPIO_WORKFLOW_NAME = CAPIO_DEFAULT_WORKFLOW_NAME, - const std::string &capio_server_exec_path = "capio_server", - const std::string &capio_cl_config = "", - const int await_server_timeout_seconds = 2) { - - if (libcapio_preamble.empty()) { - char host_name[HOST_NAME_MAX]{0}; - if (gethostname(host_name, HOST_NAME_MAX) == -1) { - std::cout << "WARN: gethostname failed: " << std::strerror(errno) << std::endl; - } - const auto pid = getpid(); - libcapio_preamble = "[[LIBCAPIO::" + std::string(host_name) + "::" + CAPIO_APP_NAME + - "::" + std::to_string(pid) + "]] "; - } - - START_LOG(gettid(), "libcapio_init(CAPIO_DIR=%s, CAPIO_APP_NAME=%s, CAPIO_WORKFLOW_NAME=%s)", - CAPIO_DIR.c_str(), CAPIO_APP_NAME.c_str(), CAPIO_WORKFLOW_NAME.c_str()); - -#ifdef CAPIO_LOG - std::cout << libcapio_preamble << " WARNING: LIBCAPIO HAS BEEN COMPILED IN DEBUG MODE!" - << std::endl; -#endif - - if (getenv("CAPIO_APP_NAME") == nullptr) { - setenv("CAPIO_APP_NAME", CAPIO_APP_NAME.c_str(), 1); - } - - if (getenv("CAPIO_DIR") == nullptr) { - setenv("CAPIO_DIR", CAPIO_DIR.string().c_str(), 1); - } - - if (std::getenv("CAPIO_WORKFLOW_NAME") == nullptr) { - setenv("CAPIO_WORKFLOW_NAME", CAPIO_WORKFLOW_NAME.c_str(), 1); - } - - if (libcapio_initialized) { - return capio_server_thread_id; - } - - const auto thread_id = - bootstrap_capio_server(CAPIO_DIR, CAPIO_WORKFLOW_NAME, capio_server_exec_path, - capio_cl_config, await_server_timeout_seconds); - if (thread_id > 0) { - capio_server_thread_id = thread_id; - } - - init_client(gettid()); - init_filesystem(); - initialize_new_thread(); - - START_SYSCALL_LOGGING(); - - if (const auto silent = std::getenv("SILENT"); - silent != nullptr && std::string(silent) == "OFF") { - std::cout << libcapio_preamble << " CAPIO_DIR: " << getenv("CAPIO_DIR") << std::endl; - std::cout << libcapio_preamble << " CAPIO_APP_NAME: " << getenv("CAPIO_APP_NAME") - << std::endl; - std::cout << libcapio_preamble << " CAPIO_WORKFLOW_NAME: " << getenv("CAPIO_WORKFLOW_NAME") - << std::endl; - std::cout << libcapio_preamble << " PID - TID: " << std::to_string(getpid()) << " - " - << std::to_string(gettid()) << std::endl - << std::endl; - } - - LOG("\n\n"); - libcapio_initialized = true; - return capio_server_thread_id; -} - -inline void libcapio_teardown(const bool teardown_server = false) { - START_LOG(gettid(), "libcapio_teardown()"); - if (libcapio_initialized) { - exit_handler(NULL, NULL, NULL, NULL, NULL, NULL, NULL); - if (teardown_server && capio_server_thread_id > 0) { - kill(capio_server_thread_id, SIGTERM); - capio_server_thread_id = -1; - } - libcapio_initialized = false; - } - - LOG("\n\n"); -} - -inline auto libcapio_open(const char *path, int flags, mode_t mode = 0) { - START_LOG(gettid(), "call(path=%s)", path); - long result; - openat_handler(AT_FDCWD, reinterpret_cast(path), flags, NULL, NULL, NULL, &result); - LOG("open_handler result = %d", result); - - if (result == CAPIO_POSIX_SYSCALL_REQUEST_SKIP) { - LOG("Delegating to glibc"); - return open(path, flags, mode); - } - - if (result == CAPIO_POSIX_SYSCALL_ERRNO) { - LOG("Error has occurred while opening file from server side! errno=%s", strerror(errno)); - } - - LOG("\n\n"); - return static_cast(result); -} - -inline auto libcapio_read(const int fd, char *buf, const size_t size) { - START_LOG(gettid(), "call(fd=%d, size=%ld)", fd, size); - long result; - read_handler(fd, reinterpret_cast(buf), size, NULL, NULL, NULL, &result); - if (result == CAPIO_POSIX_SYSCALL_REQUEST_SKIP) { - return read(fd, buf, size); - } - - LOG("\n\n"); - return result; -} - -inline auto libcapio_write(const int fd, const char *buf, const size_t size) { - START_LOG(gettid(), "call(fd=%d, size=%ld)", fd, size); - long result; - write_handler(fd, reinterpret_cast(buf), size, NULL, NULL, NULL, &result); - if (result == CAPIO_POSIX_SYSCALL_REQUEST_SKIP) { - return write(fd, buf, size); - } - - LOG("\n\n"); - return result; -} - -inline auto libcapio_close(const int fd) { - START_LOG(gettid(), "call(fd=%ld)", fd); - long result; - close_handler(fd, NULL, NULL, NULL, NULL, NULL, &result); - - LOG("\n\n"); - return result; -} - -inline auto libcapio_readdir(const int fd, dirent64 *entry) { - START_LOG(gettid(), "call(fd=%d)", fd); - long result; - getdents_handler_impl(fd, reinterpret_cast(entry), sizeof(linux_dirent64), &result, true); - - if (result == CAPIO_POSIX_SYSCALL_REQUEST_SKIP) { - throw PyCapioException("ERROR: libcapio readdir on non CAPIO directory not yet supported"); - } - - LOG("\n\n"); - return result; -} - -inline auto libcapio_mkdir(const char *path, int mode) { - START_LOG(gettid(), "call(path=%s)", path); - long result; - mkdir_handler(reinterpret_cast(path), mode, NULL, NULL, NULL, NULL, &result); - - if (result == CAPIO_POSIX_SYSCALL_REQUEST_SKIP) { - throw PyCapioException("ERROR: libcapio readdir on non CAPIO directory not yet supported"); - } - - LOG("\n\n"); - return result; -} - -inline auto libcapio_lseek(int fd, long offset, int whence) { - START_LOG(gettid(), "call(fd=%d, offset=%d, whence=%d)", fd, offset, whence); - long result; - lseek_handler(fd, offset, whence, NULL, NULL, NULL, &result); - - if (result == CAPIO_POSIX_SYSCALL_REQUEST_SKIP) { - throw PyCapioException("ERROR: libcapio readdir on non CAPIO directory not yet supported"); - } - - LOG("\n\n"); - return result; -} - -inline auto libcapio_stat(const char *path, struct stat *statbuf) { - START_LOG(gettid(), "call(path=%s)", path); - long result; - lstat_handler(reinterpret_cast(path), reinterpret_cast(statbuf), NULL, NULL, NULL, - NULL, &result); - - if (result == CAPIO_POSIX_SYSCALL_REQUEST_SKIP) { - throw PyCapioException("ERROR: libcapio stat on non CAPIO directory not yet supported"); - } - - LOG("\n\n"); - return result; -} - -#endif // PYCAPIO_PYCAPIO_HPP +int bootstrap_capio_server(const std::filesystem::path &CAPIO_DIR, + const std::string &CAPIO_WORKFLOW_NAME, + const std::string &capio_server_exec_path, + const std::string &capio_cl_config, + const int await_server_timeout_seconds); + +int libcapio_init(const std::filesystem::path &CAPIO_DIR = ".", + const std::string &CAPIO_APP_NAME = CAPIO_DEFAULT_APP_NAME, + const std::string &CAPIO_WORKFLOW_NAME = CAPIO_DEFAULT_WORKFLOW_NAME, + const std::string &capio_server_exec_path = "capio_server", + const std::string &capio_cl_config = "", + const int await_server_timeout_seconds = 2); + +void libcapio_teardown(const bool teardown_server = false); + +int libcapio_open(const char *path, int flags, mode_t mode = 0); +long libcapio_read(const int fd, char *buf, const size_t size); +long libcapio_write(const int fd, const char *buf, const size_t size); +long libcapio_close(const int fd); +long libcapio_readdir(const int fd, dirent64 *entry); +long libcapio_mkdir(const char *path, int mode); +long libcapio_lseek(int fd, long offset, int whence); +long libcapio_stat(const char *path, struct stat *statbuf); + +#endif // PYCAPIO_LIBCAPIO_HPP diff --git a/src/OsPath.cpp b/src/OsPath.cpp new file mode 100644 index 0000000..20f120b --- /dev/null +++ b/src/OsPath.cpp @@ -0,0 +1,102 @@ +#include +#include +#include +#include + +#include "OsPath.hpp" +#include "libcapio.hpp" + +// Note: Ensure that the header defining 'libcapio_stat' is included here +// or in your build environment. e.g., #include "libcapio.h" + +bool OsPath::exists(const std::string &path) { + struct stat statbuf{}; + if (libcapio_stat(path.c_str(), &statbuf) == -1 && errno == ENOENT) { + return false; + } + return true; +} + +bool OsPath::isfile(const std::string &path) { + struct stat statbuf{}; + if (libcapio_stat(path.c_str(), &statbuf) == -1 && errno == ENOENT) { + return false; + } + return (statbuf.st_mode & S_IFMT) == S_IFREG; +} + +bool OsPath::isdir(const std::string &path) { return !isfile(path); } + +uintmax_t OsPath::getsize(const std::string &path) { + struct stat statbuf{}; + if (libcapio_stat(path.c_str(), &statbuf) == -1 && errno == ENOENT) { + return 0; + } + return statbuf.st_size; +} + +std::string OsPath::basename(const std::string &path) { + return std::filesystem::path(path).filename().string(); +} + +std::string OsPath::dirname(const std::string &path) { + return std::filesystem::path(path).parent_path().string(); +} + +std::string OsPath::abspath(const std::string &path) { + return std::filesystem::absolute(path).string(); +} + +std::pair OsPath::splitext(const std::string &path) { + std::filesystem::path p(path); + return {p.stem().string(), p.extension().string()}; +} + +bool OsPath::isabs(const std::string &p) { return std::filesystem::path(p).is_absolute(); } + +std::string OsPath::normpath(const std::string &p) { + return std::filesystem::path(p).lexically_normal().string(); +} + +std::string OsPath::relpath(const std::string &path, const std::string &start) { + return std::filesystem::relative(path, start).string(); +} + +double OsPath::getmtime(const std::string &path) { + auto ftime = std::filesystem::last_write_time(path); + auto sctp = std::chrono::time_point_cast(ftime); + return static_cast(sctp.time_since_epoch().count()); +} + +bool OsPath::samefile(const std::string &p1, const std::string &p2) { + return std::filesystem::equivalent(p1, p2); +} + +std::pair OsPath::split(const std::string &p) { + std::filesystem::path path(p); + return {path.parent_path().string(), path.filename().string()}; +} + +std::string OsPath::normcase(const std::string &p) { return p; } + +std::string OsPath::realpath(const std::string &path) { + try { + return std::filesystem::canonical(path).string(); + } catch (const std::filesystem::filesystem_error &) { + return ""; + } +} + +std::string OsPath::join(const std::string &path1, const std::string &path2) { + if (path1.empty() && path2.empty()) { + return ""; + } + if (path1.empty() && !path2.empty()) { + return path2; + } + if (path2.empty() && !path1.empty()) { + return path1; + } + + return (std::filesystem::path(path1) / path2).string(); +} \ No newline at end of file diff --git a/src/PyCapioException.cpp b/src/PyCapioException.cpp new file mode 100644 index 0000000..0cff17a --- /dev/null +++ b/src/PyCapioException.cpp @@ -0,0 +1,29 @@ +#include "PyCapioException.hpp" + +#include +#include +#include + +std::string PyCapioException::capture_python_stack() { + try { + const auto traceback = pybind11::module_::import("traceback"); + const auto io = pybind11::module_::import("io"); + auto string_io = io.attr("StringIO")(); + traceback.attr("print_stack")(pybind11::none(), pybind11::none(), string_io); + return string_io.attr("getvalue")().cast(); + } catch (const pybind11::error_already_set &e) { + return std::string("[failed to capture Python stack: ") + e.what() + "]"; + } catch (...) { + return "[failed to capture Python stack: unknown error]"; + } +} + +PyCapioException::PyCapioException(const std::string &error_message) + : _message("PyCapioException: " + error_message + "\nPython stack trace:\n" + + capture_python_stack()) { + std::cerr << _message << std::endl; +} + +const char *PyCapioException::what() const noexcept { + return _message.c_str(); +} \ No newline at end of file diff --git a/src/ScandirIteratorWrapper.cpp b/src/ScandirIteratorWrapper.cpp new file mode 100644 index 0000000..99e68a6 --- /dev/null +++ b/src/ScandirIteratorWrapper.cpp @@ -0,0 +1,74 @@ +#include +#include +#include + +#include "PyCapioException.hpp" +#include "ScandirIteratorWrapper.hpp" +#include "libcapio.hpp" + +extern int capio_server_thread_id; +extern bool libcapio_initialized; + +// ----------------------------------------------------------------------------- +// CapioDirEntry Implementation +// ----------------------------------------------------------------------------- + +CapioDirEntry::CapioDirEntry(const std::filesystem::path &base, const dirent64 &ent) + : base_path(base), name_(ent.d_name), ino_(ent.d_ino), type_(ent.d_type) {} + +std::string CapioDirEntry::name() const { return name_; } + +std::string CapioDirEntry::path() const { return (base_path / name_).string(); } + +uint64_t CapioDirEntry::inode() const { return ino_; } + +bool CapioDirEntry::is_dir([[maybe_unused]] bool follow_symlinks) const { return type_ == DT_DIR; } + +bool CapioDirEntry::is_file([[maybe_unused]] bool follow_symlinks) const { return type_ == DT_REG; } + +bool CapioDirEntry::is_symlink() const { return type_ == DT_LNK; } + +// ----------------------------------------------------------------------------- +// ScandirIteratorWrapper Implementation +// ----------------------------------------------------------------------------- + +ScandirIteratorWrapper::ScandirIteratorWrapper(const std::filesystem::path &path) : path(path) { + if (!libcapio_initialized) { + throw PyCapioException("libcapio not initialized"); + } + + file_descriptor = libcapio_open(path.string().c_str(), O_RDONLY); + if (file_descriptor < 0) { + throw PyCapioException("libcapio_open failed"); + } +} + +ScandirIteratorWrapper::~ScandirIteratorWrapper() { close(); } + +CapioDirEntry ScandirIteratorWrapper::next() { + if (finished) { + throw pybind11::stop_iteration(); + } + + dirent64 ent{}; + if (libcapio_readdir(file_descriptor, &ent) == 0) { + finished = true; + throw pybind11::stop_iteration(); + } + + // Skip '.' and '..' + if (strcmp(ent.d_name, ".") == 0 || strcmp(ent.d_name, "..") == 0) { + return next(); + } + + return {path, ent}; +} + +ScandirIteratorWrapper &ScandirIteratorWrapper::iter() { return *this; } + +void ScandirIteratorWrapper::close() { + if (file_descriptor != -1) { + libcapio_close(file_descriptor); + file_descriptor = -1; + } +} \ No newline at end of file diff --git a/src/pycapio.cpp b/src/pycapio.cpp index 3482fcb..21b214f 100644 --- a/src/pycapio.cpp +++ b/src/pycapio.cpp @@ -1,13 +1,13 @@ -#include "../include/libcapio.hpp" -#include "pybind11/pybind11.h" +#include #include #include -#include "../include/PyCapioException.hpp" +#include "_libcapio_impl.hpp" -#include "../include/IOWrapper.hpp" -#include "../include/OsPath.hpp" -#include "../include/ScandirIteratorWrapper.hpp" +#include "IOWrapper.hpp" +#include "OsPath.hpp" +#include "PyCapioException.hpp" +#include "ScandirIteratorWrapper.hpp" namespace py11 = pybind11; @@ -67,6 +67,8 @@ PYBIND11_MODULE(_pycapio, m) { register_IO_wrapper(m, "PyCapioBinaryIOWrapper", 16 * 1024); + pybind11::register_exception(m, "PyCAPIOException"); + py11::class_(m, "DirEntry") .def_property_readonly("name", &CapioDirEntry::name) .def_property_readonly("path", &CapioDirEntry::path) From 9dd88c0b0a59f36af9d825742e30acec5819dddc Mon Sep 17 00:00:00 2001 From: Marco Edoardo Santimaria Date: Fri, 19 Jun 2026 11:31:42 +0200 Subject: [PATCH 2/4] Fix --- include/_libcapio_impl.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/_libcapio_impl.hpp b/include/_libcapio_impl.hpp index f89d52c..837d321 100644 --- a/include/_libcapio_impl.hpp +++ b/include/_libcapio_impl.hpp @@ -38,9 +38,9 @@ inline bool syscall_no_intercept_flag; #include "handlers.hpp" -static thread_local std::string libcapio_preamble; -static int capio_server_thread_id = -1; -static bool libcapio_initialized = false; +inline bool libcapio_initialized = false; +inline int capio_server_thread_id = -1; +inline thread_local std::string libcapio_preamble; // ----------------------------------------------------------------------------- // StartupSemaphore Implementation From e7013f5a27e975a6b27d6eea3932653d542fe78f Mon Sep 17 00:00:00 2001 From: Marco Edoardo Santimaria Date: Fri, 19 Jun 2026 11:38:35 +0200 Subject: [PATCH 3/4] fix --- include/libcapio.hpp | 16 +++++++--------- src/ScandirIteratorWrapper.cpp | 3 +++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/include/libcapio.hpp b/include/libcapio.hpp index a7ce23b..572b00a 100644 --- a/include/libcapio.hpp +++ b/include/libcapio.hpp @@ -18,23 +18,21 @@ class StartupSemaphore final { int bootstrap_capio_server(const std::filesystem::path &CAPIO_DIR, const std::string &CAPIO_WORKFLOW_NAME, const std::string &capio_server_exec_path, - const std::string &capio_cl_config, - const int await_server_timeout_seconds); + const std::string &capio_cl_config, int await_server_timeout_seconds); int libcapio_init(const std::filesystem::path &CAPIO_DIR = ".", const std::string &CAPIO_APP_NAME = CAPIO_DEFAULT_APP_NAME, const std::string &CAPIO_WORKFLOW_NAME = CAPIO_DEFAULT_WORKFLOW_NAME, const std::string &capio_server_exec_path = "capio_server", - const std::string &capio_cl_config = "", - const int await_server_timeout_seconds = 2); + const std::string &capio_cl_config = "", int await_server_timeout_seconds = 2); -void libcapio_teardown(const bool teardown_server = false); +void libcapio_teardown(bool teardown_server = false); int libcapio_open(const char *path, int flags, mode_t mode = 0); -long libcapio_read(const int fd, char *buf, const size_t size); -long libcapio_write(const int fd, const char *buf, const size_t size); -long libcapio_close(const int fd); -long libcapio_readdir(const int fd, dirent64 *entry); +long libcapio_read(int fd, char *buf, size_t size); +long libcapio_write(int fd, const char *buf, size_t size); +long libcapio_close(int fd); +long libcapio_readdir(int fd, dirent64 *entry); long libcapio_mkdir(const char *path, int mode); long libcapio_lseek(int fd, long offset, int whence); long libcapio_stat(const char *path, struct stat *statbuf); diff --git a/src/ScandirIteratorWrapper.cpp b/src/ScandirIteratorWrapper.cpp index 99e68a6..eb21d86 100644 --- a/src/ScandirIteratorWrapper.cpp +++ b/src/ScandirIteratorWrapper.cpp @@ -6,6 +6,9 @@ #include "ScandirIteratorWrapper.hpp" #include "libcapio.hpp" +// TODO: remove once _libcapio_impl becomes a cpp file +#include "_libcapio_impl.hpp" + extern int capio_server_thread_id; extern bool libcapio_initialized; From 5e4572e9c034a3083a499ba00e4e82e7dc3d038a Mon Sep 17 00:00:00 2001 From: Marco Edoardo Santimaria Date: Fri, 19 Jun 2026 11:54:27 +0200 Subject: [PATCH 4/4] fix --- include/_libcapio_impl.hpp | 42 ++++++++++++++++------------------ src/ScandirIteratorWrapper.cpp | 2 -- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/include/_libcapio_impl.hpp b/include/_libcapio_impl.hpp index 837d321..753b486 100644 --- a/include/_libcapio_impl.hpp +++ b/include/_libcapio_impl.hpp @@ -46,29 +46,29 @@ inline thread_local std::string libcapio_preamble; // StartupSemaphore Implementation // ----------------------------------------------------------------------------- -inline StartupSemaphore::StartupSemaphore(const std::string &workflow_name) +StartupSemaphore::StartupSemaphore(const std::string &workflow_name) : lock_to_check(workflow_name + ".lock") { fp = shm_open(lock_to_check.c_str(), O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); } -inline StartupSemaphore::~StartupSemaphore() { +StartupSemaphore::~StartupSemaphore() { if (fp != -1) { close(fp); shm_unlink(lock_to_check.c_str()); } } -inline StartupSemaphore::operator bool() const { return fp != -1; } +StartupSemaphore::operator bool() const { return fp != -1; } // ----------------------------------------------------------------------------- // CAPIO Server // ----------------------------------------------------------------------------- -inline int bootstrap_capio_server(const std::filesystem::path &CAPIO_DIR, - const std::string &CAPIO_WORKFLOW_NAME, - const std::string &capio_server_exec_path, - const std::string &capio_cl_config, - const int await_server_timeout_seconds) { +int bootstrap_capio_server(const std::filesystem::path &CAPIO_DIR, + const std::string &CAPIO_WORKFLOW_NAME, + const std::string &capio_server_exec_path, + const std::string &capio_cl_config, + const int await_server_timeout_seconds) { bool server_is_started = false; int server_thread_id = -1; @@ -162,11 +162,9 @@ inline int bootstrap_capio_server(const std::filesystem::path &CAPIO_DIR, return server_thread_id; } -inline int libcapio_init(const std::filesystem::path &CAPIO_DIR, const std::string &CAPIO_APP_NAME, - const std::string &CAPIO_WORKFLOW_NAME, - const std::string &capio_server_exec_path, - const std::string &capio_cl_config, - const int await_server_timeout_seconds) { +int libcapio_init(const std::filesystem::path &CAPIO_DIR, const std::string &CAPIO_APP_NAME, + const std::string &CAPIO_WORKFLOW_NAME, const std::string &capio_server_exec_path, + const std::string &capio_cl_config, const int await_server_timeout_seconds) { if (libcapio_preamble.empty()) { char host_name[HOST_NAME_MAX]{0}; @@ -232,7 +230,7 @@ inline int libcapio_init(const std::filesystem::path &CAPIO_DIR, const std::stri return capio_server_thread_id; } -inline void libcapio_teardown(const bool teardown_server) { +void libcapio_teardown(const bool teardown_server) { START_LOG(gettid(), "libcapio_teardown()"); if (libcapio_initialized) { exit_handler(NULL, NULL, NULL, NULL, NULL, NULL, NULL); @@ -250,7 +248,7 @@ inline void libcapio_teardown(const bool teardown_server) { // POSIX Syscall Wrappers // ----------------------------------------------------------------------------- -inline int libcapio_open(const char *path, int flags, mode_t mode) { +int libcapio_open(const char *path, int flags, mode_t mode) { START_LOG(gettid(), "call(path=%s)", path); long result; openat_handler(AT_FDCWD, reinterpret_cast(path), flags, NULL, NULL, NULL, &result); @@ -269,7 +267,7 @@ inline int libcapio_open(const char *path, int flags, mode_t mode) { return static_cast(result); } -inline long libcapio_read(const int fd, char *buf, const size_t size) { +long libcapio_read(const int fd, char *buf, const size_t size) { START_LOG(gettid(), "call(fd=%d, size=%ld)", fd, size); long result; read_handler(fd, reinterpret_cast(buf), size, NULL, NULL, NULL, &result); @@ -281,7 +279,7 @@ inline long libcapio_read(const int fd, char *buf, const size_t size) { return result; } -inline long libcapio_write(const int fd, const char *buf, const size_t size) { +long libcapio_write(const int fd, const char *buf, const size_t size) { START_LOG(gettid(), "call(fd=%d, size=%ld)", fd, size); long result; write_handler(fd, reinterpret_cast(buf), size, NULL, NULL, NULL, &result); @@ -293,7 +291,7 @@ inline long libcapio_write(const int fd, const char *buf, const size_t size) { return result; } -inline long libcapio_close(const int fd) { +long libcapio_close(const int fd) { START_LOG(gettid(), "call(fd=%ld)", fd); long result; close_handler(fd, NULL, NULL, NULL, NULL, NULL, &result); @@ -302,7 +300,7 @@ inline long libcapio_close(const int fd) { return result; } -inline long libcapio_readdir(const int fd, dirent64 *entry) { +long libcapio_readdir(const int fd, dirent64 *entry) { START_LOG(gettid(), "call(fd=%d)", fd); long result; getdents_handler_impl(fd, reinterpret_cast(entry), sizeof(linux_dirent64), &result, true); @@ -315,7 +313,7 @@ inline long libcapio_readdir(const int fd, dirent64 *entry) { return result; } -inline long libcapio_mkdir(const char *path, int mode) { +long libcapio_mkdir(const char *path, int mode) { START_LOG(gettid(), "call(path=%s)", path); long result; mkdir_handler(reinterpret_cast(path), mode, NULL, NULL, NULL, NULL, &result); @@ -328,7 +326,7 @@ inline long libcapio_mkdir(const char *path, int mode) { return result; } -inline long libcapio_lseek(int fd, long offset, int whence) { +long libcapio_lseek(int fd, long offset, int whence) { START_LOG(gettid(), "call(fd=%d, offset=%d, whence=%d)", fd, offset, whence); long result; lseek_handler(fd, offset, whence, NULL, NULL, NULL, &result); @@ -341,7 +339,7 @@ inline long libcapio_lseek(int fd, long offset, int whence) { return result; } -inline long libcapio_stat(const char *path, struct stat *statbuf) { +long libcapio_stat(const char *path, struct stat *statbuf) { START_LOG(gettid(), "call(path=%s)", path); long result; lstat_handler(reinterpret_cast(path), reinterpret_cast(statbuf), NULL, NULL, NULL, diff --git a/src/ScandirIteratorWrapper.cpp b/src/ScandirIteratorWrapper.cpp index eb21d86..812c91b 100644 --- a/src/ScandirIteratorWrapper.cpp +++ b/src/ScandirIteratorWrapper.cpp @@ -6,8 +6,6 @@ #include "ScandirIteratorWrapper.hpp" #include "libcapio.hpp" -// TODO: remove once _libcapio_impl becomes a cpp file -#include "_libcapio_impl.hpp" extern int capio_server_thread_id; extern bool libcapio_initialized;