diff --git a/slsReceiverSoftware/src/CommandLineOptions.cpp b/slsReceiverSoftware/src/CommandLineOptions.cpp index 5c18458c4..ec682f395 100644 --- a/slsReceiverSoftware/src/CommandLineOptions.cpp +++ b/slsReceiverSoftware/src/CommandLineOptions.cpp @@ -7,6 +7,11 @@ #include "sls/ToString.h" #include "sls/logger.h" +#include +#include +#include +#include + #define MAX_RECEIVERS 1024 ParsedOptions parseCommandLine(AppType app, int argc, char* argv[]) { @@ -108,7 +113,7 @@ ParsedOptions parseCommandLine(AppType app, int argc, char* argv[]) { multi.numReceivers = sls::StringTo(optarg); else if (app == AppType::FrameSynchronizer) frame.numReceivers = sls::StringTo(optarg); - if (numReceivers < 0 || numReceivers > MAX_RECEIVERS) { + if (numReceivers == 0 || numReceivers > MAX_RECEIVERS) { throw sls::RuntimeError("Invalid number of receivers. Max: " + std::to_string(MAX_RECEIVERS)); } multi.numReceivers = numReceivers; @@ -257,4 +262,16 @@ std::string getHelpMessage(AppType app) { "\t-u, --uid : Set effective user id if receiver started " "with privileges. \n\n"; } + throw sls::RuntimeError("Unknown AppType for help message"); +} + +void setupSignalHandler(int signal, void (*handler)(int)) { + // Catch signal SIGINT to close files and call destructors properly + struct sigaction sa{}; + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); // dont block additional signals + sa.sa_flags = 0; + if (sigaction(signal, &sa, nullptr) == -1) { + LOG(sls::logERROR) << "Could not set handler for " << strsignal(signal); + } } \ No newline at end of file diff --git a/slsReceiverSoftware/src/CommandLineOptions.h b/slsReceiverSoftware/src/CommandLineOptions.h index 299e8a7fd..608b02d55 100644 --- a/slsReceiverSoftware/src/CommandLineOptions.h +++ b/slsReceiverSoftware/src/CommandLineOptions.h @@ -2,12 +2,9 @@ // Copyright (C) 2021 Contributors to the SLS Detector Package #pragma once - - -#include -#include -#include #include +#include +#include enum class AppType { MultiReceiver, @@ -41,4 +38,4 @@ void setEffectiveUID(uid_t uid); std::string getTypeString(const AppType app); std::string getVersion(AppType app); std::string getHelpMessage(AppType app); - +void setupSignalHandler(int signal, void (*handler)(int)); diff --git a/slsReceiverSoftware/src/FrameSynchronizerApp.cpp b/slsReceiverSoftware/src/FrameSynchronizerApp.cpp index 6286f53dd..fd5f8eddc 100644 --- a/slsReceiverSoftware/src/FrameSynchronizerApp.cpp +++ b/slsReceiverSoftware/src/FrameSynchronizerApp.cpp @@ -5,12 +5,12 @@ * reconstructing image. Sample python script for pull socket for this combiner * in python/scripts folder. TODO: Not handling empty frames from one socket */ +#include "CommandLineOptions.h" #include "sls/Receiver.h" #include "sls/ToString.h" #include "sls/container_utils.h" #include "sls/logger.h" #include "sls/sls_detector_defs.h" -#include "CommandLineOptions.h" #include //SIGINT #include @@ -28,7 +28,6 @@ #include std::vector threads; -std::vector semaphores; sls::TLogLevel printHeadersLevel = sls::logDEBUG; /** Define Colors to print data call back in different colors for different @@ -57,16 +56,6 @@ struct FrameStatus { }; FrameStatus *global_frame_status = nullptr; -/** - * Control+C Interrupt Handler - * to let all the processes know to exit properly - */ -void sigInterruptHandler(int p) { - for (size_t i = 0; i != semaphores.size(); ++i) { - sem_post(semaphores[i]); - } -} - void cleanup() { if (global_frame_status) { std::lock_guard lock(global_frame_status->mtx); @@ -499,38 +488,37 @@ void GetDataCallback(slsDetectorDefs::sls_receiver_header &header, sem_post(&stat->available); } +std::vector semaphores; + +/** + * Control+C Interrupt Handler + * to let all the processes know to exit properly + * Only the main thread will call this handler + */ +void sigInterruptHandler(int p) { + (void)signal; // suppress unused warning if needed + for (auto &s : semaphores) { + sem_post(&s); + } +} + int main(int argc, char *argv[]) { auto opts = parseCommandLine(AppType::MultiReceiver, argc, argv); - auto& o = std::get(opts); + auto &o = std::get(opts); + auto &f = std::get(opts); if (o.versionRequested || o.helpRequested) { return EXIT_SUCCESS; } LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << ']'; - /** - Catch signal SIGINT to close files and call destructors properly */ - struct sigaction sa; - sa.sa_flags = 0; // no flags - sa.sa_handler = sigInterruptHandler; // handler function - sigemptyset(&sa.sa_mask); // dont block additional signals during invocation - // of handler - if (sigaction(SIGINT, &sa, nullptr) == -1) { - cprintf(RED, "Could not set handler function for SIGINT\n"); + setupSignalHandler(SIGINT, sigInterruptHandler); // close files on ctrl+c + setupSignalHandler(SIGPIPE, SIG_IGN); // handle locally on socket crash + semaphores.resize(f.numReceivers); + for (auto &s : semaphores) { + sem_init(&s, 1, 0); } - /** - Ignore SIG_PIPE, prevents global signal handler, handle locally, - instead of a server crashing due to client crash when writing, it just - gives error */ - struct sigaction asa; - asa.sa_flags = 0; // no flags - asa.sa_handler = SIG_IGN; // handler function - sigemptyset(&asa.sa_mask); // dont block additional signals during - // invocation of handler - if (sigaction(SIGPIPE, &asa, nullptr) == -1) { - cprintf(RED, "Could not set handler function for SIGPIPE\n"); - } - - auto& f = std::get(opts); FrameStatus stat{true, false, f.numReceivers}; // store pointer for signal handler global_frame_status = &stat; @@ -540,11 +528,8 @@ int main(int argc, char *argv[]) { std::thread combinerThread(Correlate, &stat); for (int i = 0; i != f.numReceivers; ++i) { - sem_t *semaphore = new sem_t; - sem_init(semaphore, 1, 0); - semaphores.push_back(semaphore); - uint16_t port = o.port + i; + sem_t *semaphore = &semaphores[i]; threads.emplace_back([i, semaphore, port, user_data]() { sls::Receiver receiver(port); receiver.registerCallBackStartAcquisition(StartAcquisitionCallback, @@ -552,10 +537,11 @@ int main(int argc, char *argv[]) { receiver.registerCallBackAcquisitionFinished( AcquisitionFinishedCallback, user_data); receiver.registerCallBackRawDataReady(GetDataCallback, user_data); + /** - as long as no Ctrl+C */ + // each child shares the common semaphore sem_wait(semaphore); sem_destroy(semaphore); - delete semaphore; // clean up frames if (i == 0) @@ -563,8 +549,8 @@ int main(int argc, char *argv[]) { }); } - for (auto &thread : threads) { - thread.join(); + for (auto &t : threads) { + t.join(); } { diff --git a/slsReceiverSoftware/src/MultiReceiverApp.cpp b/slsReceiverSoftware/src/MultiReceiverApp.cpp index fd3e7fc4a..6ca978533 100644 --- a/slsReceiverSoftware/src/MultiReceiverApp.cpp +++ b/slsReceiverSoftware/src/MultiReceiverApp.cpp @@ -2,12 +2,12 @@ // Copyright (C) 2021 Contributors to the SLS Detector Package /* Creates the slsMultiReceiver for running multiple receivers form a single * binary */ +#include "CommandLineOptions.h" #include "sls/Receiver.h" #include "sls/ToString.h" #include "sls/container_utils.h" #include "sls/logger.h" #include "sls/sls_detector_defs.h" -#include "CommandLineOptions.h" #include //SIGINT #include @@ -26,8 +26,6 @@ #define PRINT_IN_COLOR(c, f, ...) \ printf("\033[%dm" f RESET, 30 + c + 1, ##__VA_ARGS__) -sem_t semaphore; - /** * Start Acquisition Call back (slsMultiReceiver writes data if file write * enabled) if registerCallBackRawDataReady or @@ -131,49 +129,34 @@ void GetData(slsDetectorDefs::sls_receiver_header &header, // imageSize = 26000; } +sem_t semaphore; + /** * Control+C Interrupt Handler * to let all the processes know to exit properly + * All child processes will call the handler (parent process set to ignore) */ -void sigInterruptHandler(int p) { sem_post(&semaphore); } - - +void sigInterruptHandler(int signal) { + (void)signal; // suppress unused warning if needed + sem_post(&semaphore); +} int main(int argc, char *argv[]) { auto opts = parseCommandLine(AppType::MultiReceiver, argc, argv); auto& o = std::get(opts); + auto &m = std::get(opts); if (o.versionRequested || o.helpRequested) { return EXIT_SUCCESS; } LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << ']'; - /** - Catch signal SIGINT to close files and call destructors properly */ - struct sigaction sa; - sa.sa_flags = 0; // no flags - sa.sa_handler = sigInterruptHandler; // handler function - sigemptyset(&sa.sa_mask); // dont block additional signals during invocation - // of handler - if (sigaction(SIGINT, &sa, nullptr) == -1) { - LOG(sls::logERROR) << "Could not set handler function for SIGINT"; - } - - /** - Ignore SIG_PIPE, prevents global signal handler, handle locally, - instead of a server crashing due to client crash when writing, it just - gives error */ - struct sigaction asa; - asa.sa_flags = 0; // no flags - asa.sa_handler = SIG_IGN; // handler function - sigemptyset(&asa.sa_mask); // dont block additional signals during - // invocation of handler - if (sigaction(SIGPIPE, &asa, nullptr) == -1) { - LOG(sls::logERROR) << "Could not set handler function for SIGPIPE"; - } - - /** - loop over number of receivers */ + setupSignalHandler(SIGINT, sigInterruptHandler); // close files on ctrl+c + setupSignalHandler(SIGPIPE, SIG_IGN); // handle locally on socket crash sem_init(&semaphore, 1, 0); - auto& m = std::get(opts); + + /** - loop over receivers */ for (int i = 0; i < m.numReceivers; ++i) { /** - fork process to create child process */ @@ -218,6 +201,7 @@ int main(int argc, char *argv[]) { } /** - as long as no Ctrl+C */ + // each child process gets a copy of the semaphore sem_wait(&semaphore); sem_destroy(&semaphore); @@ -233,15 +217,9 @@ int main(int argc, char *argv[]) { } } - /** - Parent process ignores SIGINT (exits only when all child process - * exits) */ - sa.sa_flags = 0; // no flags - sa.sa_handler = SIG_IGN; // handler function - sigemptyset(&sa.sa_mask); // dont block additional signals during invocation - // of handler - if (sigaction(SIGINT, &sa, nullptr) == -1) { - LOG(sls::logERROR) << "Could not set handler function for SIGINT"; - } + /** - Parent process ignores SIGINT and waits for all the child processes to + * handle the signal */ + setupSignalHandler(SIGINT, SIG_IGN); /** - Print Ready and Instructions how to exit */ std::cout << "Ready ... \n"; diff --git a/slsReceiverSoftware/src/ReceiverApp.cpp b/slsReceiverSoftware/src/ReceiverApp.cpp index ff96d721c..6271c107c 100644 --- a/slsReceiverSoftware/src/ReceiverApp.cpp +++ b/slsReceiverSoftware/src/ReceiverApp.cpp @@ -1,12 +1,12 @@ // SPDX-License-Identifier: LGPL-3.0-or-other // Copyright (C) 2021 Contributors to the SLS Detector Package /* slsReceiver */ +#include "CommandLineOptions.h" #include "sls/Receiver.h" #include "sls/ToString.h" #include "sls/container_utils.h" #include "sls/logger.h" #include "sls/sls_detector_defs.h" -#include "CommandLineOptions.h" #include //SIGINT #include @@ -20,7 +20,14 @@ sem_t semaphore; -void sigInterruptHandler(int p) { sem_post(&semaphore); } +/** + * Control+C Interrupt Handler + * to let all the other process know to exit properly + */ +void sigInterruptHandler(int signal) { + (void)signal; // suppress unused warning if needed + sem_post(&semaphore); +} int main(int argc, char *argv[]) { @@ -32,28 +39,10 @@ int main(int argc, char *argv[]) { LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << " ]"; - // Catch signal SIGINT to close files and call destructors properly - struct sigaction sa; - sa.sa_flags = 0; // no flags - sa.sa_handler = sigInterruptHandler; // handler function - sigemptyset(&sa.sa_mask); // dont block additional signals during invocation - // of handler - if (sigaction(SIGINT, &sa, nullptr) == -1) { - LOG(sls::logERROR) << "Could not set handler function for SIGINT"; - } - - // if socket crash, ignores SISPIPE, prevents global signal handler - // subsequent read/write to socket gives error - must handle locally - struct sigaction asa; - asa.sa_flags = 0; // no flags - asa.sa_handler = SIG_IGN; // handler function - sigemptyset(&asa.sa_mask); // dont block additional signals during - // invocation of handler - if (sigaction(SIGPIPE, &asa, nullptr) == -1) { - LOG(sls::logERROR) << "Could not set handler function for SIGPIPE"; - } - + setupSignalHandler(SIGINT, sigInterruptHandler); // close files on ctrl+c + setupSignalHandler(SIGPIPE, SIG_IGN); // handle locally on socket crash sem_init(&semaphore, 1, 0); + try { sls::Receiver r(o.port); LOG(sls::logINFO) << "[ Press \'Ctrl+c\' to exit ]"; diff --git a/slsReceiverSoftware/tests/CMakeLists.txt b/slsReceiverSoftware/tests/CMakeLists.txt index 9a9455408..aed52be0c 100755 --- a/slsReceiverSoftware/tests/CMakeLists.txt +++ b/slsReceiverSoftware/tests/CMakeLists.txt @@ -4,6 +4,7 @@ target_sources(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/test-GeneralData.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-CircularFifo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-ArrangeDataBasedOnBitList.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test-Apps.cpp ) target_include_directories(tests PUBLIC "$")