Skip to content

Commit 802c897

Browse files
authored
Merge pull request #12905 from kjbracey-arm/timer_tweaks
Timer: minor revisions
2 parents 920133e + e3ef38d commit 802c897

File tree

3 files changed

+123
-1
lines changed

3 files changed

+123
-1
lines changed

TESTS/mbed_drivers/timer/main.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,91 @@ void test_timer_time_measurement()
660660
TEST_ASSERT_DURATION_WITHIN(delta(wait_val), wait_val, p_timer->elapsed_time());
661661
}
662662

663+
/* This test verifies if a timer can be successfully copied.
664+
*
665+
* For this test Timer which uses os ticker
666+
* must be used.
667+
*
668+
* Given timer is created
669+
* Delay occurs
670+
* Timer is copied
671+
* Timer is stopped
672+
* Timer is copied again
673+
* Delay occurs
674+
* Then original timer and second copy should have measured first delay.
675+
* First copy should have measured both delays.
676+
*/
677+
template<int wait_val_us>
678+
void test_timer_copying()
679+
{
680+
microseconds wait_val(wait_val_us);
681+
const Timer &original = *static_cast<Timer *>(p_timer);
682+
683+
/* Start the timer. */
684+
p_timer->start();
685+
686+
/* Wait <wait_val_us> us. */
687+
busy_wait(wait_val);
688+
689+
/* Copy the timer */
690+
Timer running_copy{original};
691+
692+
/* Stop the original timer. */
693+
p_timer->stop();
694+
695+
/* Copy the timer */
696+
Timer stopped_copy{original};
697+
698+
/* Wait <wait_val_us> us. */
699+
busy_wait(wait_val);
700+
701+
/* Stop the running copy. */
702+
running_copy.stop();
703+
704+
/* Check results. */
705+
TEST_ASSERT_DURATION_WITHIN(delta(wait_val), wait_val, p_timer->elapsed_time());
706+
TEST_ASSERT_EQUAL_DURATION(p_timer->elapsed_time(), stopped_copy.elapsed_time());
707+
TEST_ASSERT_DURATION_WITHIN(delta(wait_val * 2), wait_val * 2, running_copy.elapsed_time());
708+
}
709+
710+
/* This test verifies if a timer can be successfully moved.
711+
*
712+
* For this test Timer which uses os ticker
713+
* must be used.
714+
*
715+
* Given timer is created
716+
* Delay occurs
717+
* Timer is moved
718+
* Delay occurs
719+
* Then moved timer should have measured both delays.
720+
*/
721+
template<int wait_val_us>
722+
void test_timer_moving()
723+
{
724+
microseconds wait_val(wait_val_us);
725+
Timer &original = *static_cast<Timer *>(p_timer);
726+
727+
/* Start the timer. */
728+
p_timer->start();
729+
730+
/* Wait <wait_val_us> us. */
731+
busy_wait(wait_val);
732+
733+
/* Move the timer */
734+
Timer moved_timer{std::move(original)};
735+
736+
/* No longer valid to do anything with the original, other than destroy it (happens in cleanup) */
737+
738+
/* Wait <wait_val_us> us. */
739+
busy_wait(wait_val);
740+
741+
/* Stop the moved timer . */
742+
moved_timer.stop();
743+
744+
/* Check results. */
745+
TEST_ASSERT_DURATION_WITHIN(delta(wait_val * 2), wait_val * 2, moved_timer.elapsed_time());
746+
}
747+
663748
utest::v1::status_t test_setup(const size_t number_of_cases)
664749
{
665750
GREENTEA_SETUP(15, "default_auto");
@@ -683,6 +768,9 @@ Case cases[] = {
683768
Case("Test: Timer - time measurement 10 ms.", timer_os_ticker_setup_handler, test_timer_time_measurement<10000>, timer_os_ticker_cleanup_handler),
684769
Case("Test: Timer - time measurement 100 ms.", timer_os_ticker_setup_handler, test_timer_time_measurement<100000>, timer_os_ticker_cleanup_handler),
685770
Case("Test: Timer - time measurement 1 s.", timer_os_ticker_setup_handler, test_timer_time_measurement<1000000>, timer_os_ticker_cleanup_handler),
771+
772+
Case("Test: Timer - copying 5 ms.", timer_os_ticker_setup_handler, test_timer_copying<5000>, timer_os_ticker_cleanup_handler),
773+
Case("Test: Timer - moving 5 ms.", timer_os_ticker_setup_handler, test_timer_moving<5000>, timer_os_ticker_cleanup_handler),
686774
};
687775

688776
Specification specification(test_setup, cases);

drivers/Timer.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
#include "platform/NonCopyable.h"
2323

2424
namespace mbed {
25+
26+
class CriticalSectionLock;
27+
2528
/**
2629
* \defgroup drivers_Timer Timer class
2730
* \ingroup drivers-public-api-ticker
@@ -51,7 +54,7 @@ namespace mbed {
5154
* }
5255
* @endcode
5356
*/
54-
class TimerBase : private NonCopyable<TimerBase> {
57+
class TimerBase {
5558

5659
public:
5760
/** Start the timer
@@ -109,13 +112,24 @@ class TimerBase : private NonCopyable<TimerBase> {
109112
protected:
110113
TimerBase(const ticker_data_t *data);
111114
TimerBase(const ticker_data_t *data, bool lock_deepsleep);
115+
TimerBase(const TimerBase &t);
116+
TimerBase(TimerBase &&t);
112117
~TimerBase();
118+
119+
const TimerBase &operator=(const TimerBase &) = delete;
120+
113121
std::chrono::microseconds slicetime() const;
114122
TickerDataClock::time_point _start{}; // the start time of the latest slice
115123
std::chrono::microseconds _time{}; // any accumulated time from previous slices
116124
TickerDataClock _ticker_data;
117125
bool _lock_deepsleep; // flag that indicates if deep sleep should be disabled
118126
bool _running = false; // whether the timer is running
127+
128+
private:
129+
// Copy storage while a lock is held
130+
TimerBase(const TimerBase &t, const CriticalSectionLock &) : TimerBase(t, false) {}
131+
// Copy storage only - used by delegating constructors
132+
TimerBase(const TimerBase &t, bool) : _start(t._start), _time(t._time), _ticker_data(t._ticker_data), _lock_deepsleep(t._lock_deepsleep), _running(t._running) {}
119133
};
120134
#endif
121135

drivers/source/Timer.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,26 @@ TimerBase::TimerBase(const ticker_data_t *data, bool lock_deepsleep) : _ticker_d
3838
reset();
3939
}
4040

41+
// This creates a temporary CriticalSectionLock while we delegate to the
42+
// constructor that does the copy, thus holding critical section during the copy,
43+
// ensuring locking on the source. Then continue our own initialization
44+
// outside the critical section
45+
TimerBase::TimerBase(const TimerBase &t) : TimerBase(t, CriticalSectionLock{})
46+
{
47+
// If running, new copy needs an extra lock
48+
if (_running && _lock_deepsleep) {
49+
sleep_manager_lock_deep_sleep();
50+
}
51+
}
52+
53+
// Unlike copy constructor, no need for lock on move - we must be only person
54+
// accessing source.
55+
TimerBase::TimerBase(TimerBase &&t) : TimerBase(t, false)
56+
{
57+
// Original is marked as no longer running - we adopt any lock it had
58+
t._running = false;
59+
}
60+
4161
TimerBase::~TimerBase()
4262
{
4363
if (_running) {

0 commit comments

Comments
 (0)