mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2026-11-10 02:53:53 +01:00
receiver on mac + gui style
This commit is contained in:
1 parent
d438b37b64
commit
4461951f18
8 files changed
+141
-71
No files matched your search
@@ -18,6 +18,7 @@
|
||||
#include <QFileDialog>
|
||||
#include <QResizeEvent>
|
||||
#include <QSizePolicy>
|
||||
#include <QStyleFactory>
|
||||
|
||||
#include "sls/Version.h"
|
||||
#include <getopt.h>
|
||||
@@ -100,6 +101,12 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
QApplication app(argc, argv);
|
||||
// Use the same (platform independent) widget style everywhere so that the
|
||||
// gui looks the same on linux and macOS. Fusion is built into Qt.
|
||||
// Can still be overridden with -style <name> or QT_STYLE_OVERRIDE.
|
||||
if (QStyleFactory::keys().contains("Fusion", Qt::CaseInsensitive)) {
|
||||
app.setStyle(QStyleFactory::create("Fusion"));
|
||||
}
|
||||
try {
|
||||
sls::qDetectorMain det(multiId, fname, isDeveloper);
|
||||
det.show();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#include "ClientInterface.h"
|
||||
#include "sls/ClientSocket.h"
|
||||
#include "sls/ServerSocket.h"
|
||||
#include "sls/StaticVector.h"
|
||||
#include "sls/ToString.h"
|
||||
@@ -34,6 +35,16 @@ ClientInterface::~ClientInterface() {
|
||||
killTcpThread = true;
|
||||
LOG(logINFO) << "Shutting down TCP Socket on port " << portNumber;
|
||||
server.shutdown();
|
||||
#ifdef __APPLE__
|
||||
// On macOS shutdown() on a listening socket fails with ENOTCONN and does
|
||||
// not wake up the blocking accept() in the tcp thread. Connect to our own
|
||||
// port so that accept() returns and the thread sees killTcpThread.
|
||||
try {
|
||||
ReceiverSocket wakeup("localhost", portNumber);
|
||||
} catch (const RuntimeError &e) {
|
||||
LOG(logWARNING) << "Could not wake up TCP server thread: " << e.what();
|
||||
}
|
||||
#endif
|
||||
LOG(logDEBUG) << "TCP Socket closed on port " << portNumber;
|
||||
tcpThread->join();
|
||||
}
|
||||
@@ -82,6 +93,9 @@ void ClientInterface::startTCPServer() {
|
||||
while (!killTcpThread) {
|
||||
try {
|
||||
auto socket = server.accept();
|
||||
if (killTcpThread) {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
verifyLock(); // lock should be checked only for set (not get),
|
||||
// Move it back?
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <ostream>
|
||||
#include <semaphore.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h> //wait
|
||||
#include <thread>
|
||||
@@ -489,19 +488,8 @@ void GetDataCallback(slsDetectorDefs::sls_receiver_header &header,
|
||||
stat->available.release();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
/** Released once per receiver thread by the main thread on Ctrl+C */
|
||||
sls::counting_semaphore<> stopSemaphore{0};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
CommandLineOptions cli(AppType::FrameSynchronizer);
|
||||
@@ -519,16 +507,12 @@ int main(int argc, char *argv[]) {
|
||||
LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << sls::getThreadId()
|
||||
<< ']';
|
||||
|
||||
// close files on ctrl+c
|
||||
sls::setupSignalHandler(SIGINT, sigInterruptHandler);
|
||||
// close files on ctrl+c: SIGINT is blocked (before any thread is created,
|
||||
// so they all inherit the mask) and waited for in the main thread
|
||||
sls::blockSignal(SIGINT);
|
||||
// handle locally on socket crash
|
||||
sls::setupSignalHandler(SIGPIPE, SIG_IGN);
|
||||
|
||||
semaphores.resize(f.numReceivers);
|
||||
for (auto &s : semaphores) {
|
||||
sem_init(&s, 0, 0);
|
||||
}
|
||||
|
||||
FrameStatus stat{true, false, f.numReceivers};
|
||||
// store pointer for signal handler
|
||||
global_frame_status = &stat;
|
||||
@@ -540,9 +524,7 @@ int main(int argc, char *argv[]) {
|
||||
std::exception_ptr threadException = nullptr;
|
||||
for (int i = 0; i != f.numReceivers; ++i) {
|
||||
uint16_t port = f.port + i;
|
||||
sem_t *semaphore = &semaphores[i];
|
||||
threads.emplace_back([i, semaphore, port, user_data,
|
||||
&threadException]() {
|
||||
threads.emplace_back([i, port, user_data, &threadException]() {
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Thread " << i << " [ Tid: " << sls::getThreadId() << ']';
|
||||
try {
|
||||
@@ -555,24 +537,27 @@ int main(int argc, char *argv[]) {
|
||||
user_data);
|
||||
|
||||
/** - as long as no Ctrl+C */
|
||||
// each child shares the common semaphore
|
||||
sem_wait(semaphore);
|
||||
stopSemaphore.acquire();
|
||||
} catch (...) {
|
||||
// capture exception and raise SIGINT to exit gracefully
|
||||
// capture exception and send SIGINT to the process (not
|
||||
// raise(), which would target this thread where it is
|
||||
// blocked) so the main thread shuts everything down
|
||||
threadException = std::current_exception();
|
||||
raise(SIGINT);
|
||||
kill(getpid(), SIGINT);
|
||||
}
|
||||
LOG(sls::logINFOBLUE) << "Exiting Thread " << i
|
||||
<< " [ Tid: " << sls::getThreadId() << " ]";
|
||||
});
|
||||
}
|
||||
|
||||
LOG(sls::logINFO) << "[ Press \'Ctrl+c\' to exit ]";
|
||||
sls::waitForSignal(SIGINT);
|
||||
stopSemaphore.release(f.numReceivers);
|
||||
|
||||
for (auto &t : threads) {
|
||||
t.join();
|
||||
}
|
||||
|
||||
for (auto &s : semaphores)
|
||||
sem_destroy(&s);
|
||||
cleanup();
|
||||
|
||||
{
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
#include <csignal> //SIGINT
|
||||
#include <cstring>
|
||||
#include <semaphore.h>
|
||||
#include <sys/wait.h> //wait
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -125,18 +124,6 @@ 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 signal) {
|
||||
(void)signal; // suppress unused warning if needed
|
||||
sem_post(&semaphore);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
CommandLineOptions cli(AppType::MultiReceiver);
|
||||
@@ -154,13 +141,12 @@ int main(int argc, char *argv[]) {
|
||||
LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << sls::getThreadId()
|
||||
<< ']';
|
||||
|
||||
// close files on ctrl+c
|
||||
sls::setupSignalHandler(SIGINT, sigInterruptHandler);
|
||||
// close files on ctrl+c: SIGINT is blocked before forking so that every
|
||||
// child process inherits the mask and can wait for it synchronously
|
||||
sls::blockSignal(SIGINT);
|
||||
// handle locally on socket crash
|
||||
sls::setupSignalHandler(SIGPIPE, SIG_IGN);
|
||||
|
||||
sem_init(&semaphore, 1, 0);
|
||||
|
||||
/** - loop over receivers */
|
||||
for (int i = 0; i < m.numReceivers; ++i) {
|
||||
|
||||
@@ -206,15 +192,12 @@ 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);
|
||||
sls::waitForSignal(SIGINT);
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Exiting Child Process [ Tid: " << sls::getThreadId()
|
||||
<< ']';
|
||||
exit(EXIT_SUCCESS);
|
||||
} catch (...) {
|
||||
sem_destroy(&semaphore);
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Exiting Child Process [ Tid: " << sls::getThreadId()
|
||||
<< " ]";
|
||||
|
||||
@@ -11,20 +11,8 @@
|
||||
#include "sls/thread_utils.h"
|
||||
|
||||
#include <csignal> //SIGINT
|
||||
#include <semaphore.h>
|
||||
#include <unistd.h>
|
||||
|
||||
sem_t 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[]) {
|
||||
|
||||
CommandLineOptions cli(AppType::SingleReceiver);
|
||||
@@ -42,20 +30,17 @@ int main(int argc, char *argv[]) {
|
||||
LOG(sls::logINFOBLUE) << "Current Process [ Tid: " << sls::getThreadId()
|
||||
<< " ]";
|
||||
|
||||
// close files on ctrl+c
|
||||
sls::setupSignalHandler(SIGINT, sigInterruptHandler);
|
||||
// close files on ctrl+c: SIGINT is blocked (before the receiver threads
|
||||
// are created, so they inherit the mask) and waited for synchronously
|
||||
sls::blockSignal(SIGINT);
|
||||
// handle locally on socket crash
|
||||
sls::setupSignalHandler(SIGPIPE, SIG_IGN);
|
||||
|
||||
sem_init(&semaphore, 1, 0);
|
||||
|
||||
try {
|
||||
sls::Receiver r(o.port);
|
||||
LOG(sls::logINFO) << "[ Press \'Ctrl+c\' to exit ]";
|
||||
sem_wait(&semaphore);
|
||||
sem_destroy(&semaphore);
|
||||
sls::waitForSignal(SIGINT);
|
||||
} catch (...) {
|
||||
sem_destroy(&semaphore);
|
||||
LOG(sls::logINFOBLUE)
|
||||
<< "Exiting [ Tid: " << sls::getThreadId() << " ]";
|
||||
throw;
|
||||
|
||||
@@ -91,4 +91,13 @@ IpAddr InterfaceNameToIp(const std::string &ifn);
|
||||
void validatePortNumber(uint16_t port);
|
||||
void validatePortRange(uint16_t startPort, int numPorts);
|
||||
void setupSignalHandler(int signal, void (*handler)(int));
|
||||
|
||||
/** Block a signal in the calling thread. Threads created afterwards (and
|
||||
* child processes) inherit the mask, so call this before spawning them. */
|
||||
void blockSignal(int signal);
|
||||
|
||||
/** Wait synchronously until the (previously blocked) signal is delivered to
|
||||
* the process. Replaces the signal handler + unnamed POSIX semaphore
|
||||
* (sem_init) pattern, which is not implemented on macOS. */
|
||||
void waitForSignal(int signal);
|
||||
} // namespace sls
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <iostream>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
@@ -91,5 +92,35 @@ void UdpRxSocket::setBufferSize(int size) {
|
||||
void UdpRxSocket::Shutdown() {
|
||||
// not closing yet on purpose, but read gives -1
|
||||
shutdown(sockfd_, SHUT_RDWR);
|
||||
#ifdef __APPLE__
|
||||
// On macOS shutdown() on an unconnected UDP socket fails with ENOTCONN
|
||||
// and does not wake up a blocking recvfrom(). Send an empty datagram to
|
||||
// our own port instead: it is read as 0 bytes, so ReceivePacket returns
|
||||
// false and the listener thread sees that the socket is no longer alive.
|
||||
sockaddr_storage addr{};
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
if (getsockname(sockfd_, reinterpret_cast<sockaddr *>(&addr), &addrlen) ==
|
||||
-1) {
|
||||
return;
|
||||
}
|
||||
if (addr.ss_family == AF_INET) {
|
||||
auto *a = reinterpret_cast<sockaddr_in *>(&addr);
|
||||
if (a->sin_addr.s_addr == htonl(INADDR_ANY))
|
||||
a->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
} else if (addr.ss_family == AF_INET6) {
|
||||
auto *a = reinterpret_cast<sockaddr_in6 *>(&addr);
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr))
|
||||
a->sin6_addr = in6addr_loopback;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
int wakefd = socket(addr.ss_family, SOCK_DGRAM, 0);
|
||||
if (wakefd == -1) {
|
||||
return;
|
||||
}
|
||||
sendto(wakefd, nullptr, 0, 0, reinterpret_cast<sockaddr *>(&addr),
|
||||
addrlen);
|
||||
close(wakefd);
|
||||
#endif
|
||||
}
|
||||
} // namespace sls
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <algorithm>
|
||||
#include <arpa/inet.h>
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <csignal>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
@@ -14,6 +15,10 @@
|
||||
#include <limits>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#ifdef __APPLE__
|
||||
#include <net/if_dl.h>
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <sstream>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -179,7 +184,33 @@ IpAddr InterfaceNameToIp(const std::string &ifn) {
|
||||
MacAddr InterfaceNameToMac(const std::string &inf) {
|
||||
|
||||
#ifdef __APPLE__
|
||||
throw RuntimeError("InterfaceNameToMac not implemented on macOS yet");
|
||||
// No SIOCGIFHWADDR on macOS: the hardware address is the AF_LINK entry
|
||||
// that getifaddrs() returns for the interface
|
||||
struct ifaddrs *ifaddr = nullptr;
|
||||
if (getifaddrs(&ifaddr) == -1) {
|
||||
throw RuntimeError("getifaddrs failed [" +
|
||||
std::string(strerror(errno)) + ']');
|
||||
}
|
||||
MacAddr result{};
|
||||
for (auto *ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
|
||||
if (ifa->ifa_addr == nullptr || ifa->ifa_addr->sa_family != AF_LINK ||
|
||||
inf != ifa->ifa_name) {
|
||||
continue;
|
||||
}
|
||||
auto *sdl = reinterpret_cast<struct sockaddr_dl *>(ifa->ifa_addr);
|
||||
if (sdl->sdl_alen != 6) {
|
||||
continue; // not an ethernet style address (e.g. utun, lo0)
|
||||
}
|
||||
auto *hw = reinterpret_cast<const unsigned char *>(LLADDR(sdl));
|
||||
uint64_t addr = 0;
|
||||
for (int j = 0; j < 6; ++j) {
|
||||
addr = (addr << 8) | hw[j];
|
||||
}
|
||||
result = MacAddr(addr);
|
||||
break;
|
||||
}
|
||||
freeifaddrs(ifaddr);
|
||||
return result;
|
||||
#else
|
||||
|
||||
// TODO! Copied from genericSocket needs to be refactored!
|
||||
@@ -234,4 +265,29 @@ void setupSignalHandler(int signal, void (*handler)(int)) {
|
||||
std::string(strsignal(signal)));
|
||||
}
|
||||
}
|
||||
|
||||
void blockSignal(int signal) {
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, signal);
|
||||
if (pthread_sigmask(SIG_BLOCK, &set, nullptr) != 0) {
|
||||
throw RuntimeError("Could not block " + std::string(strsignal(signal)));
|
||||
}
|
||||
}
|
||||
|
||||
void waitForSignal(int signal) {
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, signal);
|
||||
int received = 0;
|
||||
int ret = 0;
|
||||
do {
|
||||
ret = sigwait(&set, &received);
|
||||
} while (ret == EINTR);
|
||||
if (ret != 0) {
|
||||
throw RuntimeError("Could not wait for " +
|
||||
std::string(strsignal(signal)) + ": " +
|
||||
strerror(ret));
|
||||
}
|
||||
}
|
||||
} // namespace sls
|
||||
Reference in new issue
Block a user