Fix structure in ExpiryTimer
[platform/upstream/iotivity.git] / service / resource-manipulation / src / common / expiryTimer / src / ExpiryTimerImpl.cpp
1 //******************************************************************
2 //
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
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
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
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.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include "ExpiryTimerImpl.h"
22
23 #include <unistd.h>
24 #include <cstdlib>
25 #include <utility>
26
27 ExpiryTimerImpl* ExpiryTimerImpl::s_instance = nullptr;
28 std::once_flag* ExpiryTimerImpl::s_flag = new std::once_flag;
29
30 ExpiryTimerImpl::ExpiryTimerImpl()
31 {
32     m_engine = std::default_random_engine(m_device());
33     m_checkerThread = std::thread(&ExpiryTimerImpl::runChecker, this);
34 }
35
36 ExpiryTimerImpl::~ExpiryTimerImpl()
37 {
38     m_checkerThread.join();
39 }
40
41 ExpiryTimerImpl* ExpiryTimerImpl::getInstance()
42 {
43     std::call_once(*s_flag, [](){ s_instance = new ExpiryTimerImpl(); });
44     return s_instance;
45 }
46
47 ExpiryTimerImpl::Id ExpiryTimerImpl::post(DelayInMilliSec millisec, CB cb)
48 {
49     Id retID = generateId();
50
51     MilliSeconds delay(millisec);
52     insertTimerCBInfo(countExpireTime(delay), cb, retID);
53
54     return retID;
55 }
56
57 bool ExpiryTimerImpl::cancel(Id id)
58 {
59     bool ret = false;
60     std::lock_guard<std::mutex> lockf(m_mutex);
61     for(auto it: m_timerCBList)
62     {
63         if(it.second.m_id == id)
64         {
65             if(m_timerCBList.erase(it.first)!=0)
66                 ret = true;
67             else
68                 ret = false;
69         }
70     }
71     return ret;
72 }
73
74 void ExpiryTimerImpl::insertTimerCBInfo(ExpiredTime msec, CB cb, Id id)
75 {
76     TimerCBInfo newInfo{id, cb};
77     std::lock_guard<std::mutex> lockf(m_mutex);
78     m_timerCBList.insert({msec, newInfo});
79     m_cond.notify_all();
80 }
81
82 ExpiryTimerImpl::ExpiredTime ExpiryTimerImpl::countExpireTime(MilliSeconds msec)
83 {
84     auto now = std::chrono::system_clock::now();
85     return std::chrono::duration_cast<MilliSeconds>(now.time_since_epoch()) + msec;
86 }
87
88 ExpiryTimerImpl::Id ExpiryTimerImpl::generateId()
89 {
90     Id retID = m_dist(m_device);
91
92     for(auto it = m_timerCBList.begin(); it != m_timerCBList.end(); )
93      {
94        if(it->second.m_id == retID || retID == 0)
95         {
96             retID = m_dist(m_device);
97             it = m_timerCBList.begin();
98         }
99        else
100        {
101            ++it;
102        }
103      }
104
105     return retID;
106 }
107
108 void ExpiryTimerImpl::runChecker()
109 {
110     while(true)
111     {
112         std::unique_lock<std::mutex> ul(m_mutex);
113
114         if(m_timerCBList.empty())
115         {
116             m_cond.wait(ul);
117         }
118         else
119         {
120             ExpiredTime expireTime;
121             expireTime = m_timerCBList.begin()->first;
122
123             auto now = std::chrono::system_clock::now();
124             MilliSeconds waitTime = expireTime - std::chrono::duration_cast<MilliSeconds>(now.time_since_epoch());
125             m_cond.wait_for(ul, waitTime);
126
127             auto callTime = std::chrono::system_clock::now();
128             runExecutor(std::chrono::duration_cast<MilliSeconds>(callTime.time_since_epoch()));
129         }
130     }
131 }
132
133 void ExpiryTimerImpl::runExecutor(ExpiredTime expireTime)
134 {
135     for(auto it = m_timerCBList.begin(); it != m_timerCBList.end(); ++it)
136     {
137         if(it->first <= expireTime)
138         {
139             ExecutorThread executor(it->second);
140             m_timerCBList.erase(it);
141         }
142         else
143         {
144             break;
145         }
146     }
147 }
148
149 // ExecutorThread Class
150 ExpiryTimerImpl::ExecutorThread::ExecutorThread(TimerCBInfo cbInfo)
151 {
152     m_executorThread = std::thread(&ExpiryTimerImpl::ExecutorThread::executorFunc, this, cbInfo);
153 }
154
155 ExpiryTimerImpl::ExecutorThread::~ExecutorThread()
156 {
157     m_executorThread.detach();
158 }
159
160 void ExpiryTimerImpl::ExecutorThread::executorFunc(TimerCBInfo cbInfo)
161 {
162     cbInfo.m_cB(cbInfo.m_id);
163 }