Program Listing for File IPC_SHARE_MEM.hpp

Return to documentation for file (include/input/linux/IPC_SHARE_MEM.hpp)

#pragma once
#include <limits>
#include <string>
#include <sys/mman.h>
#include <unistd.h>

template <typename T, int MEM_PROT_FLAG> class IPCSharedMem {
  public:
    IPCSharedMem(std::string *external_logger_string)
    {
        external_logger = external_logger_string;
    }

    IPCSharedMem(const IPCSharedMem &) = delete;
    IPCSharedMem &
    operator=(const IPCSharedMem &) = delete;

    T           *ptr             = nullptr;
    int          FD              = -1;
    size_t       count           = 0;
    size_t       bytes           = 0;
    std::string *external_logger = nullptr;

    bool
    MakeIPCSharedMemory(const std::string &memfd_name, size_t data_length)
    {

        static_assert(
            std::is_trivially_copyable_v<T>,
            "Shared mem should contain trivially copyable types only.");
        if (data_length == 0) {
            *external_logger += "data_length is zero\n ";
            return false;
        }
        constexpr size_t Tsize    = sizeof(T);
        constexpr auto Max_length = std::numeric_limits<size_t>::max() / Tsize;
        if (Tsize != 0 && data_length > Max_length) {
            *external_logger += "byte size exceeded size_t maximum value\n ";
            return false;
        }

        FD = memfd_create(memfd_name.c_str(), MFD_CLOEXEC);
        if (FD < 0) {
            *external_logger += "memfd not created\n ";
            return false;
        }

        size_t byte_length = Tsize * data_length;
        if (ftruncate(FD, static_cast<off_t>(byte_length)) != 0) {
            close(FD);
            FD = -1;
            *external_logger += "ftruncate failed\n ";
            return false;
        }

        void *p = mmap(nullptr, byte_length, MEM_PROT_FLAG, MAP_SHARED, FD, 0);
        if (p == MAP_FAILED) {
            close(FD);
            FD = -1;
            *external_logger += "map failed\n ";
            return false;
        }

        ptr   = reinterpret_cast<T *>(p);
        count = data_length;
        bytes = byte_length;
        return true;
    }

    ~IPCSharedMem()
    {
        if (ptr && bytes > 0) {
            if (munmap(ptr, bytes) == -1) {
                if (external_logger) {
                    *external_logger += "failed to munmap\n ";
                }
            }
        }
        if (FD != -1) {
            if (close(FD) == -1) {
                if (external_logger) {
                    *external_logger += "failed to close FD\n ";
                }
            }
        }
    }
};