diff --git a/Framework/LiveData/inc/MantidLiveData/ISIS/FakeISISEventDAE.h b/Framework/LiveData/inc/MantidLiveData/ISIS/FakeISISEventDAE.h index 2f648a9df8f0af3c299aa202f5ffbaae08b195ce..c9cb0496b4b23823da4079fc323fcac2d0b5def6 100644 --- a/Framework/LiveData/inc/MantidLiveData/ISIS/FakeISISEventDAE.h +++ b/Framework/LiveData/inc/MantidLiveData/ISIS/FakeISISEventDAE.h @@ -6,23 +6,14 @@ //---------------------------------------------------------------------- #include "MantidAPI/Algorithm.h" -#include <mutex> - -namespace Poco { -namespace Net { -class TCPServer; -} -} - namespace Mantid { namespace LiveData { /** Simulates ISIS histogram DAE. It runs continuously until canceled and - listens to port 6789 for - ISIS DAE commands. + listens to port 6789 for ISIS DAE commands. Copyright © 2008-9 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge - National Laboratory & European Spallation Source + National Laboratory & European Spallation Source This file is part of Mantid. @@ -44,9 +35,6 @@ namespace LiveData { */ class FakeISISEventDAE : public API::Algorithm { public: - FakeISISEventDAE(); - ~FakeISISEventDAE() override; - /// Algorithm's name for identification overriding a virtual method const std::string name() const override { return "FakeISISEventDAE"; } /// Algorithm's version for identification overriding a virtual method @@ -67,10 +55,6 @@ public: private: void init() override; void exec() override; - /// Poco TCP server - Poco::Net::TCPServer *m_server; - /// Mutex - std::mutex m_mutex; }; } // namespace LiveData diff --git a/Framework/LiveData/inc/MantidLiveData/ISIS/FakeISISHistoDAE.h b/Framework/LiveData/inc/MantidLiveData/ISIS/FakeISISHistoDAE.h index 87a7dab447a2c2c066a911ee8d8f3f127b0e6117..84c187739b3ef62cf0f3e7736b2cb1d3ef26d2d4 100644 --- a/Framework/LiveData/inc/MantidLiveData/ISIS/FakeISISHistoDAE.h +++ b/Framework/LiveData/inc/MantidLiveData/ISIS/FakeISISHistoDAE.h @@ -5,30 +5,22 @@ // Includes //---------------------------------------------------------------------- #include "MantidAPI/Algorithm.h" -#include <mutex> - -namespace Poco { -namespace Net { -class TCPServer; -} -} namespace Mantid { namespace LiveData { /** Simulates ISIS histogram DAE. It runs continuously until canceled and - listens to port 6789 for - ISIS DAE commands. + listens to port 6789 for ISIS DAE commands. Data is generated starting at 10000 microseconds Time of flight, and each - bin requested covers 100 microseconds. + bin requested covers 100 microseconds. The algorithm silently defines three additional spectra with numbers - NSpectra+1, NSpectra+2 and NSpectra+3 in a + NSpectra+1, NSpectra+2 and NSpectra+3 in a different time regime (they have different binning to the rest of the - spectra). + spectra). Copyright © 2008-9 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge - National Laboratory & European Spallation Source + National Laboratory & European Spallation Source This file is part of Mantid. @@ -50,13 +42,10 @@ namespace LiveData { */ class DLLExport FakeISISHistoDAE : public API::Algorithm { public: - FakeISISHistoDAE(); - ~FakeISISHistoDAE() override; - /// Algorithm's name for identification overriding a virtual method - const std::string name() const override { return "FakeISISHistoDAE"; }; + const std::string name() const override { return "FakeISISHistoDAE"; } /// Algorithm's version for identification overriding a virtual method - int version() const override { return 1; }; + int version() const override { return 1; } /// Algorithm's category for identification overriding a virtual method const std::string category() const override { return "DataHandling\\DataAcquisition"; @@ -73,10 +62,6 @@ private: // Implement abstract Algorithm methods void init() override; void exec() override; - /// Poco TCP server - Poco::Net::TCPServer *m_server; - /// Mutex - std::mutex m_mutex; }; } // namespace LiveData diff --git a/Framework/LiveData/inc/MantidLiveData/ISIS/ISISLiveEventDataListener.h b/Framework/LiveData/inc/MantidLiveData/ISIS/ISISLiveEventDataListener.h index 1609026442d0f8d06652f84f7bdeaebc058afcfd..d773d374a82a23d3e0bb528461c6ef68fe77e0d9 100644 --- a/Framework/LiveData/inc/MantidLiveData/ISIS/ISISLiveEventDataListener.h +++ b/Framework/LiveData/inc/MantidLiveData/ISIS/ISISLiveEventDataListener.h @@ -19,7 +19,7 @@ const long RECV_TIMEOUT = 30; // Sleep time in case we need to wait for the data to become available (in // milliseconds) -const long RECV_WAIT = 1; +const long RECV_WAIT = 10; //---------------------------------------------------------------------- // Forward declarations @@ -164,6 +164,8 @@ protected: void Receive(T &buffer, const std::string &head, const std::string &msg) { long timeout = 0; while (m_socket.available() < static_cast<int>(sizeof(buffer))) { + if (m_stopThread) + return; Poco::Thread::sleep(RECV_WAIT); timeout += RECV_WAIT; if (timeout > RECV_TIMEOUT * 1000) @@ -190,7 +192,7 @@ protected: /// Thread that reads events from the DAE in the background Poco::Thread m_thread; /// background thread checks this periodically. If true, the thread exits - bool m_stopThread; + std::atomic<bool> m_stopThread; /// Holds on to any exceptions that were thrown in the background thread so /// that we /// can re-throw them in the forground thread diff --git a/Framework/LiveData/src/ISIS/FakeISISEventDAE.cpp b/Framework/LiveData/src/ISIS/FakeISISEventDAE.cpp index 4e22d55816a660cb0447323e3be79c1c4abd5420..b16acedc7e39170baae9503a9164573812576e00 100644 --- a/Framework/LiveData/src/ISIS/FakeISISEventDAE.cpp +++ b/Framework/LiveData/src/ISIS/FakeISISEventDAE.cpp @@ -7,15 +7,12 @@ #include "MantidKernel/MersenneTwister.h" #include "MantidKernel/Timer.h" +#include <Poco/ActiveResult.h> #include <Poco/Net/TCPServer.h> #include <Poco/Net/StreamSocket.h> -#include <Poco/ActiveResult.h> -#include <Poco/Thread.h> #include <boost/random/uniform_int.hpp> -#include <numeric> - namespace Mantid { namespace LiveData { // Register the algorithm into the algorithm factory @@ -147,17 +144,6 @@ public: }; } // end anonymous -/// (Empty) Constructor -FakeISISEventDAE::FakeISISEventDAE() : m_server(nullptr) {} - -/// Destructor -FakeISISEventDAE::~FakeISISEventDAE() { - if (m_server) { - m_server->stop(); - delete m_server; - } -} - /** * Declare the algorithm properties */ @@ -198,19 +184,18 @@ void FakeISISEventDAE::exec() { histoDAE->setProperty("NPeriods", nper); histoDAE->setProperty("NSpectra", nspec); histoDAE->setProperty("Port", port + 1); - Poco::ActiveResult<bool> histoDAEHandle = histoDAE->executeAsync(); + auto histoDAEHandle = histoDAE->executeAsync(); auto prog = boost::make_shared<Progress>(this, 0.0, 1.0, 100); prog->setNotifyStep(0); prog->report(0, "Waiting for client"); - std::lock_guard<std::mutex> lock(m_mutex); Poco::Net::ServerSocket socket(static_cast<Poco::UInt16>(port)); socket.listen(); - m_server = new Poco::Net::TCPServer( + Poco::Net::TCPServer server( TestServerConnectionFactory::Ptr( new TestServerConnectionFactory(nper, nspec, rate, nevents, prog)), socket); - m_server->start(); + server.start(); // Keep going until you get cancelled while (true) { try { @@ -223,19 +208,12 @@ void FakeISISEventDAE::exec() { // Sleep for 50 msec Poco::Thread::sleep(50); } + // It's most likely that we got here from a cancel request + // so calling prog->report after this point + // will generate another CancelException histoDAE->cancel(); histoDAEHandle.wait(); - if (m_server) { - m_server->stop(); - m_server = nullptr; - } socket.close(); - - prog->report(90, "Closing ISIS event DAE"); - histoDAE->setLogging(false); // hide the final closedown message to the log it - // is confusing as it is a child alg. - histoDAE->cancel(); - histoDAEHandle.wait(); } } // namespace LiveData diff --git a/Framework/LiveData/src/ISIS/FakeISISHistoDAE.cpp b/Framework/LiveData/src/ISIS/FakeISISHistoDAE.cpp index bb9b11d2eeaa89eb54ca98966863c3bf395d31c9..bea46be21c0ad16c5abbae6e96493b28a7a01bb6 100644 --- a/Framework/LiveData/src/ISIS/FakeISISHistoDAE.cpp +++ b/Framework/LiveData/src/ISIS/FakeISISHistoDAE.cpp @@ -2,11 +2,9 @@ // Includes //---------------------------------------------------------------------- #include "MantidLiveData/ISIS/FakeISISHistoDAE.h" -#include <numeric> #include <Poco/Net/TCPServer.h> #include <Poco/Net/StreamSocket.h> -#include <Poco/Thread.h> namespace Mantid { namespace LiveData { @@ -314,17 +312,6 @@ public: using namespace Kernel; using namespace API; -/// (Empty) Constructor -FakeISISHistoDAE::FakeISISHistoDAE() : m_server(nullptr) {} - -/// Destructor -FakeISISHistoDAE::~FakeISISHistoDAE() { - if (m_server) { - m_server->stop(); - delete m_server; - } -} - /** * Declare the algorithm properties */ @@ -352,16 +339,15 @@ void FakeISISHistoDAE::exec() { int nbins = getProperty("NBins"); int port = getProperty("Port"); - std::lock_guard<std::mutex> lock(m_mutex); Poco::Net::ServerSocket socket(static_cast<Poco::UInt16>(port)); socket.listen(); - m_server = new Poco::Net::TCPServer( + Poco::Net::TCPServer server( TestServerConnectionFactory::Ptr( new TestServerConnectionFactory(nper, nspec, nbins)), socket); - m_server->start(); - // Keep going until you get cancelled + server.start(); + // Keep going until you get cancelled or an error occurs while (true) { try { // Exit if the user presses cancel @@ -374,10 +360,10 @@ void FakeISISHistoDAE::exec() { // Sleep for 50 msec Poco::Thread::sleep(50); } - if (m_server) { - m_server->stop(); - m_server = nullptr; - } + // It's most likely that we got here from a cancel request + // so calling prog->report after this point + // will generate another CancelException + server.stop(); socket.close(); } diff --git a/Framework/LiveData/src/ISIS/ISISLiveEventDataListener.cpp b/Framework/LiveData/src/ISIS/ISISLiveEventDataListener.cpp index ef62b701c44ff04e8463b0294632f56dea03f25f..53c620436f3292a33d09d648cac9145a94bcde34 100644 --- a/Framework/LiveData/src/ISIS/ISISLiveEventDataListener.cpp +++ b/Framework/LiveData/src/ISIS/ISISLiveEventDataListener.cpp @@ -235,6 +235,8 @@ void ISISLiveEventDataListener::run() { // get the header with the type of the packet Receive(events.head, "Events header", "Corrupt stream - you should reconnect."); + if (m_stopThread) + break; if (!(events.head.type == TCPStreamEventHeader::Neutron)) { // don't know what to do with it - stop throw std::runtime_error("Unknown packet type."); @@ -244,6 +246,8 @@ void ISISLiveEventDataListener::run() { // get the header with the sream size Receive(events.head_n, "Neutrons header", "Corrupt stream - you should reconnect."); + if (m_stopThread) + break; CollectJunk(events.head_n); // absolute pulse (frame) time @@ -282,8 +286,7 @@ void ISISLiveEventDataListener::run() { saveEvents(events.data, pulseTime, events.head_n.period); } - } catch (std::runtime_error & - e) { // exception handler for generic runtime exceptions + } catch (std::runtime_error &e) { g_log.error() << "Caught a runtime exception.\nException message: " << e.what() << '\n'; @@ -291,8 +294,8 @@ void ISISLiveEventDataListener::run() { m_backgroundException = boost::make_shared<std::runtime_error>(e); - } catch (std::invalid_argument & - e) { // TimeSeriesProperty (and possibly some other things) can + } catch (std::invalid_argument &e) { + // TimeSeriesProperty (and possibly some other things) can // can throw these errors g_log.error() << "Caught an invalid argument exception.\nException message: " @@ -303,7 +306,7 @@ void ISISLiveEventDataListener::run() { newMsg += e.what(); m_backgroundException = boost::make_shared<std::runtime_error>(newMsg); - } catch (...) { // Default exception handler + } catch (...) { g_log.error() << "Uncaught exception in ISISLiveEventDataListener network " "read thread.\n"; m_isConnected = false; diff --git a/docs/source/algorithms/FakeISISEventDAE-v1.rst b/docs/source/algorithms/FakeISISEventDAE-v1.rst index 1cbf89c3dd270c4a5301ee45f36d8ed352c2d49f..721609488025ed9f0fb4dd61d19050208dc3106b 100644 --- a/docs/source/algorithms/FakeISISEventDAE-v1.rst +++ b/docs/source/algorithms/FakeISISEventDAE-v1.rst @@ -25,10 +25,7 @@ Usage **Example:** -.. This test is currently hanging on macOS as the MonitorLiveData algorithm - is taking a long time to cancel - -.. code-block:: python +.. testcode:: exFakeISISEventDAE from threading import Thread import time @@ -45,20 +42,22 @@ Usage def captureLive(): ConfigService.setFacility("TEST_LIVE") - # start a Live data listener updating every second, that rebins the data - # and replaces the results each time with those of the last second. - StartLiveData(Instrument='ISIS_Event', OutputWorkspace='wsOut', UpdateEvery=1, - ProcessingAlgorithm='Rebin', ProcessingProperties='Params=10000,1000,20000;PreserveEvents=1', - AccumulationMethod='Add', PreserveEvents=True) - - # give it a couple of seconds before stopping it - time.sleep(2) - - # This will cancel both algorithms - # you can do the same in the GUI - # by clicking on the details button on the bottom right - AlgorithmManager.newestInstanceOf("MonitorLiveData").cancel() - AlgorithmManager.newestInstanceOf("FakeISISEventDAE").cancel() + try: + # start a Live data listener updating every second, that rebins the data + # and replaces the results each time with those of the last second. + StartLiveData(Instrument='ISIS_Event', OutputWorkspace='wsOut', UpdateEvery=1, + ProcessingAlgorithm='Rebin', ProcessingProperties='Params=10000,1000,20000;PreserveEvents=1', + AccumulationMethod='Add', PreserveEvents=True) + + # give it a couple of seconds before stopping it + time.sleep(2) + finally: + # This will cancel both algorithms + # you can do the same in the GUI + # by clicking on the details button on the bottom right + AlgorithmManager.newestInstanceOf("MonitorLiveData").cancel() + AlgorithmManager.newestInstanceOf("FakeISISEventDAE").cancel() + time.sleep(1) #-------------------------------------------------------------------------------------------------- oldFacility = ConfigService.getFacility().name() diff --git a/docs/source/algorithms/FakeISISHistoDAE-v1.rst b/docs/source/algorithms/FakeISISHistoDAE-v1.rst index 8d65f2a33f540f5147c24b2be4059c25c3db4e0e..6cbe8c7711f5fc23fe8da78f72c276a675f400d0 100644 --- a/docs/source/algorithms/FakeISISHistoDAE-v1.rst +++ b/docs/source/algorithms/FakeISISHistoDAE-v1.rst @@ -36,20 +36,21 @@ Usage def captureLive(): ConfigService.setFacility("TEST_LIVE") - # start a Live data listener updating every second, that rebins the data - # and replaces the results each time with those of the last second. - StartLiveData(Instrument='ISIS_Histogram', OutputWorkspace='wsOut', UpdateEvery=1, - AccumulationMethod='Replace') - - # give it a couple of seconds before stopping it - time.sleep(2) - - # This will cancel both algorithms - # you can do the same in the GUI - # by clicking on the details button on the bottom right - AlgorithmManager.newestInstanceOf("MonitorLiveData").cancel() - AlgorithmManager.newestInstanceOf("FakeISISHistoDAE").cancel() - time.sleep(1) # give them time to cancel + try: + # start a Live data listener updating every second, that rebins the data + # and replaces the results each time with those of the last second. + StartLiveData(Instrument='ISIS_Histogram', OutputWorkspace='wsOut', UpdateEvery=1, + AccumulationMethod='Replace') + + # give it a couple of seconds before stopping it + time.sleep(2) + finally: + # This will cancel both algorithms + # you can do the same in the GUI + # by clicking on the details button on the bottom right + AlgorithmManager.newestInstanceOf("MonitorLiveData").cancel() + AlgorithmManager.newestInstanceOf("FakeISISHistoDAE").cancel() + time.sleep(1) #-------------------------------------------------------------------------------------------------- oldFacility = ConfigService.getFacility().name() diff --git a/docs/source/algorithms/StartLiveData-v1.rst b/docs/source/algorithms/StartLiveData-v1.rst index 27df59b0e3d074c69a50808a8b5bee49f0344bfe..03cf63fcf7ac035c691aaaab96cbb2b3afd223bd 100644 --- a/docs/source/algorithms/StartLiveData-v1.rst +++ b/docs/source/algorithms/StartLiveData-v1.rst @@ -123,20 +123,22 @@ Usage def captureLive(): ConfigService.setFacility("TEST_LIVE") - # start a Live data listener updating every second, that rebins the data - # and replaces the results each time with those of the last second. - StartLiveData(Instrument='ISIS_Event', OutputWorkspace='wsOut', UpdateEvery=1, - ProcessingAlgorithm='Rebin', ProcessingProperties='Params=10000,1000,20000;PreserveEvents=1', - AccumulationMethod='Add', PreserveEvents=True) - - # give it a couple of seconds before stopping it - time.sleep(2) - - # This will cancel both algorithms - # you can do the same in the GUI - # by clicking on the details button on the bottom right - AlgorithmManager.newestInstanceOf("MonitorLiveData").cancel() - AlgorithmManager.newestInstanceOf("FakeISISEventDAE").cancel() + try: + # start a Live data listener updating every second, that rebins the data + # and replaces the results each time with those of the last second. + StartLiveData(Instrument='ISIS_Event', OutputWorkspace='wsOut', UpdateEvery=1, + ProcessingAlgorithm='Rebin', ProcessingProperties='Params=10000,1000,20000;PreserveEvents=1', + AccumulationMethod='Add', PreserveEvents=True) + + # give it a couple of seconds before stopping it + time.sleep(2) + finally: + # This will cancel both algorithms + # you can do the same in the GUI + # by clicking on the details button on the bottom right + AlgorithmManager.newestInstanceOf("MonitorLiveData").cancel() + AlgorithmManager.newestInstanceOf("FakeISISEventDAE").cancel() + time.sleep(1) #-------------------------------------------------------------------------------------------------- oldFacility = ConfigService.getFacility().name() @@ -187,20 +189,22 @@ Output: def captureLive(): ConfigService.setFacility("TEST_LIVE") - # Start a Live data listener updating every second, - # that replaces the results each time with those of the last second. - # Load only spectra 2,4, and 6 from periods 1 and 3 - StartLiveData(Instrument='ISIS_Histogram', OutputWorkspace='wsOut', UpdateEvery=1, - AccumulationMethod='Replace', PeriodList=[1,3],SpectraList=[2,4,6]) - - # give it a couple of seconds before stopping it - time.sleep(2) - - # This will cancel both algorithms - # you can do the same in the GUI - # by clicking on the details button on the bottom right - AlgorithmManager.newestInstanceOf("MonitorLiveData").cancel() - AlgorithmManager.newestInstanceOf("FakeISISHistoDAE").cancel() + try: + # Start a Live data listener updating every second, + # that replaces the results each time with those of the last second. + # Load only spectra 2,4, and 6 from periods 1 and 3 + StartLiveData(Instrument='ISIS_Histogram', OutputWorkspace='wsOut', UpdateEvery=1, + AccumulationMethod='Replace', PeriodList=[1,3],SpectraList=[2,4,6]) + + # give it a couple of seconds before stopping it + time.sleep(2) + finally: + # This will cancel both algorithms + # you can do the same in the GUI + # by clicking on the details button on the bottom right + AlgorithmManager.newestInstanceOf("MonitorLiveData").cancel() + AlgorithmManager.newestInstanceOf("FakeISISHistoDAE").cancel() + time.sleep(1) #-------------------------------------------------------------------------------------------------- oldFacility = ConfigService.getFacility().name()