diff --git a/drivers/Timer.h b/drivers/Timer.h index cf39871..bff06b7 100644 --- a/drivers/Timer.h +++ b/drivers/Timer.h @@ -22,6 +22,9 @@ #include "platform/NonCopyable.h" namespace mbed { + +class CriticalSectionLock; + /** * \defgroup drivers_Timer Timer class * \ingroup drivers-public-api-ticker @@ -51,7 +54,7 @@ * } * @endcode */ -class TimerBase : private NonCopyable { +class TimerBase { public: /** Start the timer @@ -109,13 +112,24 @@ protected: TimerBase(const ticker_data_t *data); TimerBase(const ticker_data_t *data, bool lock_deepsleep); + TimerBase(const TimerBase &t); + TimerBase(TimerBase &&t); ~TimerBase(); + + const TimerBase &operator=(const TimerBase &) = delete; + std::chrono::microseconds slicetime() const; TickerDataClock::time_point _start{}; // the start time of the latest slice std::chrono::microseconds _time{}; // any accumulated time from previous slices TickerDataClock _ticker_data; bool _lock_deepsleep; // flag that indicates if deep sleep should be disabled bool _running = false; // whether the timer is running + +private: + // Copy storage while a lock is held + TimerBase(const TimerBase &t, const CriticalSectionLock &) : TimerBase(t, false) {} + // Copy storage only - used by delegating constructors + TimerBase(const TimerBase &t, bool) : _start(t._start), _time(t._time), _ticker_data(t._ticker_data), _lock_deepsleep(t._lock_deepsleep), _running(t._running) {} }; #endif diff --git a/drivers/source/Timer.cpp b/drivers/source/Timer.cpp index 27ea32d..a603b85 100644 --- a/drivers/source/Timer.cpp +++ b/drivers/source/Timer.cpp @@ -38,6 +38,26 @@ reset(); } +// This creates a temporary CriticalSectionLock while we delegate to the +// constructor that does the copy, thus holding critical section during the copy, +// ensuring locking on the source. Then continue our own initialization +// outside the critical section +TimerBase::TimerBase(const TimerBase &t) : TimerBase(t, CriticalSectionLock{}) +{ + // If running, new copy needs an extra lock + if (_running && _lock_deepsleep) { + sleep_manager_lock_deep_sleep(); + } +} + +// Unlike copy constructor, no need for lock on move - we must be only person +// accessing source. +TimerBase::TimerBase(TimerBase &&t) : TimerBase(t, false) +{ + // Original is marked as no longer running - we adopt any lock it had + t._running = false; +} + TimerBase::~TimerBase() { if (_running) {