From d99a65cd49722485e6f64a15f91863fa7431020d Mon Sep 17 00:00:00 2001 From: ben Date: Sun, 11 Aug 2024 15:51:55 +0300 Subject: [PATCH] Add cross-platform code for semaphore --- .vscode/settings.json | 90 ------------------------- sh_mem/ProcCommunicator.cpp | 116 ++++++++++++++++++++++++++++---- sh_mem/ProcCommunicator.h | 13 ++++ sh_mem/SharedMemoryReceiver.cpp | 62 ++++++++++++++++- sh_mem/SharedMemoryReceiver.h | 16 +++-- sh_mem/SharedMemorySender.cpp | 65 +++++++++++++++++- sh_mem/SharedMemorySender.h | 23 +++++-- 7 files changed, 272 insertions(+), 113 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 012ad0b..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "files.associations": { - "__bit_reference": "cpp", - "__bits": "cpp", - "__config": "cpp", - "__debug": "cpp", - "__errc": "cpp", - "__hash_table": "cpp", - "__locale": "cpp", - "__mutex_base": "cpp", - "__node_handle": "cpp", - "__split_buffer": "cpp", - "__threading_support": "cpp", - "__tree": "cpp", - "__tuple": "cpp", - "__verbose_abort": "cpp", - "any": "cpp", - "array": "cpp", - "atomic": "cpp", - "bit": "cpp", - "bitset": "cpp", - "cctype": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "complex": "cpp", - "condition_variable": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "deque": "cpp", - "exception": "cpp", - "forward_list": "cpp", - "fstream": "cpp", - "future": "cpp", - "initializer_list": "cpp", - "iomanip": "cpp", - "ios": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "list": "cpp", - "locale": "cpp", - "map": "cpp", - "memory": "cpp", - "mutex": "cpp", - "new": "cpp", - "optional": "cpp", - "ostream": "cpp", - "queue": "cpp", - "ratio": "cpp", - "set": "cpp", - "sstream": "cpp", - "stack": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "string": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "thread": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "typeinfo": "cpp", - "unordered_map": "cpp", - "unordered_set": "cpp", - "variant": "cpp", - "vector": "cpp", - "__nullptr": "cpp", - "__string": "cpp", - "chrono": "cpp", - "compare": "cpp", - "concepts": "cpp", - "algorithm": "cpp", - "*.tcc": "cpp", - "functional": "cpp", - "iterator": "cpp", - "memory_resource": "cpp", - "numeric": "cpp", - "random": "cpp", - "utility": "cpp", - "charconv": "cpp", - "execution": "cpp" - } -} \ No newline at end of file diff --git a/sh_mem/ProcCommunicator.cpp b/sh_mem/ProcCommunicator.cpp index 883abb9..c4feeaf 100644 --- a/sh_mem/ProcCommunicator.cpp +++ b/sh_mem/ProcCommunicator.cpp @@ -1,7 +1,9 @@ #include "ProcCommunicator.h" #include +#ifndef _WIN32 #include #include +#endif static constexpr int SEMAPHORE_DISABLED = 0; static constexpr int SEMAPHORE_ENABLED = 1; @@ -9,19 +11,16 @@ static constexpr int SEMAPHORE_ENABLED = 1; ProcCommunicator::ProcCommunicator(const bool isMasterMode, const bool isMultipleMasters, const std::string &shMemName) : m_master_mode(isMasterMode), - m_multiple_master(isMultipleMasters), - m_master_received((sem_t *)-1), - m_slave_received((sem_t *)-1), - m_master_sent((sem_t *)-1), - m_slave_sent((sem_t *)-1) + m_multiple_master(isMultipleMasters) { const std::string master_mem_name = shMemName + "_master"; const std::string slave_mem_name = shMemName + "_slave"; + + m_sender = std::make_unique(master_mem_name.c_str()); + m_receiver = std::make_unique(slave_mem_name.c_str()); +#ifndef _WIN32 if (isMasterMode) { - m_sender = std::make_unique(master_mem_name.c_str()); - m_receiver = std::make_unique(slave_mem_name.c_str()); - m_master_received = sem_open((shMemName + "_m_rsem").c_str(), O_CREAT, 0666, SEMAPHORE_DISABLED); m_slave_received = sem_open((shMemName + "_s_rsem").c_str(), O_CREAT, 0666, SEMAPHORE_DISABLED); m_master_sent = sem_open((shMemName + "_m_sent").c_str(), O_CREAT, 0666, SEMAPHORE_DISABLED); @@ -31,16 +30,13 @@ ProcCommunicator::ProcCommunicator(const bool isMasterMode, m_slave_ready = sem_open((shMemName + "_s_ready").c_str(), O_CREAT, 0666, SEMAPHORE_ENABLED); if (m_master_received == SEM_FAILED || m_slave_received == SEM_FAILED || - m_master_sent == SEM_FAILED || m_slave_sent == SEM_FAILED || m_slave_ready == SEM_FAILED) + m_master_sent == SEM_FAILED || m_slave_sent == SEM_FAILED || (isMultipleMasters && m_slave_ready == SEM_FAILED)) { perror("ProcCommunicator sem_open failure."); } } else { - m_sender = std::make_unique(slave_mem_name.c_str()); - m_receiver = std::make_unique(master_mem_name.c_str()); - while (m_master_received == SEM_FAILED || m_slave_received == SEM_FAILED || m_master_sent == SEM_FAILED || m_slave_sent == SEM_FAILED || m_slave_ready == SEM_FAILED) { @@ -53,9 +49,42 @@ ProcCommunicator::ProcCommunicator(const bool isMasterMode, m_slave_ready = sem_open((shMemName + "_s_ready").c_str(), O_RDWR, 0666, SEMAPHORE_ENABLED); } } +#else + m_sender = std::make_unique(slave_mem_name.c_str()); + m_receiver = std::make_unique(master_mem_name.c_str()); + +std::wstring wshMemName(shMemName.begin(), shMemName.end()); + + if (!(m_master_received = CreateSemaphoreW(NULL, SEMAPHORE_DISABLED, MAXLONG, (wshMemName + L"_m_rsem").c_str()))) + m_master_received = OpenSemaphoreW(SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, 0, (wshMemName + L"_m_rsem").c_str()); + + if (!(m_slave_received = CreateSemaphoreW(NULL, SEMAPHORE_DISABLED, MAXLONG, (wshMemName + L"_s_rsem").c_str()))) + m_slave_received = OpenSemaphoreW(SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, 0, (wshMemName + L"_s_rsem").c_str()); + + if (!(m_master_sent = CreateSemaphoreW(NULL, SEMAPHORE_DISABLED, MAXLONG, (wshMemName + L"_m_sent").c_str()))) + m_master_sent = OpenSemaphoreW(SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, 0, (wshMemName + L"_m_sent").c_str()); + + if (!(m_slave_sent = CreateSemaphoreW(NULL, SEMAPHORE_DISABLED, MAXLONG, (wshMemName + L"_s_ready").c_str()))) + m_slave_sent = OpenSemaphoreW(SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, 0, (wshMemName + L"_s_ready").c_str()); + + if (isMultipleMasters) + { + if (!(m_slave_ready = CreateSemaphoreW(NULL, SEMAPHORE_DISABLED, MAXLONG, (wshMemName + L"_s_ready").c_str()))) + m_slave_ready = OpenSemaphoreW(SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, 0, (wshMemName + L"_s_ready").c_str()); + } + + if (m_master_received == NULL || m_slave_received == NULL || + m_master_sent == NULL || m_slave_sent == NULL || m_slave_ready == NULL || (isMultipleMasters && m_slave_ready == NULL)) + { + perror("ProcCommunicator sem_open failure."); + } + +#endif } + ProcCommunicator::~ProcCommunicator() { +#ifndef _WIN32 if (sem_close(m_master_received) == -1) { perror("Failed to destroy m_master_received semaphore"); @@ -76,10 +105,33 @@ ProcCommunicator::~ProcCommunicator() { perror("Failed to destroy m_slave_ready semaphore"); } +#else + if (m_master_received && CloseHandle(m_master_received)) + { + perror("Failed to destroy m_master_received semaphore"); + } + if (m_slave_received && CloseHandle(m_slave_received)) + { + perror("Failed to destroy m_slave_received semaphore"); + } + if (m_master_sent && CloseHandle(m_master_sent)) + { + perror("Failed to destroy m_master_sent semaphore"); + } + if (m_slave_sent && CloseHandle(m_slave_sent)) + { + perror("Failed to destroy m_slave_sent semaphore"); + } + if (m_multiple_master && m_slave_ready && CloseHandle(m_slave_ready)) + { + perror("Failed to destroy m_slave_ready semaphore"); + } +#endif } void ProcCommunicator::send(const Message *msg) { +#ifndef _WIN32 if (m_multiple_master && m_master_mode) sem_wait(m_slave_ready); @@ -89,15 +141,55 @@ void ProcCommunicator::send(const Message *msg) if (m_multiple_master && !m_master_mode) sem_post(m_slave_ready); +#else + // Wait for the semaphore to be signaled + if (m_multiple_master && m_master_mode) { + WaitForSingleObject(m_slave_ready, INFINITE); // INFINITE timeout to wait indefinitely + } + + // Send the message + m_sender->sendMessage(msg); + + // Post (release) the semaphore + ReleaseSemaphore(m_master_mode ? m_master_sent : m_slave_sent, 1, NULL); + + // Wait for the semaphore to be signaled + WaitForSingleObject(m_master_mode ? m_slave_received : m_master_received, INFINITE); + + // Post (release) the semaphore if needed + if (m_multiple_master && !m_master_mode) { + ReleaseSemaphore(m_slave_ready, 1, NULL); + } +#endif } Message *ProcCommunicator::receive() { +#ifndef _WIN32 sem_wait(m_master_mode ? m_slave_sent : m_master_sent); Message *response = m_receiver->receiveMessage(); sem_post(m_master_mode ? m_master_received : m_slave_received); return response; +#else + DWORD waitResult = WaitForSingleObject(m_master_mode ? m_slave_sent : m_master_sent, INFINITE); + if (waitResult != WAIT_OBJECT_0) { + // Handle error + return nullptr; + } + + // Receive the message + Message *response = m_receiver->receiveMessage(); + + // Post (release) the semaphore + BOOL releaseResult = ReleaseSemaphore(m_master_mode ? m_master_received : m_slave_received, 1, NULL); + if (!releaseResult) { + // Handle error + return nullptr; + } + + return response; +#endif } Message *ProcCommunicator::sendAndGetResponse(const Message *msg) diff --git a/sh_mem/ProcCommunicator.h b/sh_mem/ProcCommunicator.h index 93827f3..3776384 100644 --- a/sh_mem/ProcCommunicator.h +++ b/sh_mem/ProcCommunicator.h @@ -1,6 +1,11 @@ #pragma once #include +#ifndef _WIN32 +#include +#else +#include +#endif #include "SharedMemorySender.h" #include "SharedMemoryReceiver.h" #include "Message.hpp" @@ -20,9 +25,17 @@ class ProcCommunicator std::unique_ptr m_receiver; bool m_master_mode; bool m_multiple_master; +#ifndef _WIN32 sem_t *m_master_received; sem_t *m_slave_received; sem_t *m_master_sent; sem_t *m_slave_sent; sem_t *m_slave_ready; +#else + HANDLE m_master_received; + HANDLE m_slave_received; + HANDLE m_master_sent; + HANDLE m_slave_sent; + HANDLE m_slave_ready; +#endif }; \ No newline at end of file diff --git a/sh_mem/SharedMemoryReceiver.cpp b/sh_mem/SharedMemoryReceiver.cpp index 59cd51a..a8f2b70 100644 --- a/sh_mem/SharedMemoryReceiver.cpp +++ b/sh_mem/SharedMemoryReceiver.cpp @@ -1,10 +1,16 @@ #include #include #include +#ifndef _WIN32 #include #include #include #include +#else +#include +#include +#include +#endif #include "SharedMemoryReceiver.h" #include @@ -12,9 +18,22 @@ const int SHARED_MEMORY_SIZE = 4096; // 4KB SharedMemoryReceiver::SharedMemoryReceiver(const char *shMemName) : m_name(shMemName) { - init(); +#ifdef _WIN32 + initWindowsSharedMemory(); +#else + initUnixSharedMemory(); +#endif +} +SharedMemoryReceiver::~SharedMemoryReceiver() +{ +#ifdef _WIN32 + finishWindows(); +#else + finish(); +#endif } -void SharedMemoryReceiver::init() +#ifndef _WIN32 +void SharedMemoryReceiver::initUnixSharedMemory() { // Try to create the shared memory segment m_shm_fd = shm_open(m_name.c_str(), O_CREAT | O_EXCL | O_RDWR, 0666); @@ -66,6 +85,45 @@ void SharedMemoryReceiver::finish() std::cerr << "close failed" << std::endl; } } +#else +void SharedMemoryReceiver::initWindowsSharedMemory() +{ + std::wstring wshMemName(m_name.begin(), m_name.end()); + m_shm_fd = OpenFileMappingW( + FILE_MAP_ALL_ACCESS, // read/write access + FALSE, // do not inherit the name + wshMemName.c_str()); // name of mapping object + + if (m_shm_fd == NULL) + { + printf(("Could not open file mapping object (%d).\n"), + GetLastError()); + return; + } + + m_ptr = (void *)MapViewOfFile(m_shm_fd, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + SHARED_MEMORY_SIZE); + + if (m_ptr == NULL) + { + printf("Could not map view of file (%d).\n", GetLastError()); + + CloseHandle(m_shm_fd); + + return; + } +} + +void SharedMemoryReceiver::finishWindows() +{ + UnmapViewOfFile(m_ptr); + + CloseHandle(m_shm_fd); +} +#endif Message *SharedMemoryReceiver::receiveMessage() { diff --git a/sh_mem/SharedMemoryReceiver.h b/sh_mem/SharedMemoryReceiver.h index 3f15b6f..6809b5f 100644 --- a/sh_mem/SharedMemoryReceiver.h +++ b/sh_mem/SharedMemoryReceiver.h @@ -1,5 +1,4 @@ #pragma once -#include #include #include "Message.hpp" @@ -7,14 +6,23 @@ class SharedMemoryReceiver { public: SharedMemoryReceiver(const char *shMemName); - void init(); + ~SharedMemoryReceiver(); + +#ifdef WIN32 + void initWindowsSharedMemory(); + void finishWindows(); +#else + void initUnixSharedMemory(); void finish(); +#endif Message *receiveMessage(); private: +#ifndef _WIN32 int m_shm_fd; +#else + HANDLE m_shm_fd; +#endif void *m_ptr; - sem_t *m_sem; - sem_t *m_rec_sem; std::string m_name; }; \ No newline at end of file diff --git a/sh_mem/SharedMemorySender.cpp b/sh_mem/SharedMemorySender.cpp index bc12050..2e74079 100644 --- a/sh_mem/SharedMemorySender.cpp +++ b/sh_mem/SharedMemorySender.cpp @@ -1,10 +1,14 @@ #include #include #include +#ifndef _WIN32 #include #include #include #include +#endif +#include +#include #include #include "SharedMemorySender.h" @@ -12,8 +16,56 @@ const int SHARED_MEMORY_SIZE = 4096; // 4KB SharedMemorySender::SharedMemorySender(const char *shMemName) : m_name(shMemName) { +#ifndef _WIN32 init(); +#else + initWindows(); +#endif +} +SharedMemorySender::~SharedMemorySender() +{ +#ifndef _WIN32 + finish(); +#else + finishWindows(); +#endif } +#ifdef _WIN32 +void SharedMemorySender::initWindows() +{ + std::wstring wshMemName(m_name.begin(), m_name.end()); + m_shm_fd = CreateFileMappingW( + INVALID_HANDLE_VALUE, // use paging file + NULL, // default security + PAGE_READWRITE, // read/write access + 0, // maximum object size (high-order DWORD) + SHARED_MEMORY_SIZE, // maximum object size (low-order DWORD) + wshMemName.c_str()); // name of mapping object + + if (m_shm_fd == NULL) + { + printf("Could not create file mapping object (%d).\n", + GetLastError()); + } + m_ptr = (void *)MapViewOfFile(m_shm_fd, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + SHARED_MEMORY_SIZE); + + if (m_ptr == NULL) + { + printf("Could not map view of file (%d).\n", GetLastError()); + CloseHandle(m_shm_fd); + } +} + +void SharedMemorySender::finishWindows() +{ + UnmapViewOfFile(m_ptr); + CloseHandle(m_shm_fd); +} +#else void SharedMemorySender::init() { // Try to create the shared memory segment @@ -71,10 +123,11 @@ void SharedMemorySender::finish() std::cerr << "shm_unlink failed" << std::endl; } } - +#endif void SharedMemorySender::sendMessage(const Message *msg) { // std::cout<<"sendMessage\n"; +#ifndef WIN32 if (msg->type == MessageType::SET_CONFIG) std::memcpy(m_ptr, msg, sizeof(MessageSetConfig)); else if (msg->type == MessageType::COMPARE_REQUEST) @@ -83,4 +136,14 @@ void SharedMemorySender::sendMessage(const Message *msg) std::memcpy(m_ptr, msg, sizeof(MessageCompareResult)); else std::memcpy(m_ptr, msg, sizeof(Message)); +#else + if (msg->type == MessageType::SET_CONFIG) + CopyMemory(m_ptr, msg, sizeof(MessageSetConfig)); + else if (msg->type == MessageType::COMPARE_REQUEST) + CopyMemory(m_ptr, msg, sizeof(MessageCompareRequest)); + else if (msg->type == MessageType::COMPARE_RESULT) + CopyMemory(m_ptr, msg, sizeof(MessageCompareResult)); + else + CopyMemory(m_ptr, msg, sizeof(Message)); +#endif } \ No newline at end of file diff --git a/sh_mem/SharedMemorySender.h b/sh_mem/SharedMemorySender.h index 4ea253e..9553f6d 100644 --- a/sh_mem/SharedMemorySender.h +++ b/sh_mem/SharedMemorySender.h @@ -1,20 +1,35 @@ #pragma once -#include #include #include "Message.hpp" +#ifdef _WIN32 +#include +#include +#include +#include +#pragma comment(lib, "user32.lib") +#endif class SharedMemorySender { public: SharedMemorySender(const char *shMemName); + ~SharedMemorySender(); +#ifdef WIN32 + void initWindows(); + void finishWindows(); +#else void init(); void finish(); +#endif void sendMessage(const Message *msg); private: +void *m_ptr; +#ifndef _WIN32 int m_shm_fd; - void *m_ptr; - sem_t *m_sem; - sem_t *m_rec_sem; + +#else + HANDLE m_shm_fd; +#endif std::string m_name; }; \ No newline at end of file