Fixed remove for timer_active_list

Moved time to nex notifications to inside the lock regions
Finished unit tests
This commit is contained in:
John Wellbelove 2026-10-26 15:50:35 +00:00
parent f1d188e60c
commit 2aa0c4edb3
7 changed files with 605 additions and 609 deletions

View File

@ -131,17 +131,10 @@ namespace etl
result = true;
}
// Get the next timer that is due to expire.
etl::timer_node* next_timer = active_list.first();
notify_about_timer_change(notify, active_list.first());
lock_policy.unlock();
if (notify)
{
// The next timer has changed, so notify the user.
time_to_next_notification.call_if(next_timer->get_delta());
}
return result;
}
@ -214,7 +207,7 @@ namespace etl
if (timer->get_mode() == etl::timer::mode::Repeating)
{
// Reinsert the timer.
timer->delta = timer->get_period();
timer->delta = timer->get_interval();
active_list.insert(timer);
}
@ -224,7 +217,7 @@ namespace etl
has_active = !active_list.empty();
notify = has_active;
notify = true;
}
if (has_active)
@ -233,19 +226,12 @@ namespace etl
active_list.first()->delta -= count;
}
}
}
// Get the next timer that is due to expire.
etl::timer_node* next_timer = active_list.first();
notify_about_timer_change(notify, active_list.first());
lock_policy.unlock();
was_processed = true;
was_processed = true;
if (notify)
{
// The next timer has changed, so notify the user.
time_to_next_notification.call_if(next_timer->get_delta());
lock_policy.unlock();
}
// Invoke all of the expired timers.
@ -266,8 +252,9 @@ namespace etl
if (timer_.is_registered_with(this))
{
// Must not be active and must have a valid period.
if (!timer_.is_active() && (timer_.get_period() != etl::timer::interval::No_Active_Interval))
// Must not be active, must have a valid interval, and must have a valid mode.
if (!timer_.is_active() && (timer_.get_interval() != etl::timer::interval::No_Active_Interval)
&& (timer_.get_mode() != etl::timer::mode::No_Mode_Set))
{
active_list.insert(timer_);
is_started = true;
@ -285,11 +272,7 @@ namespace etl
timer_.invoke();
}
if (notify)
{
// The next timer has changed, so notify the user.
time_to_next_notification.call_if(timer_.get_delta());
}
notify_about_timer_change(notify, &timer_);
return is_started;
}
@ -300,34 +283,27 @@ namespace etl
bool stop(etl::timer_node& timer_) ETL_NOEXCEPT
{
bool is_stopped = false;
bool notify = false;
lock_policy.lock();
if (timer_.is_active())
{
notify = (active_list.first() == &timer_);
stop_timer(timer_);
is_stopped = true;
}
// Get the next timer that is due to expire.
etl::timer_node* next_timer = active_list.first();
notify = true;
// The next timer has changed, so notify the user.
time_to_next_notification.call_if(active_list.first()->get_delta());
lock_policy.unlock();
// The next timer has changed, so notify the user.
time_to_next_notification.call_if(next_timer->get_delta());
return is_stopped;
}
//*******************************************
/// Sets a timer's period.
/// Sets a timer's interval.
//*******************************************
bool set_period(etl::timer_node& timer_, uint32_t period_) ETL_NOEXCEPT
bool set_interval(etl::timer_node& timer_, uint32_t interval_) ETL_NOEXCEPT
{
bool result = false;
@ -343,21 +319,14 @@ namespace etl
stop_timer(timer_);
}
timer_.set_period(period_);
timer_.set_interval(interval_);
result = true;
}
// Get the next timer that is due to expire.
etl::timer_node* next_timer = active_list.first();
notify_about_timer_change(notify, active_list.first());
lock_policy.unlock();
if (notify)
{
// The next timer has changed, so notify the user.
time_to_next_notification.call_if(next_timer->get_delta());
}
return result;
}
@ -383,17 +352,40 @@ namespace etl
result = true;
}
// Get the next timer that is due to expire.
etl::timer_node* next_timer = active_list.first();
notify_about_timer_change(notify, active_list.first());
lock_policy.unlock();
if (notify)
return result;
}
//*******************************************
/// Sets a timer's interval.
//*******************************************
bool set_config(etl::timer_node& timer_, const etl::timer_config& config_) ETL_NOEXCEPT
{
bool result = false;
lock_policy.lock();
bool notify = false;
if (timer_.is_registered_with(this))
{
// The next timer has changed, so notify the user.
time_to_next_notification.call_if(next_timer->get_delta());
if (timer_.is_active())
{
notify = (active_list.first() == &timer_);
stop_timer(timer_);
}
timer_.set_config(config_);
result = true;
}
notify_about_timer_change(notify, active_list.first());
lock_policy.unlock();
return result;
}
@ -475,8 +467,21 @@ namespace etl
private:
//*******************************************
/// Notifies the user of the next timer that is due to expire.
//*******************************************
void notify_about_timer_change(bool notify_, etl::timer_node* timer_) ETL_NOEXCEPT
{
if (notify_ && time_to_next_notification.is_valid())
{
// The next timer has changed, so notify the user.
time_to_next_notification(timer_->get_delta());
}
}
//*******************************************
/// Gets the next available timer id.
/// Searches the list of registered timers for the next available id.
//*******************************************
etl::timer::id::type get_next_id() ETL_NOEXCEPT
{
@ -484,23 +489,12 @@ namespace etl
etl::timer_node* timer = register_list.first();
while (timer != register_list.end())
while ((timer != register_list.end()) && (timer->get_id() == next_id))
{
if (timer->get_id() == next_id)
{
// Already in use, so increment next_id and continue checking.
++next_id;
}
else if (timer->get_id() > next_id)
{
// Found a gap in the IDs, so return the next_id.
return next_id;
}
++next_id;
timer = register_list.next(timer);
}
// We never found a gap, so return the next available ID.
return next_id;
}

View File

@ -162,7 +162,7 @@ namespace etl
// Clear the id and next pointer of the removed timer.
current->set_id(etl::timer::id::No_Timer);
current->registered_next = end();
current->registered_next = etl::timer_node::unlinked();
// We are no longer the owner of this timer_node.
current->set_owner(ETL_NULLPTR);
@ -214,9 +214,9 @@ namespace etl
while (head != end())
{
head = timer->registered_next;
timer->registered_next = etl::timer_node::unlinked();
timer = head;
head = timer->registered_next;
timer->clear();
timer = head;
}
tail = end();
@ -377,7 +377,7 @@ namespace etl
}
// Clear the next pointer of the removed timer.
current->active_next = end();
timer_->active_next = etl::timer_node::unlinked();
return next;
}

View File

@ -58,14 +58,15 @@ namespace etl
{
enum
{
SINGLE_SHOT = false,
REPEATING = true,
SINGLE_SHOT = 0, // Deprecated
REPEATING = 1, // Deprecated
Single_Shot = false,
Repeating = true
Single_Shot = 0,
Repeating = 1,
No_Mode_Set = 2
};
typedef bool type;
typedef uint_least8_t type;
};
// Timer start status.
@ -115,6 +116,12 @@ namespace etl
typedef uint32_t type;
};
// Timer owner.
struct owner
{
static ETL_CONSTANT void* No_Owner = ETL_NULLPTR;
};
};
} // namespace etl

View File

@ -77,19 +77,19 @@ namespace etl
//*******************************************
/// Constructor.
//*******************************************
ETL_CONSTEXPR timer_config(uint32_t period_, etl::timer::mode::type repeating_) ETL_NOEXCEPT
: period(period_)
ETL_CONSTEXPR timer_config(uint32_t interval_, etl::timer::mode::type repeating_) ETL_NOEXCEPT
: interval(interval_)
, mode(repeating_)
, id(etl::timer::id::No_Timer)
{
}
//*******************************************
/// Returns the period of the timer.
/// Returns the interval of the timer.
//*******************************************
ETL_CONSTEXPR uint32_t get_period() const ETL_NOEXCEPT
ETL_CONSTEXPR uint32_t get_interval() const ETL_NOEXCEPT
{
return period;
return interval;
}
//*******************************************
@ -113,16 +113,16 @@ namespace etl
//*******************************************
ETL_CONSTEXPR14 void clear() ETL_NOEXCEPT
{
period = etl::timer::state::Inactive;
mode = etl::timer::mode::Repeating;
id = etl::timer::id::No_Timer;
interval = etl::timer::interval::No_Active_Interval;
mode = etl::timer::mode::No_Mode_Set;
id = etl::timer::id::No_Timer;
}
private:
uint32_t period; ///< The period of the timer.
etl::timer::mode::type mode; ///< Whether the timer is repeating or single-shot.
etl::timer::id::type id; ///< The id of the timer.
uint32_t interval; ///< The interval of the timer.
etl::timer::mode::type mode; ///< Whether the timer is repeating or single-shot.
etl::timer::id::type id; ///< The id of the timer.
};
class sentinal_node;
@ -165,9 +165,9 @@ namespace etl
: registered_next(unlinked())
, active_next(unlinked())
, expired_next(unlinked())
, owner(ETL_NULLPTR)
, owner(etl::timer::owner::No_Owner)
, config(config_)
, delta(config_.get_period())
, delta(config_.get_interval())
{
}
@ -178,9 +178,9 @@ namespace etl
: registered_next(unlinked())
, active_next(unlinked())
, expired_next(unlinked())
, owner(ETL_NULLPTR)
, owner(etl::timer::owner::No_Owner)
, config(node_.config)
, delta(node_.config.get_period())
, delta(node_.config.get_interval())
{
}
@ -201,11 +201,11 @@ namespace etl
}
//*******************************************
/// Returns the period of the timer.
/// Returns the interval of the timer.
//*******************************************
ETL_CONSTEXPR uint32_t get_period() const ETL_NOEXCEPT
ETL_CONSTEXPR uint32_t get_interval() const ETL_NOEXCEPT
{
return config.get_period();
return config.get_interval();
}
//*******************************************
@ -242,11 +242,20 @@ namespace etl
private:
//*******************************************
/// Sets the period of the timer.
/// Returns the configuration of the timer.
//*******************************************
void set_period(uint32_t period_) ETL_NOEXCEPT
void set_config(const timer_config& config_) ETL_NOEXCEPT
{
config.period = period_;
set_interval(config_.get_interval());
set_mode(config_.get_mode());
}
//*******************************************
/// Sets the interval of the timer.
//*******************************************
void set_interval(uint32_t interval_) ETL_NOEXCEPT
{
config.interval = interval_;
}
//*******************************************
@ -282,20 +291,20 @@ namespace etl
}
//*******************************************
/// Clear the next pointers.
/// Clear the node.
//*******************************************
void clear() ETL_NOEXCEPT
{
config.clear();
registered_next = unlinked();
active_next = unlinked();
expired_next = unlinked();
owner = ETL_NULLPTR;
delta = config.get_period();
owner = etl::timer::owner::No_Owner;
delta = config.get_interval();
}
//*******************************************
/// Returns true if the timer is registered to this owner.
/// A timer cannot be registered to more than one owner.
/// Returns true if the timer is registered to the specified owner.
//*******************************************
bool is_registered_with(void* owner_) const ETL_NOEXCEPT
{
@ -303,8 +312,7 @@ namespace etl
}
//*******************************************
/// Returns true if the timer is registered to this owner.
/// A timer cannot be registered to more than one owner.
/// Returns true if the timer is registered to an owner.
//*******************************************
bool is_registered() const ETL_NOEXCEPT
{

File diff suppressed because it is too large Load Diff

View File

@ -194,7 +194,7 @@ namespace
etl::timer_node* timer = active_list.first();
// The timers should be in the order of their periods.
// The timers should be in the order of their intervals.
CHECK_EQUAL(&timer2, timer);
timer = active_list.next(timer);
CHECK_EQUAL(&timer3, timer);
@ -208,23 +208,23 @@ namespace
CHECK_EQUAL(active_list.end(), timer);
// Check the deltas are correct.
// The period order of the timers in the list is timer2, timer3, timer5, timer1, timer4.
// timer 5 has the same period as timer 3, so it should be after timer 3 in the list.
CHECK_EQUAL(timer2.get_period(), timer2.get_delta());
CHECK_EQUAL(timer3.get_period() - timer2.get_period(), timer3.get_delta());
CHECK_EQUAL(timer1.get_period() - timer3.get_period(), timer1.get_delta());
CHECK_EQUAL(timer4.get_period() - timer1.get_period(), timer4.get_delta());
CHECK_EQUAL(timer5.get_period() - timer3.get_period(), timer5.get_delta());
// The interval order of the timers in the list is timer2, timer3, timer5, timer1, timer4.
// timer 5 has the same interval as timer 3, so it should be after timer 3 in the list.
CHECK_EQUAL(timer2.get_interval(), timer2.get_delta());
CHECK_EQUAL(timer3.get_interval() - timer2.get_interval(), timer3.get_delta());
CHECK_EQUAL(timer1.get_interval() - timer3.get_interval(), timer1.get_delta());
CHECK_EQUAL(timer4.get_interval() - timer1.get_interval(), timer4.get_delta());
CHECK_EQUAL(timer5.get_interval() - timer3.get_interval(), timer5.get_delta());
// Remove timer3 from the list.
active_list.remove(&timer3);
// Check the deltas are still correct.
// The period order of the timers in the list is now timer2, timer5, timer1, timer4.
CHECK_EQUAL(timer2.get_period(), timer2.get_delta());
CHECK_EQUAL(timer5.get_period() - timer2.get_period(), timer5.get_delta());
CHECK_EQUAL(timer1.get_period() - timer5.get_period(), timer1.get_delta());
CHECK_EQUAL(timer4.get_period() - timer1.get_period(), timer4.get_delta());
// The interval order of the timers in the list is now timer2, timer5, timer1, timer4.
CHECK_EQUAL(timer2.get_interval(), timer2.get_delta());
CHECK_EQUAL(timer5.get_interval() - timer2.get_interval(), timer5.get_delta());
CHECK_EQUAL(timer1.get_interval() - timer5.get_interval(), timer1.get_delta());
CHECK_EQUAL(timer4.get_interval() - timer1.get_interval(), timer4.get_delta());
// Search the list to ensure the other timers are still present.
bool timer1_found = false;

View File

@ -38,24 +38,24 @@ namespace
TEST(test_timer_config)
{
constexpr etl::timer_config config1(100U, etl::timer::mode::Repeating);
CHECK_EQUAL(100U, config1.get_period());
CHECK_EQUAL(100U, config1.get_interval());
CHECK_EQUAL(etl::timer::mode::Repeating, config1.get_mode());
etl::timer_config config2(200U, etl::timer::mode::Single_Shot);
CHECK_EQUAL(200U, config2.get_period());
CHECK_EQUAL(200U, config2.get_interval());
CHECK_EQUAL(etl::timer::mode::Single_Shot, config2.get_mode());
etl::timer_config config3(config2);
CHECK_EQUAL(config2.get_period(), config3.get_period());
CHECK_EQUAL(config2.get_interval(), config3.get_interval());
CHECK_EQUAL(etl::timer::mode::Single_Shot, config2.get_mode());
etl::timer_config config4 = etl::timer_config(500U, etl::timer::mode::Repeating);
CHECK_EQUAL(500U, config4.get_period());
CHECK_EQUAL(500U, config4.get_interval());
CHECK_EQUAL(etl::timer::mode::Repeating, config4.get_mode());
config2.clear();
CHECK_EQUAL(etl::timer::state::Inactive, config2.get_period());
CHECK_EQUAL(etl::timer::mode::Repeating, config2.get_mode());
CHECK_EQUAL(etl::timer::interval::No_Active_Interval, config2.get_interval());
CHECK_EQUAL(etl::timer::mode::No_Mode_Set, config2.get_mode());
}
//*************************************************************************
@ -68,10 +68,10 @@ namespace
const etl::timer_config& config1_ref = node1.get_config();
CHECK_EQUAL(config1.get_period(), node1.get_config().get_period());
CHECK_EQUAL(config1.get_interval(), node1.get_config().get_interval());
CHECK_EQUAL(config1.get_mode(), node1.get_config().get_mode());
CHECK_EQUAL(node1.get_config().get_period(), node2.get_config().get_period());
CHECK_EQUAL(node1.get_config().get_interval(), node2.get_config().get_interval());
CHECK_EQUAL(node1.get_config().get_mode(), node2.get_config().get_mode());
}
}