2013-12-15 18:30:16 -05:00
|
|
|
/*----------------------------------------------------------------------------*/
|
2016-01-02 03:02:34 -08:00
|
|
|
/* Copyright (c) FIRST 2008-2016. All Rights Reserved. */
|
2013-12-15 18:30:16 -05:00
|
|
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
2016-01-02 03:02:34 -08:00
|
|
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
|
|
|
|
/* the project. */
|
2013-12-15 18:30:16 -05:00
|
|
|
/*----------------------------------------------------------------------------*/
|
2016-01-02 03:02:34 -08:00
|
|
|
|
2014-05-02 17:54:01 -04:00
|
|
|
#pragma once
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2015-12-29 10:58:11 -08:00
|
|
|
#include <atomic>
|
|
|
|
|
#include <functional>
|
2015-10-30 00:51:05 -07:00
|
|
|
#include <list>
|
2015-12-29 10:58:11 -08:00
|
|
|
#include <thread>
|
|
|
|
|
|
2013-12-15 18:30:16 -05:00
|
|
|
#include "ErrorBase.h"
|
2015-06-25 01:54:20 -07:00
|
|
|
#include "HAL/cpp/priority_mutex.h"
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2015-12-29 10:58:11 -08:00
|
|
|
typedef std::function<void()> TimerEventHandler;
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
class Notifier : public ErrorBase {
|
|
|
|
|
public:
|
2015-12-29 10:58:11 -08:00
|
|
|
explicit Notifier(TimerEventHandler handler);
|
|
|
|
|
|
|
|
|
|
template <typename Callable, typename Arg, typename... Args>
|
|
|
|
|
Notifier(Callable&& f, Arg&& arg, Args&&... args)
|
|
|
|
|
: Notifier(std::bind(std::forward<Callable>(f),
|
|
|
|
|
std::forward<Arg>(arg),
|
|
|
|
|
std::forward<Args>(args)...)) {}
|
2015-06-25 15:07:55 -04:00
|
|
|
virtual ~Notifier();
|
2015-07-21 01:23:34 -07:00
|
|
|
|
|
|
|
|
Notifier(const Notifier&) = delete;
|
|
|
|
|
Notifier& operator=(const Notifier&) = delete;
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
void StartSingle(double delay);
|
|
|
|
|
void StartPeriodic(double period);
|
|
|
|
|
void Stop();
|
2013-12-15 18:30:16 -05:00
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
private:
|
2015-10-30 00:51:05 -07:00
|
|
|
static std::list<Notifier*> timerQueue;
|
2015-06-25 01:54:20 -07:00
|
|
|
static priority_recursive_mutex queueMutex;
|
Prevent PID tests from hanging.
For the previous couple of months, the PID tests have been hanging.
The reason that the tests have been hanging lies with the Notifier,
not the PID controller. Basically, a deadlock was occuring during
Notifier destruction when the notifier destructor was called while
the notifier interrupt handler was being called. Because the low-level
interrupt manager waits for the interrupt handler to finish executing before
disabling itself, the notifier destructor would not exit until the
ProcessQueue function finished. However, at the same time, the handler
was attempting to lock the queueMutex before continuing; the Notifier
destructor had locked the queueMutex while wrapping things up, meaning
that the last run of the handler would not complete until the destructor
did, resulting in a deadlock.
In order to repair this, I reduced the scope of the lock on the queueMutex
in the destructor so that it only locks when absolutely necessary. This
should work now.
This bug was likely introduced over the summer when we updated to stl
mutexes and locks, which may have messed up the original lock structure.
This likely did not affect any teams, as it can only occur if you are actively
destroying every* Notifier object present and if the destructor happens to be
called while the handler is being run.
*Note: the component of the destructor causing issues only ran if the last
Notifier object is being destroyed.
Change-Id: I38ba4e60816a2a8d523e927c25378390a0755444
2015-11-24 16:35:36 -05:00
|
|
|
static priority_mutex halMutex;
|
2015-06-25 15:07:55 -04:00
|
|
|
static void *m_notifier;
|
Prevent PID tests from hanging.
For the previous couple of months, the PID tests have been hanging.
The reason that the tests have been hanging lies with the Notifier,
not the PID controller. Basically, a deadlock was occuring during
Notifier destruction when the notifier destructor was called while
the notifier interrupt handler was being called. Because the low-level
interrupt manager waits for the interrupt handler to finish executing before
disabling itself, the notifier destructor would not exit until the
ProcessQueue function finished. However, at the same time, the handler
was attempting to lock the queueMutex before continuing; the Notifier
destructor had locked the queueMutex while wrapping things up, meaning
that the last run of the handler would not complete until the destructor
did, resulting in a deadlock.
In order to repair this, I reduced the scope of the lock on the queueMutex
in the destructor so that it only locks when absolutely necessary. This
should work now.
This bug was likely introduced over the summer when we updated to stl
mutexes and locks, which may have messed up the original lock structure.
This likely did not affect any teams, as it can only occur if you are actively
destroying every* Notifier object present and if the destructor happens to be
called while the handler is being run.
*Note: the component of the destructor causing issues only ran if the last
Notifier object is being destroyed.
Change-Id: I38ba4e60816a2a8d523e927c25378390a0755444
2015-11-24 16:35:36 -05:00
|
|
|
static std::atomic<int> refcount;
|
2014-05-02 17:54:01 -04:00
|
|
|
|
2015-10-30 00:51:05 -07:00
|
|
|
// Process the timer queue on a timer event
|
2015-12-29 10:41:31 -08:00
|
|
|
static void ProcessQueue(uint32_t mask, void *params);
|
2015-10-30 00:51:05 -07:00
|
|
|
|
|
|
|
|
// Update the FPGA alarm since the queue has changed
|
2015-12-29 10:41:31 -08:00
|
|
|
static void UpdateAlarm();
|
2015-10-30 00:51:05 -07:00
|
|
|
|
|
|
|
|
// Insert the Notifier in the timer queue
|
2015-12-29 10:41:31 -08:00
|
|
|
void InsertInQueue(bool reschedule);
|
2015-10-30 00:51:05 -07:00
|
|
|
|
|
|
|
|
// Delete this Notifier from the timer queue
|
2015-12-29 10:41:31 -08:00
|
|
|
void DeleteFromQueue();
|
|
|
|
|
|
2015-10-30 00:51:05 -07:00
|
|
|
// Address of the handler
|
2015-12-29 10:41:31 -08:00
|
|
|
TimerEventHandler m_handler;
|
2015-10-30 00:51:05 -07:00
|
|
|
// The relative time (either periodic or single)
|
2015-12-29 10:41:31 -08:00
|
|
|
double m_period = 0;
|
2015-10-30 00:51:05 -07:00
|
|
|
// Absolute expiration time for the current event
|
2015-12-29 10:41:31 -08:00
|
|
|
double m_expirationTime = 0;
|
2015-10-30 00:51:05 -07:00
|
|
|
// True if this is a periodic event
|
2015-12-29 10:41:31 -08:00
|
|
|
bool m_periodic = false;
|
2015-10-30 00:51:05 -07:00
|
|
|
// Indicates if this entry is queued
|
2015-12-29 10:41:31 -08:00
|
|
|
bool m_queued = false;
|
2015-10-30 00:51:05 -07:00
|
|
|
// Held by interrupt manager task while handler call is in progress
|
2015-12-29 10:41:31 -08:00
|
|
|
priority_mutex m_handlerMutex;
|
2015-07-29 16:48:04 -04:00
|
|
|
static std::thread m_task;
|
|
|
|
|
static std::atomic<bool> m_stopped;
|
2015-06-25 15:07:55 -04:00
|
|
|
static void Run();
|
2013-12-15 18:30:16 -05:00
|
|
|
};
|