Bug fix: pidControlLoop may loop infinitely.

boost::basic_waitable_timer::cancel is a non-blocking function and only
sends cancellation to the pending operations. For other operations:
```
If the timer has already expired when cancel() is called, then the
handlers for asynchronous wait operations will:
* have already been invoked; or
* have been queued for invocation in the near future.
These handlers can no longer be cancelled, and therefore are passed an
error code that indicates the successful completion of the wait
operation.
```

In our case, if pidControlLoop() has been invoked or in the invoke
queue while the timer cancellation, it will ignore the cancal ec and
infinitely call the pidControlLoop() chain.

Thus an extra cancel variable is introduced to break the chain.

Signed-off-by: Hao Jiang <jianghao@google.com>
Change-Id: Ie4e53454ee326bdf612abb511990610a6b528300
diff --git a/main.cpp b/main.cpp
index c49c522..37418e6 100644
--- a/main.cpp
+++ b/main.cpp
@@ -81,11 +81,13 @@
     static SensorManager mgmr;
     static std::unordered_map<int64_t, std::shared_ptr<ZoneInterface>> zones;
     static std::vector<std::shared_ptr<boost::asio::steady_timer>> timers;
+    static bool isCanceling = false;
 
     for (const auto timer : timers)
     {
         timer->cancel();
     }
+    isCanceling = true;
     timers.clear();
 
     if (zones.size() > 0 && zones.begin()->second.use_count() > 1)
@@ -93,6 +95,7 @@
         throw std::runtime_error("wait for count back to 1");
     }
     zones.clear();
+    isCanceling = false;
 
     const std::string& path =
         (configPath.length() > 0) ? configPath : jsonConfigurationPath;
@@ -140,7 +143,7 @@
         std::shared_ptr<boost::asio::steady_timer> timer = timers.emplace_back(
             std::make_shared<boost::asio::steady_timer>(io));
         std::cerr << "pushing zone " << i.first << "\n";
-        pidControlLoop(i.second, timer);
+        pidControlLoop(i.second, timer, &isCanceling);
     }
 }