diff --git a/RELEASE.txt b/RELEASE.txt index a0e86380e..b56b0dacf 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -33,7 +33,7 @@ against any of the libSls*.so libraries, you can enable this by passing Added SLS_USE_SYSTEM_ZMQ option (default OFF) to use the libzmq of the host instead of the one included in our repo. - +Experimental support for building the detector client (including python bindings) on macOS 2 On-board Detector Server Compatibility ========================================== diff --git a/slsDetectorSoftware/CMakeLists.txt b/slsDetectorSoftware/CMakeLists.txt index 6147546d6..91173978b 100755 --- a/slsDetectorSoftware/CMakeLists.txt +++ b/slsDetectorSoftware/CMakeLists.txt @@ -29,7 +29,6 @@ target_link_libraries(slsDetectorObject slsProjectOptions slsSupportStatic pthread - rt PRIVATE slsProjectWarnings ) diff --git a/slsDetectorSoftware/src/CmdParser.cpp b/slsDetectorSoftware/src/CmdParser.cpp index 109a50b77..d036e4dc2 100644 --- a/slsDetectorSoftware/src/CmdParser.cpp +++ b/slsDetectorSoftware/src/CmdParser.cpp @@ -27,6 +27,10 @@ void CmdParser::Parse(std::string s) { // taking s by value we can modify it. Reset(); + // If the string is empty there is nothing to parse + if (s.empty()) + return; + // Are we looking at -h --help? avoid removing h from command starting // with h when combined with detector id (ex, 1-hostname) bool h = replace_first(&s, "--help", " "); diff --git a/slsDetectorSoftware/src/Module.cpp b/slsDetectorSoftware/src/Module.cpp index 7e8ded18f..a47eda649 100644 --- a/slsDetectorSoftware/src/Module.cpp +++ b/slsDetectorSoftware/src/Module.cpp @@ -1202,7 +1202,7 @@ void Module::setDestinationUDPIP(const IpAddr ip) { } sendToDetector(F_SET_DEST_UDP_IP, ip, nullptr); if (shm()->useReceiverFlag) { - MacAddr retval(0LU); + MacAddr retval; sendToReceiver(F_SET_RECEIVER_UDP_IP, ip, retval); LOG(logINFO) << "Setting destination udp mac of Module " << moduleIndex << " to " << retval; @@ -1225,7 +1225,7 @@ void Module::setDestinationUDPIP2(const IpAddr ip) { } sendToDetector(F_SET_DEST_UDP_IP2, ip, nullptr); if (shm()->useReceiverFlag) { - MacAddr retval(0LU); + MacAddr retval; sendToReceiver(F_SET_RECEIVER_UDP_IP2, ip, retval); LOG(logINFO) << "Setting destination udp mac2 of Module " << moduleIndex << " to " << retval; diff --git a/slsDetectorSoftware/src/SharedMemory.h b/slsDetectorSoftware/src/SharedMemory.h index f489373ba..2265d2f96 100644 --- a/slsDetectorSoftware/src/SharedMemory.h +++ b/slsDetectorSoftware/src/SharedMemory.h @@ -25,15 +25,27 @@ #include // fstat #include -namespace sls { - -struct CtbConfig; -// struct sharedDetector; +// ********************** Defines for shared memory. ********************** +// WARNING! before chaning these search the codebase for their usage! #define SHM_IS_VALID_CHECK_VERSION 0x250820 + +//Max shared memory name length in macOS is 31 characters +#ifdef __APPLE__ +#define SHM_DETECTOR_PREFIX "/sls_" +#define SHM_MODULE_PREFIX "_mod_" +#else #define SHM_DETECTOR_PREFIX "/slsDetectorPackage_detector_" #define SHM_MODULE_PREFIX "_module_" +#endif + #define SHM_ENV_NAME "SLSDETNAME" +// ************************************************************************ + +namespace sls { + +class CtbConfig; + template constexpr bool is_type() { return std::is_same_v, T>; @@ -267,6 +279,11 @@ template class SharedMemory { throw SharedMemoryError(msg); } + #ifdef __APPLE__ + // On macOS, fstat returns the allocated size and not the requested size. + // This means we can't check for size since we always get for example 16384 bytes. + return; + #endif auto actual_size = static_cast(sb.st_size); auto expected_size = sizeof(T); if (actual_size != expected_size) { diff --git a/slsDetectorSoftware/tests/test-SharedMemory.cpp b/slsDetectorSoftware/tests/test-SharedMemory.cpp index f9b7ce16f..c81f9643d 100644 --- a/slsDetectorSoftware/tests/test-SharedMemory.cpp +++ b/slsDetectorSoftware/tests/test-SharedMemory.cpp @@ -38,10 +38,16 @@ void freeShm(const int dindex, const int mIndex) { } constexpr int shm_id = 10; + +//macOS does not expose shm in the filesystem +#ifndef __APPLE__ + const std::string file_path = std::string("/dev/shm/slsDetectorPackage_detector_") + std::to_string(shm_id); + + TEST_CASE("Free obsolete (without isValid)", "[detector][shm]") { // ensure its clean to start @@ -89,6 +95,8 @@ TEST_CASE("Free obsolete (without isValid)", "[detector][shm]") { } } +#endif + TEST_CASE("Create SharedMemory read and write", "[detector][shm]") { SharedMemory shm(shm_id, -1); if (shm.exists()) { @@ -96,9 +104,9 @@ TEST_CASE("Create SharedMemory read and write", "[detector][shm]") { } shm.createSharedMemory(); - const char *env_p = std::getenv("SLSDETNAME"); + const char *env_p = std::getenv(SHM_ENV_NAME); std::string env_name = env_p ? ("_" + std::string(env_p)) : ""; - CHECK(shm.getName() == std::string("/slsDetectorPackage_detector_") + + CHECK(shm.getName() == std::string(SHM_DETECTOR_PREFIX) + std::to_string(shm_id) + env_name); shm()->x = 3; shm()->y = 5.7; @@ -168,11 +176,11 @@ TEST_CASE("Open two shared memories to the same place", "[detector][shm]") { } TEST_CASE("Move SharedMemory", "[detector][shm]") { - const char *env_p = std::getenv("SLSDETNAME"); + const char *env_p = std::getenv(SHM_ENV_NAME); std::string env_name = env_p ? ("_" + std::string(env_p)) : ""; SharedMemory shm(shm_id, -1); - CHECK(shm.getName() == std::string("/slsDetectorPackage_detector_") + + CHECK(shm.getName() == std::string(SHM_DETECTOR_PREFIX) + std::to_string(shm_id) + env_name); shm.createSharedMemory(); shm()->x = 9; @@ -183,13 +191,13 @@ TEST_CASE("Move SharedMemory", "[detector][shm]") { CHECK(shm2()->x == 9); REQUIRE_THROWS( shm()); // trying to access should throw instead of returning a nullptr - CHECK(shm2.getName() == std::string("/slsDetectorPackage_detector_") + + CHECK(shm2.getName() == std::string(SHM_DETECTOR_PREFIX) + std::to_string(shm_id) + env_name); shm2.removeSharedMemory(); } TEST_CASE("Create several shared memories", "[detector][shm]") { - const char *env_p = std::getenv("SLSDETNAME"); + const char *env_p = std::getenv(SHM_ENV_NAME); std::string env_name = env_p ? ("_" + std::string(env_p)) : ""; constexpr int N = 5; @@ -205,7 +213,7 @@ TEST_CASE("Create several shared memories", "[detector][shm]") { for (int i = 0; i != N; ++i) { CHECK(v[i]()->x == i); - CHECK(v[i].getName() == std::string("/slsDetectorPackage_detector_") + + CHECK(v[i].getName() == std::string(SHM_DETECTOR_PREFIX) + std::to_string(i + shm_id) + env_name); } @@ -216,12 +224,12 @@ TEST_CASE("Create several shared memories", "[detector][shm]") { } TEST_CASE("Create create a shared memory with a tag") { - const char *env_p = std::getenv("SLSDETNAME"); + const char *env_p = std::getenv(SHM_ENV_NAME); std::string env_name = env_p ? ("_" + std::string(env_p)) : ""; SharedMemory shm(0, -1, "ctbdacs"); REQUIRE(shm.getName() == - "/slsDetectorPackage_detector_0" + env_name + "_ctbdacs"); + std::string(SHM_DETECTOR_PREFIX) + "0" + env_name + "_ctbdacs"); } TEST_CASE("Create create a shared memory with a tag when SLSDETNAME is set") { @@ -235,7 +243,7 @@ TEST_CASE("Create create a shared memory with a tag when SLSDETNAME is set") { setenv(SHM_ENV_NAME, "myprefix", 1); SharedMemory shm(0, -1, "ctbdacs"); - REQUIRE(shm.getName() == "/slsDetectorPackage_detector_0_myprefix_ctbdacs"); + REQUIRE(shm.getName() == std::string(SHM_DETECTOR_PREFIX) + "0_myprefix_ctbdacs"); // Clean up after us if (old_slsdetname.empty()) diff --git a/slsSupportLib/src/file_utils.cpp b/slsSupportLib/src/file_utils.cpp index 15fb3a1c3..3b82a5a9f 100644 --- a/slsSupportLib/src/file_utils.cpp +++ b/slsSupportLib/src/file_utils.cpp @@ -10,11 +10,16 @@ #include #include #include // dirname +#include #include #include #include #include //readlink +#if defined(__APPLE__) +#include +#endif + namespace sls { int readDataFile(std::ifstream &infile, short int *data, int nch, int offset) { @@ -246,21 +251,40 @@ std::vector getChannelsFromFile(const std::string &fname) { } std::string getAbsolutePathFromCurrentProcess(const std::string &fname) { + if (fname[0] == '/') { return fname; } - // get path of current binary - char path[MAX_STR_LENGTH]; - memset(path, 0, MAX_STR_LENGTH); - ssize_t len = readlink("/proc/self/exe", path, MAX_STR_LENGTH - 1); + //in case PATH_MAX defines the longest possible path on linux and macOS + //use string instead of char array to avoid overflow + std::string path(PATH_MAX, '\0'); + + + #if defined(__APPLE__) + uint32_t size = PATH_MAX; + if (_NSGetExecutablePath(path.data(), &size) != 0) { + throw std::runtime_error("Failed to get executable path"); + } + // Resolve any symlinks and .. components + std::string resolved(PATH_MAX, '\0'); + if (!realpath(path.data(), resolved.data())) { + throw std::runtime_error("realpath failed for executable"); + } + path = resolved; + #else + + + ssize_t len = readlink("/proc/self/exe", path.data(), PATH_MAX - 1); if (len < 0) { throw RuntimeError("Could not get absolute path for " + fname); } path[len] = '\0'; + #endif + // get dir path and attach file name - std::string absPath = (std::string(dirname(path)) + '/' + fname); + std::string absPath = (std::string(dirname(path.data())) + '/' + fname); return absPath; } diff --git a/slsSupportLib/src/network_utils.cpp b/slsSupportLib/src/network_utils.cpp index 28072259b..166d9ccf0 100644 --- a/slsSupportLib/src/network_utils.cpp +++ b/slsSupportLib/src/network_utils.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -178,6 +177,12 @@ IpAddr InterfaceNameToIp(const std::string &ifn) { } MacAddr InterfaceNameToMac(const std::string &inf) { + +#ifdef __APPLE__ + throw RuntimeError( + "InterfaceNameToMac not implemented on macOS yet"); +#else + // TODO! Copied from genericSocket needs to be refactored! struct ifreq ifr; char mac[32]; @@ -203,6 +208,7 @@ MacAddr InterfaceNameToMac(const std::string &inf) { close(sock); } return MacAddr(mac); +#endif } void validatePortNumber(uint16_t port) { diff --git a/slsSupportLib/tests/test-UdpRxSocket.cpp b/slsSupportLib/tests/test-UdpRxSocket.cpp index 2fc152b5d..645fed8c1 100644 --- a/slsSupportLib/tests/test-UdpRxSocket.cpp +++ b/slsSupportLib/tests/test-UdpRxSocket.cpp @@ -72,6 +72,10 @@ TEST_CASE("Receive data from a vector") { CHECK(data_to_send == data_received); } +// TODO! Test blocking on apple, investigate when implementing +// receiver support in macOS +#ifndef __APPLE__ + TEST_CASE("Shutdown socket without hanging when waiting for data") { constexpr int port = 50001; constexpr ssize_t packet_size = 8000; @@ -81,13 +85,14 @@ TEST_CASE("Shutdown socket without hanging when waiting for data") { // Start a thread and wait for package // if the socket is left open we would block std::future ret = - std::async(&UdpRxSocket::ReceivePacket, &s, (char *)&buff); + std::async(std::launch::async, &UdpRxSocket::ReceivePacket, &s, (char *)&buff); s.Shutdown(); auto r = ret.get(); CHECK(r == false); // since we didn't get the packet } +#endif TEST_CASE("Too small packet") { constexpr int port = 50001; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6a451e24d..5537cc230 100755 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -25,7 +25,6 @@ target_link_libraries(tests slsProjectOptions slsSupportStatic pthread - rt PRIVATE slsProjectWarnings )