From dc33baaa3f2563bd194892bc05501d04ebb1f752 Mon Sep 17 00:00:00 2001
From: Martin Killenberg <martin.killenberg@desy.de>
Date: Tue, 31 Oct 2017 02:24:39 +0100
Subject: [PATCH] changed updater to run in its own thread. Tests still using
 doocs update, which is just doing an insanely long sleep of 1 second.

---
 include/CSAdapterEqFct.h         |  3 ++-
 include/DoocsUpdater.h           | 12 ++++++++----
 src/CSAdapterEqFct.cc            | 12 +++++++++---
 src/DoocsUpdater.cc              | 22 ++++++++++++++++++++++
 src/eq_create.cc                 |  1 +
 tests/src/testCSAdapterEqFct.cpp | 21 ++++++++++++---------
 6 files changed, 54 insertions(+), 17 deletions(-)

diff --git a/include/CSAdapterEqFct.h b/include/CSAdapterEqFct.h
index 3a80e50..0a7f04b 100644
--- a/include/CSAdapterEqFct.h
+++ b/include/CSAdapterEqFct.h
@@ -30,7 +30,8 @@ class CSAdapterEqFct : public EqFct , boost::noncopyable {
 		   boost::shared_ptr<ControlSystemPVManager> const & controlSystemPVManager,
                    boost::shared_ptr<DoocsUpdater> const & updater,
 		   std::string fctName = std::string());
-
+    ~CSAdapterEqFct();
+    
     void init();
     void update();
     int fct_code();
diff --git a/include/DoocsUpdater.h b/include/DoocsUpdater.h
index 924437c..b368140 100644
--- a/include/DoocsUpdater.h
+++ b/include/DoocsUpdater.h
@@ -4,6 +4,7 @@
 #include <unordered_map>
 #include <map>
 #include <mtca4u/TransferElement.h>
+#include <boost/noncopyable.hpp>
 
 namespace ChimeraTK{
   /** A class to synchronise DeviceToControlSystem variable to Doocs.
@@ -12,13 +13,16 @@ namespace ChimeraTK{
    *  when the thread is started, and (FIXME can be stopped by the stop() function which
    *  returns after the thread has been joined). This happens latest in the destructor.
    */
-  class DoocsUpdater{
+  class DoocsUpdater: public boost::noncopyable{
   public:
-    ~DoocsUpdater(){};
+    ~DoocsUpdater();
     void update(); // Update all variables once. This is the intermediate solution
                    // before we have implemented the thread, and for testing
-    void run(){};
-    void stop(){};
+
+    void updateLoop(); // Endless loop with interruption point around the update function.
+                       // Intermediate solution until we have a working/testable version of readAny()
+    void run();
+    void stop();
 
     void addVariable( mtca4u::TransferElement & variable, std::function<void ()> updaterFunction);
   protected:
diff --git a/src/CSAdapterEqFct.cc b/src/CSAdapterEqFct.cc
index 9e249e4..a3ae2e7 100644
--- a/src/CSAdapterEqFct.cc
+++ b/src/CSAdapterEqFct.cc
@@ -22,6 +22,11 @@ namespace ChimeraTK{
     registerProcessVariablesInDoocs();
   }
   
+  CSAdapterEqFct::~CSAdapterEqFct(){
+    //stop the updater thread before any of the process variables go out of scope
+    updater_->stop();
+  }
+
   void CSAdapterEqFct::init(){
     std::cout << "this is eqfct init of " << fct_name() << std::endl;
   }
@@ -33,9 +38,10 @@ namespace ChimeraTK{
 
     // dirty hack until this is moved to a thread: unlock this EqFct. The updater does the locking
     // and the locks are not re-entrant
-    unlock();
-    updater_->update();
-    lock();
+    //unlock();
+    //updater_->update();
+    //lock();
+    sleep(1);
   }
     
   int CSAdapterEqFct::fct_code(){
diff --git a/src/DoocsUpdater.cc b/src/DoocsUpdater.cc
index d9e6e1e..78898fa 100644
--- a/src/DoocsUpdater.cc
+++ b/src/DoocsUpdater.cc
@@ -20,4 +20,26 @@ namespace ChimeraTK{
     }
   }
 
+  void DoocsUpdater::updateLoop(){
+    while(true){
+      update();
+      // FIXME: This is brainstorming. Use testable sleep here
+      boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
+    }
+  }
+
+  void DoocsUpdater::run(){
+    _syncThread = boost::thread( boost::bind( &DoocsUpdater::updateLoop, this) );
+  }
+  
+  void DoocsUpdater::stop(){
+    _syncThread.interrupt();
+    _syncThread.join();    
+  }
+
+  DoocsUpdater::~DoocsUpdater(){
+    stop();
+  }
+ 
+  
 }//namespace ChimeraTK
diff --git a/src/eq_create.cc b/src/eq_create.cc
index fff70ed..a2594ee 100644
--- a/src/eq_create.cc
+++ b/src/eq_create.cc
@@ -48,4 +48,5 @@ EqFct* eq_create (int eq_code, void *) {
  * the config file. We start the application here. It will be launched in a separate thread. */
 void post_init_epilog() {
   ChimeraTK::ApplicationBase::getInstance().run();
+  doocsAdapter.updater->run();
 }
diff --git a/tests/src/testCSAdapterEqFct.cpp b/tests/src/testCSAdapterEqFct.cpp
index ae36f6b..09231a7 100644
--- a/tests/src/testCSAdapterEqFct.cpp
+++ b/tests/src/testCSAdapterEqFct.cpp
@@ -21,9 +21,10 @@ using namespace ChimeraTK;
 class TestableCSAdapterEqFct: public CSAdapterEqFct{
 public:
   TestableCSAdapterEqFct(int fctCode,
-    boost::shared_ptr<ControlSystemPVManager> controlSystemPVManager,
-    std::string fctName):
-    CSAdapterEqFct(fctCode, controlSystemPVManager, boost::make_shared<DoocsUpdater>(), fctName){
+                         boost::shared_ptr<ControlSystemPVManager> controlSystemPVManager,
+                         boost::shared_ptr<DoocsUpdater> const & updater,
+                         std::string fctName):
+    CSAdapterEqFct(fctCode, controlSystemPVManager, updater, fctName){
   }
   std::vector< boost::shared_ptr<D_fct> > & getDoocsProperties(){
     return doocsProperties_;
@@ -50,7 +51,8 @@ BOOST_AUTO_TEST_CASE( testCSAdapterEqFct ) {
   auto csManager = doocsAdapter.getControlSystemPVManager();
   VariableMapper::getInstance().directImport( getAllVariableNames(csManager ) );  
   // after that create the EqFct
-  TestableCSAdapterEqFct eqFct(42, csManager, "test");
+  auto updater = boost::make_shared<DoocsUpdater>();
+  TestableCSAdapterEqFct eqFct(42, csManager, updater, "test");
 
   // Test that the right number of properties is created.
   // Currently the vector is still empty.
@@ -86,12 +88,12 @@ BOOST_AUTO_TEST_CASE( testCSAdapterEqFct ) {
   // and the other direction
   businessLogic.fromDeviceInt->accessData(0) = 12;
   businessLogic.fromDeviceInt->write();
-  eqFct.update();
+  updater->update();
   BOOST_CHECK_EQUAL( doocsProperties["FROM_DEVICE.INT "]->value(), 12);
 
   businessLogic.fromDeviceInt->accessData(0) = 15;
   businessLogic.fromDeviceInt->write();
-  eqFct.update();
+  updater->update();
   BOOST_CHECK_EQUAL( doocsProperties["FROM_DEVICE.INT "]->value(), 15);
 }
 
@@ -110,9 +112,10 @@ BOOST_AUTO_TEST_CASE( testWithMapping ) {
 
   VariableMapper::getInstance().prepareOutput( "EqFctTest.xml", getAllVariableNames(csManager ) );
 
-// in the mapping two locations are created
-  TestableCSAdapterEqFct toDeviceEqFct(42, csManager, "test.TO_DEVICE");
-  TestableCSAdapterEqFct fromDeviceEqFct(42, csManager, "test.FROM_DEVICE");
+  // in the mapping two locations are created
+  auto updater = boost::make_shared<DoocsUpdater>();
+  TestableCSAdapterEqFct toDeviceEqFct(42, csManager, updater, "test.TO_DEVICE");
+  TestableCSAdapterEqFct fromDeviceEqFct(42, csManager, updater, "test.FROM_DEVICE");
 
   BOOST_REQUIRE( toDeviceEqFct.getDoocsProperties().size() == 1 );
   BOOST_REQUIRE( fromDeviceEqFct.getDoocsProperties().size() == 1 );
-- 
GitLab