Example #1
0
inline void setState(qi::Atomic<int>& state, TaskState from, TaskState to, TaskState from2, TaskState to2)
{
  for (unsigned i=0; i<1000; ++i)
    if (state.setIfEquals(from, to) || state.setIfEquals(from2, to2))
      return;
  while (true)
  {
    for (unsigned i=0; i<1000; ++i)
    {
      if (state.setIfEquals(from, to) || state.setIfEquals(from2, to2))
        return;
      qi::os::msleep(1); // TODO: 1ms is probably too long
    }
    qiLogWarning() << "PeriodicTask is stuck " << from << ' ' << to << ' '  << from2 << ' ' << to2 << ' '<< *state;
  }
}
Example #2
0
 void PeriodicTaskPrivate::_reschedule(qi::int64_t delay)
 {
   qiLogDebug() << _name <<" rescheduling in " << delay;
   _task = getEventLoop()->async(boost::bind(&PeriodicTaskPrivate::_wrap, shared_from_this()), delay);
   if (!_state.setIfEquals(Task_Rescheduling, Task_Scheduled))
     qiLogError() << "PeriodicTask forbidden state change while rescheduling " << *_state;
 }
Example #3
0
  void PeriodicTaskPrivate::_trigger(qi::Future<void> future)
  {
    // if future was not canceled, the task already ran, don't retrigger
    if (!future.isCanceled())
      return;

    // else, start the task now if we are still triggering
    if (_state.setIfEquals(Task_Triggering, Task_Rescheduling))
      _reschedule(0);
  }
Example #4
0
  void Application::stop()
  {

    static qi::Atomic<bool> atStopHandlerCall = false;
    if (atStopHandlerCall.setIfEquals(false, true))
    {
      FunctionList& fl = lazyGet(globalAtStop);
      qiLogDebug() << "Executing " << fl.size() << " atStop handlers";
      for (FunctionList::iterator i = fl.begin(); i!= fl.end(); ++i)
      {
        try
        {
          (*i)();
        }
        catch (std::exception& e)
        {
          qiLogError() << "Application atStop callback throw the following error: " << e.what();
        }
      }
      globalIsStop = true;
      globalCond.notify_all();
    }
  }
Example #5
0
  void PeriodicTaskPrivate::_wrap()
  {
    if (*_state == Task_Stopped)
      qiLogError()  << "PeriodicTask inconsistency: stopped from callback";
    /* To avoid being stuck because of unhandled transition, the rule is
    * that any other thread playing with our state can only do so
    * to stop us, and must eventualy reach the Stopping state
    */
    if (_state.setIfEquals(Task_Stopping, Task_Stopped))
      return;
    /* reschedule() needs to call async() before reseting state from rescheduling
    *  to scheduled, to protect the _task object. So we might still be
    * in rescheduling state here.
    */
    while (*_state == Task_Rescheduling)
      boost::this_thread::yield();
    // order matters! check scheduled state first as the state cannot change
    // from triggering to scheduled but can change in the other way
    if (!_state.setIfEquals(Task_Scheduled, Task_Running) &&
        !_state.setIfEquals(Task_Triggering, Task_Running))
    {
      setState(_state, Task_Stopping, Task_Stopped);
      return;
    }
    bool shouldAbort = false;
    qi::int64_t wall = 0, now=0, delta=0;
    qi::int64_t usr, sys;
    bool compensate = _compensateCallTime; // we don't want that bool to change in the middle
    try
    {
      wall = qi::os::ustime();
      std::pair<qi::int64_t, qi::int64_t> cpu = qi::os::cputime();
      _tid = os::gettid();
      _callback();
      _tid = invalidThreadId;
      now = qi::os::ustime();
      wall = now - wall;
      std::pair<qi::int64_t, qi::int64_t> cpu2 = qi::os::cputime();
      usr = cpu2.first - cpu.first;
      sys = cpu2.second - cpu.second;
      if (compensate)
        delta = wall;
    }
    catch (const std::exception& e)
    {
      qiLogInfo() << "Exception in task " << _name << ": " << e.what();
      shouldAbort = true;
    }
    catch(...)
    {
      qiLogInfo() << "Unknown exception in task callback.";
      shouldAbort = true;
    }
    if (shouldAbort)
    {
      setState(_state, Task_Stopping, Task_Stopped,
                       Task_Running, Task_Stopped);
      return;
    }
    else
    {
      _callStats.push((float)wall / 1e6f, (float)usr / 1e6f, (float)sys / 1e6f);

      if (now - _statsDisplayTime >= 20000000)
      {
        float secTime = float(now - _statsDisplayTime) / 1e6f;
        _statsDisplayTime = now;
        unsigned int count = _callStats.count();
        std::string catName = "stats." + _name;
        qiLogVerbose(catName.c_str())
          << (_callStats.user().cumulatedValue() * 100.0 / secTime)
          << "%  "
          << count
          << "  " << _callStats.wall().asString(count)
          << "  " << _callStats.user().asString(count)
          << "  " << _callStats.system().asString(count)
          ;
        _callStats.reset();
      }

      if (!_state.setIfEquals(Task_Running, Task_Rescheduling))
      { // If we are not in running state anymore, someone switched us
        // to stopping
        setState(_state, Task_Stopping, Task_Stopped);
        return;
      }
      _reschedule(std::max((qi::int64_t)0, _usPeriod - delta));
    }
  }