Add destroy function into primitive service timer
[platform/upstream/iotivity.git] / service / resource-manipulation / modules / common / expiryTimer / src / ExpiryTimer_Impl.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 "ExpiryTimer_Impl.h"
22
23 #include <unistd.h>
24 #include <algorithm>
25 #include <cstdlib>
26 #include <utility>
27
28 ExpiryTimer_Impl* ExpiryTimer_Impl::s_instance = nullptr;
29 std::once_flag* ExpiryTimer_Impl::mflag = new std::once_flag;
30
31 ExpiryTimer_Impl::ExpiryTimer_Impl()
32 {
33     createChecker();
34 }
35
36 ExpiryTimer_Impl::~ExpiryTimer_Impl()
37 {
38     check.detach();
39     delete mflag;
40     s_instance = nullptr;
41     delete s_instance;
42 }
43
44 void ExpiryTimer_Impl::destroy()
45 {
46     if(mTimerCBList.empty())
47     {
48         try
49         {
50             s_instance->~ExpiryTimer_Impl();
51         }
52         catch(std::exception &e)
53         {
54             std::cout << e.what();
55         }
56     }
57 }
58 ExpiryTimer_Impl* ExpiryTimer_Impl::getInstance()
59 {
60     std::call_once((*mflag), [](){ s_instance = new ExpiryTimer_Impl(); });
61     return s_instance;
62 }
63
64 ExpiryTimer_Impl::Id ExpiryTimer_Impl::postTimer(DelayMilliSec msec, TimerCb cb)
65 {
66     Id retID;
67     retID = generateID();
68
69     milliSeconds delay(msec);
70     insertTimerCBInfo(countExpireTime(delay), cb, retID);
71
72     return retID;
73 }
74
75 bool ExpiryTimer_Impl::cancelTimer(Id timerID)
76 {
77     bool ret = false;
78     for(auto it: mTimerCBList)
79     {
80         if(it.second.m_id == timerID)
81         {
82             std::lock_guard<std::mutex> lockf(m_mutex);
83             if(mTimerCBList.erase(it.first)!=0)
84                 ret = true;
85             else
86                 ret = false;
87         }
88     }
89     return ret;
90 }
91
92 void ExpiryTimer_Impl::insertTimerCBInfo(ExpiredTime msec, TimerCb cb, Id timerID)
93 {
94     TimerCBInfo newInfo = {timerID, cb};
95     std::lock_guard<std::mutex> lockf(m_mutex);
96     mTimerCBList.insert(std::multimap<ExpiredTime, TimerCBInfo>::value_type(msec, newInfo));
97     m_cond.notify_all();
98 }
99
100 ExpiryTimer_Impl::ExpiredTime ExpiryTimer_Impl::countExpireTime(milliDelayTime msec)
101 {
102     auto now = std::chrono::system_clock::now();
103     milliSeconds ret = std::chrono::duration_cast<milliSeconds>(now.time_since_epoch()) + msec;
104
105     return ret;
106 }
107
108 ExpiryTimer_Impl::Id ExpiryTimer_Impl::generateID()
109 {
110     srand(time(NULL));
111     Id retID = rand();
112
113     std::lock_guard<std::mutex> lockf(id_mutex);
114     for(std::multimap<ExpiredTime, TimerCBInfo>::iterator it=mTimerCBList.begin(); it!=mTimerCBList.end(); ++it)
115      {
116        if((*it).second.m_id == retID || retID == 0)
117         {
118             retID = rand();
119             it = mTimerCBList.begin();
120         }
121      }
122     return retID;
123 }
124
125 void ExpiryTimer_Impl::createChecker()
126 {
127     check = std::thread(&ExpiryTimer_Impl::doChecker, this);
128 }
129
130 void ExpiryTimer_Impl::doChecker()
131 {
132     while(true)
133     {
134         std::unique_lock<std::mutex> ul(cond_mutex);
135
136         if(mTimerCBList.empty())
137         {
138             m_cond.wait_for(ul, std::chrono::seconds(CHECKER_WAIT_TIME));
139         }
140         else
141         {
142             ExpiredTime expireTime;
143             expireTime = mTimerCBList.begin()->first;
144
145             auto now = std::chrono::system_clock::now();
146             milliSeconds waitTime = expireTime - std::chrono::duration_cast<milliSeconds>(now.time_since_epoch());
147             m_cond.wait_for(ul, waitTime);
148
149             auto callTime = std::chrono::system_clock::now();
150             doExecutor(std::chrono::duration_cast<milliSeconds>(callTime.time_since_epoch()));
151         }
152     }
153 }
154
155 void ExpiryTimer_Impl::doExecutor(ExpiredTime expireTime)
156 {
157     for(auto it: mTimerCBList)
158     {
159         if(it.first <= expireTime)
160         {
161             new ExecutorThread(it.second);
162             mTimerCBList.erase(mTimerCBList.begin());
163         }
164         else
165             break;
166     }
167 }
168
169 // ExecuterThread Class
170 ExpiryTimer_Impl::ExecutorThread::ExecutorThread(TimerCBInfo cbInfo)
171 {
172     execute = std::thread(&ExpiryTimer_Impl::ExecutorThread::executorFunc, this, cbInfo);
173 }
174
175 ExpiryTimer_Impl::ExecutorThread::~ExecutorThread()
176 {
177     execute.detach();
178 }
179
180 void ExpiryTimer_Impl::ExecutorThread::executorFunc(TimerCBInfo cbInfo)
181 {
182     cbInfo.m_cb(cbInfo.m_id);
183 }