works, need to add tests

This commit is contained in:
2025-07-07 12:20:40 +02:00
parent 4ff29161d4
commit d18ea00b85
6 changed files with 78 additions and 110 deletions

View File

@ -7,6 +7,11 @@
#include "sls/ToString.h" #include "sls/ToString.h"
#include "sls/logger.h" #include "sls/logger.h"
#include <csignal>
#include <cstring>
#include <getopt.h>
#include <unistd.h>
#define MAX_RECEIVERS 1024 #define MAX_RECEIVERS 1024
ParsedOptions parseCommandLine(AppType app, int argc, char* argv[]) { ParsedOptions parseCommandLine(AppType app, int argc, char* argv[]) {
@ -108,7 +113,7 @@ ParsedOptions parseCommandLine(AppType app, int argc, char* argv[]) {
multi.numReceivers = sls::StringTo<uint16_t>(optarg); multi.numReceivers = sls::StringTo<uint16_t>(optarg);
else if (app == AppType::FrameSynchronizer) else if (app == AppType::FrameSynchronizer)
frame.numReceivers = sls::StringTo<uint16_t>(optarg); frame.numReceivers = sls::StringTo<uint16_t>(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)); throw sls::RuntimeError("Invalid number of receivers. Max: " + std::to_string(MAX_RECEIVERS));
} }
multi.numReceivers = numReceivers; multi.numReceivers = numReceivers;
@ -257,4 +262,16 @@ std::string getHelpMessage(AppType app) {
"\t-u, --uid : Set effective user id if receiver started " "\t-u, --uid : Set effective user id if receiver started "
"with privileges. \n\n"; "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);
}
} }

View File

@ -2,12 +2,9 @@
// Copyright (C) 2021 Contributors to the SLS Detector Package // Copyright (C) 2021 Contributors to the SLS Detector Package
#pragma once #pragma once
#include <variant>
#include <getopt.h>
#include <unistd.h>
#include <cstdint> #include <cstdint>
#include <string>
#include <variant>
enum class AppType { enum class AppType {
MultiReceiver, MultiReceiver,
@ -41,4 +38,4 @@ void setEffectiveUID(uid_t uid);
std::string getTypeString(const AppType app); std::string getTypeString(const AppType app);
std::string getVersion(AppType app); std::string getVersion(AppType app);
std::string getHelpMessage(AppType app); std::string getHelpMessage(AppType app);
void setupSignalHandler(int signal, void (*handler)(int));

View File

@ -5,12 +5,12 @@
* reconstructing image. Sample python script for pull socket for this combiner * reconstructing image. Sample python script for pull socket for this combiner
* in python/scripts folder. TODO: Not handling empty frames from one socket * in python/scripts folder. TODO: Not handling empty frames from one socket
*/ */
#include "CommandLineOptions.h"
#include "sls/Receiver.h" #include "sls/Receiver.h"
#include "sls/ToString.h" #include "sls/ToString.h"
#include "sls/container_utils.h" #include "sls/container_utils.h"
#include "sls/logger.h" #include "sls/logger.h"
#include "sls/sls_detector_defs.h" #include "sls/sls_detector_defs.h"
#include "CommandLineOptions.h"
#include <csignal> //SIGINT #include <csignal> //SIGINT
#include <cstdio> #include <cstdio>
@ -28,7 +28,6 @@
#include <zmq.h> #include <zmq.h>
std::vector<std::thread> threads; std::vector<std::thread> threads;
std::vector<sem_t *> semaphores;
sls::TLogLevel printHeadersLevel = sls::logDEBUG; sls::TLogLevel printHeadersLevel = sls::logDEBUG;
/** Define Colors to print data call back in different colors for different /** Define Colors to print data call back in different colors for different
@ -57,16 +56,6 @@ struct FrameStatus {
}; };
FrameStatus *global_frame_status = nullptr; 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() { void cleanup() {
if (global_frame_status) { if (global_frame_status) {
std::lock_guard<std::mutex> lock(global_frame_status->mtx); std::lock_guard<std::mutex> lock(global_frame_status->mtx);
@ -499,38 +488,37 @@ void GetDataCallback(slsDetectorDefs::sls_receiver_header &header,
sem_post(&stat->available); sem_post(&stat->available);
} }
std::vector<sem_t> 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[]) { int main(int argc, char *argv[]) {
auto opts = parseCommandLine(AppType::MultiReceiver, argc, argv); auto opts = parseCommandLine(AppType::MultiReceiver, argc, argv);
auto& o = std::get<CommonOptions>(opts); auto &o = std::get<CommonOptions>(opts);
auto &f = std::get<FrameSyncOptions>(opts);
if (o.versionRequested || o.helpRequested) { if (o.versionRequested || o.helpRequested) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << ']'; LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << ']';
/** - Catch signal SIGINT to close files and call destructors properly */ setupSignalHandler(SIGINT, sigInterruptHandler); // close files on ctrl+c
struct sigaction sa; setupSignalHandler(SIGPIPE, SIG_IGN); // handle locally on socket crash
sa.sa_flags = 0; // no flags semaphores.resize(f.numReceivers);
sa.sa_handler = sigInterruptHandler; // handler function for (auto &s : semaphores) {
sigemptyset(&sa.sa_mask); // dont block additional signals during invocation sem_init(&s, 1, 0);
// of handler
if (sigaction(SIGINT, &sa, nullptr) == -1) {
cprintf(RED, "Could not set handler function for SIGINT\n");
} }
/** - 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<FrameSyncOptions>(opts);
FrameStatus stat{true, false, f.numReceivers}; FrameStatus stat{true, false, f.numReceivers};
// store pointer for signal handler // store pointer for signal handler
global_frame_status = &stat; global_frame_status = &stat;
@ -540,11 +528,8 @@ int main(int argc, char *argv[]) {
std::thread combinerThread(Correlate, &stat); std::thread combinerThread(Correlate, &stat);
for (int i = 0; i != f.numReceivers; ++i) { 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; uint16_t port = o.port + i;
sem_t *semaphore = &semaphores[i];
threads.emplace_back([i, semaphore, port, user_data]() { threads.emplace_back([i, semaphore, port, user_data]() {
sls::Receiver receiver(port); sls::Receiver receiver(port);
receiver.registerCallBackStartAcquisition(StartAcquisitionCallback, receiver.registerCallBackStartAcquisition(StartAcquisitionCallback,
@ -552,10 +537,11 @@ int main(int argc, char *argv[]) {
receiver.registerCallBackAcquisitionFinished( receiver.registerCallBackAcquisitionFinished(
AcquisitionFinishedCallback, user_data); AcquisitionFinishedCallback, user_data);
receiver.registerCallBackRawDataReady(GetDataCallback, user_data); receiver.registerCallBackRawDataReady(GetDataCallback, user_data);
/** - as long as no Ctrl+C */ /** - as long as no Ctrl+C */
// each child shares the common semaphore
sem_wait(semaphore); sem_wait(semaphore);
sem_destroy(semaphore); sem_destroy(semaphore);
delete semaphore;
// clean up frames // clean up frames
if (i == 0) if (i == 0)
@ -563,8 +549,8 @@ int main(int argc, char *argv[]) {
}); });
} }
for (auto &thread : threads) { for (auto &t : threads) {
thread.join(); t.join();
} }
{ {

View File

@ -2,12 +2,12 @@
// Copyright (C) 2021 Contributors to the SLS Detector Package // Copyright (C) 2021 Contributors to the SLS Detector Package
/* Creates the slsMultiReceiver for running multiple receivers form a single /* Creates the slsMultiReceiver for running multiple receivers form a single
* binary */ * binary */
#include "CommandLineOptions.h"
#include "sls/Receiver.h" #include "sls/Receiver.h"
#include "sls/ToString.h" #include "sls/ToString.h"
#include "sls/container_utils.h" #include "sls/container_utils.h"
#include "sls/logger.h" #include "sls/logger.h"
#include "sls/sls_detector_defs.h" #include "sls/sls_detector_defs.h"
#include "CommandLineOptions.h"
#include <csignal> //SIGINT #include <csignal> //SIGINT
#include <cstring> #include <cstring>
@ -26,8 +26,6 @@
#define PRINT_IN_COLOR(c, f, ...) \ #define PRINT_IN_COLOR(c, f, ...) \
printf("\033[%dm" f RESET, 30 + c + 1, ##__VA_ARGS__) printf("\033[%dm" f RESET, 30 + c + 1, ##__VA_ARGS__)
sem_t semaphore;
/** /**
* Start Acquisition Call back (slsMultiReceiver writes data if file write * Start Acquisition Call back (slsMultiReceiver writes data if file write
* enabled) if registerCallBackRawDataReady or * enabled) if registerCallBackRawDataReady or
@ -131,49 +129,34 @@ void GetData(slsDetectorDefs::sls_receiver_header &header,
// imageSize = 26000; // imageSize = 26000;
} }
sem_t semaphore;
/** /**
* Control+C Interrupt Handler * Control+C Interrupt Handler
* to let all the processes know to exit properly * 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[]) { int main(int argc, char *argv[]) {
auto opts = parseCommandLine(AppType::MultiReceiver, argc, argv); auto opts = parseCommandLine(AppType::MultiReceiver, argc, argv);
auto& o = std::get<CommonOptions>(opts); auto& o = std::get<CommonOptions>(opts);
auto &m = std::get<MultiReceiverOptions>(opts);
if (o.versionRequested || o.helpRequested) { if (o.versionRequested || o.helpRequested) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << ']'; LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << ']';
/** - Catch signal SIGINT to close files and call destructors properly */ setupSignalHandler(SIGINT, sigInterruptHandler); // close files on ctrl+c
struct sigaction sa; setupSignalHandler(SIGPIPE, SIG_IGN); // handle locally on socket crash
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 */
sem_init(&semaphore, 1, 0); sem_init(&semaphore, 1, 0);
auto& m = std::get<MultiReceiverOptions>(opts);
/** - loop over receivers */
for (int i = 0; i < m.numReceivers; ++i) { for (int i = 0; i < m.numReceivers; ++i) {
/** - fork process to create child process */ /** - fork process to create child process */
@ -218,6 +201,7 @@ int main(int argc, char *argv[]) {
} }
/** - as long as no Ctrl+C */ /** - as long as no Ctrl+C */
// each child process gets a copy of the semaphore
sem_wait(&semaphore); sem_wait(&semaphore);
sem_destroy(&semaphore); sem_destroy(&semaphore);
@ -233,15 +217,9 @@ int main(int argc, char *argv[]) {
} }
} }
/** - Parent process ignores SIGINT (exits only when all child process /** - Parent process ignores SIGINT and waits for all the child processes to
* exits) */ * handle the signal */
sa.sa_flags = 0; // no flags setupSignalHandler(SIGINT, SIG_IGN);
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";
}
/** - Print Ready and Instructions how to exit */ /** - Print Ready and Instructions how to exit */
std::cout << "Ready ... \n"; std::cout << "Ready ... \n";

View File

@ -1,12 +1,12 @@
// SPDX-License-Identifier: LGPL-3.0-or-other // SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package // Copyright (C) 2021 Contributors to the SLS Detector Package
/* slsReceiver */ /* slsReceiver */
#include "CommandLineOptions.h"
#include "sls/Receiver.h" #include "sls/Receiver.h"
#include "sls/ToString.h" #include "sls/ToString.h"
#include "sls/container_utils.h" #include "sls/container_utils.h"
#include "sls/logger.h" #include "sls/logger.h"
#include "sls/sls_detector_defs.h" #include "sls/sls_detector_defs.h"
#include "CommandLineOptions.h"
#include <csignal> //SIGINT #include <csignal> //SIGINT
#include <semaphore.h> #include <semaphore.h>
@ -20,7 +20,14 @@
sem_t semaphore; 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[]) { int main(int argc, char *argv[]) {
@ -32,28 +39,10 @@ int main(int argc, char *argv[]) {
LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << " ]"; LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << gettid() << " ]";
// Catch signal SIGINT to close files and call destructors properly setupSignalHandler(SIGINT, sigInterruptHandler); // close files on ctrl+c
struct sigaction sa; setupSignalHandler(SIGPIPE, SIG_IGN); // handle locally on socket crash
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";
}
sem_init(&semaphore, 1, 0); sem_init(&semaphore, 1, 0);
try { try {
sls::Receiver r(o.port); sls::Receiver r(o.port);
LOG(sls::logINFO) << "[ Press \'Ctrl+c\' to exit ]"; LOG(sls::logINFO) << "[ Press \'Ctrl+c\' to exit ]";

View File

@ -4,6 +4,7 @@ target_sources(tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/test-GeneralData.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-GeneralData.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-CircularFifo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-CircularFifo.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-ArrangeDataBasedOnBitList.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-ArrangeDataBasedOnBitList.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-Apps.cpp
) )
target_include_directories(tests PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../src>") target_include_directories(tests PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../src>")