1 //******************************************************************
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21 #include "ExpiryTimerImpl.h"
23 #include "RCSException.h"
32 constexpr ExpiryTimerImpl::Id INVALID_ID{ 0U };
35 ExpiryTimerImpl::ExpiryTimerImpl() :
37 m_thread{ std::thread(&ExpiryTimerImpl::run, this) },
41 m_mt{ std::random_device{ }() },
46 ExpiryTimerImpl::~ExpiryTimerImpl()
49 std::lock_guard< std::mutex > lock{ m_mutex };
57 ExpiryTimerImpl* ExpiryTimerImpl::getInstance()
59 static ExpiryTimerImpl instance;
63 std::shared_ptr< TimerTask > ExpiryTimerImpl::post(DelayInMillis delay, Callback cb)
67 throw InvalidParameterException{ "delay can't be negative." };
72 throw InvalidParameterException{ "callback is empty." };
75 return addTask(convertToTime(Milliseconds{ delay }), std::move(cb), generateId());
78 bool ExpiryTimerImpl::cancel(Id id)
80 if (id == INVALID_ID) return false;
82 std::lock_guard< std::mutex > lock{ m_mutex };
84 for(auto it = m_tasks.begin(); it != m_tasks.end(); ++it)
86 if(it->second->getId() == id)
95 size_t ExpiryTimerImpl::cancelAll(
96 const std::unordered_set< std::shared_ptr<TimerTask > >& tasks)
98 std::lock_guard< std::mutex > lock{ m_mutex };
101 for(auto it = m_tasks.begin(); it != m_tasks.end();)
103 if(tasks.count(it->second))
105 it = m_tasks.erase(it);
116 ExpiryTimerImpl::Milliseconds ExpiryTimerImpl::convertToTime(Milliseconds delay)
118 const auto now = std::chrono::system_clock::now();
119 return std::chrono::duration_cast< Milliseconds >(now.time_since_epoch()) + delay;
122 std::shared_ptr< TimerTask > ExpiryTimerImpl::addTask(
123 Milliseconds delay, Callback cb, Id id)
125 std::lock_guard< std::mutex > lock{ m_mutex };
127 auto newTask = std::make_shared< TimerTask >(id, std::move(cb));
128 m_tasks.insert({ delay, newTask });
134 bool ExpiryTimerImpl::containsId(Id id) const
136 for (const auto& info : m_tasks)
138 if (info.second->getId() == id) return true;
143 ExpiryTimerImpl::Id ExpiryTimerImpl::generateId()
145 Id newId = m_dist(m_mt);
147 std::lock_guard< std::mutex > lock{ m_mutex };
149 while (newId == INVALID_ID || containsId(newId))
151 newId = m_dist(m_mt);
156 void ExpiryTimerImpl::executeExpired()
158 if (m_tasks.empty()) return;
160 auto now = std::chrono::system_clock::now().time_since_epoch();
162 auto it = m_tasks.begin();
163 for (; it != m_tasks.end() && it->first <= now; ++it)
165 it->second->execute();
168 m_tasks.erase(m_tasks.begin(), it);
171 ExpiryTimerImpl::Milliseconds ExpiryTimerImpl::remainingTimeForNext() const
173 const Milliseconds& expiredTime = m_tasks.begin()->first;
175 return std::chrono::duration_cast< Milliseconds >(expiredTime -
176 std::chrono::system_clock::now().time_since_epoch()) + Milliseconds{ 1 };
179 void ExpiryTimerImpl::run()
181 auto hasTaskOrStop = [this](){ return !m_tasks.empty() || m_stop; };
183 std::unique_lock< std::mutex > lock{ m_mutex };
187 m_cond.wait(lock, hasTaskOrStop);
191 m_cond.wait_for(lock, remainingTimeForNext());
198 TimerTask::TimerTask(ExpiryTimerImpl::Id id, ExpiryTimerImpl::Callback cb) :
200 m_callback{ std::move(cb) }
204 void TimerTask::execute()
206 if (isExecuted()) return;
208 ExpiryTimerImpl::Id id { m_id };
211 std::thread(std::move(m_callback), id).detach();
213 m_callback = ExpiryTimerImpl::Callback{ };
216 bool TimerTask::isExecuted() const
218 return m_id == INVALID_ID;
221 ExpiryTimerImpl::Id TimerTask::getId() const