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