84f489cca240cb9d6aef4974566aeec29959bb9a
[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
29 ExpiryTimer_Impl* ExpiryTimer_Impl::s_instance = nullptr;
30 std::mutex ExpiryTimer_Impl::s_mutexForCreation;
31 bool ExpiryTimer_Impl::isDestroyed = false;
32
33 ExpiryTimer_Impl::ExpiryTimer_Impl()
34 {
35     threadNum = 0;
36     checkThreadRun = false;
37 }
38
39 ExpiryTimer_Impl::~ExpiryTimer_Impl()
40 {
41     isDestroyed = true;
42     int status;
43
44     pthread_join(checker_th, (void **)&status);
45     pthread_detach(checker_th);
46 }
47
48 void ExpiryTimer_Impl::killTimer()
49 {
50     s_instance->~ExpiryTimer_Impl();
51 }
52
53 ExpiryTimer_Impl* ExpiryTimer_Impl::getInstance()
54 {
55     if(isDestroyed)
56     {
57         new(s_instance) ExpiryTimer_Impl;
58         atexit(killTimer);
59         isDestroyed = false;
60     }
61     else if(s_instance == nullptr)
62     {
63         static ExpiryTimer_Impl tmp_instance;
64         s_instance = &tmp_instance;
65     }
66     return s_instance;
67 }
68
69 TimerID ExpiryTimer_Impl::requestTimer(long long sec, TimerCB cb)
70 {
71     if(threadNum < EXPIRY_THREAD_LIST)
72     {
73         unsigned int timerID = generateTimerID();
74         ExpiryTimer_Impl::getInstance()->registerCBTimer(sec, cb, timerID);
75         return timerID;
76     }
77     else
78         return OVERFLOW_THREAD_NUM;
79 }
80
81 void ExpiryTimer_Impl::cancelTimer(TimerID timerID)
82 {
83     for( auto it : mTimerCBList)
84     {
85         if(it.second.m_id == timerID)
86         {
87             mTimerCBList.erase(it.first);
88             timerIDList.remove(it.second.m_id);
89         }
90     }
91 }
92
93 void ExpiryTimer_Impl::registerCBTimer(long long countSEC, TimerCB _cb, TimerID id)
94 {
95     timerCBInfo newInfo = {id, _cb};
96     mTimerCBList.insert(multimap<long long, ExpiryTimer_Impl::timerCBInfo>::value_type(countSEC, newInfo));
97
98     if (checkThreadRun == false)
99     {
100         initThCheck();
101     }
102 }
103
104 void ExpiryTimer_Impl::checkTimeOut()
105 {
106     while (1)
107     {
108         if(mTimerCBList.empty())
109         {
110             checkThreadRun = false;
111             break;
112         }
113        else
114         {
115            long long curSEC = getSeconds(0);
116            long long expireTime;
117            expireTime = mTimerCBList.begin()->first;
118
119            if(curSEC >= expireTime)
120            {
121                initThExecutor(mTimerCBList.begin()->second);
122                mTimerCBList.erase(mTimerCBList.begin());
123            }
124         }
125        usleep(SLEEP_TIME);
126     }
127 }
128
129 void* ExpiryTimer_Impl::threadChecker(void * msg)
130 {
131     if(s_instance != nullptr)
132         s_instance->checkTimeOut();
133     return NULL;
134 }
135
136 void ExpiryTimer_Impl::initThCheck()
137 {
138     int retThreadCreation;
139
140     retThreadCreation = pthread_create(&checker_th, NULL, s_instance->threadChecker, NULL);
141     if (retThreadCreation != 0)
142     {
143         return;
144     }
145     else
146     {
147         checkThreadRun = true;
148     }
149 }
150
151 void *ExpiryTimer_Impl::threadExecutor(void * msg)
152 {
153     TimerCB cb;
154     timerCBInfo *curCBInfo;
155     curCBInfo= (timerCBInfo *) msg;
156
157     cb = curCBInfo->m_pCB;
158     cb(curCBInfo->m_id);
159
160     return NULL;
161 }
162
163 void ExpiryTimer_Impl::initThExecutor(timerCBInfo cbInfo)
164 {
165
166     int retThreadCreation;
167     int status;
168     pthread_t executor_th;
169
170     retThreadCreation = pthread_create(&executor_th, NULL, ExpiryTimer_Impl::threadExecutor, (void *)&cbInfo);
171     threadNum++;
172
173     if (retThreadCreation != 0)
174     {
175         return;
176     }
177     else
178     {
179         pthread_join(executor_th, (void **)&status);
180         pthread_detach(executor_th);
181         threadNum--;
182     }
183 }
184
185 TimerID ExpiryTimer_Impl::generateTimerID()
186 {
187     srand(time(NULL));
188     unsigned int retID = rand();
189
190     for(auto it : timerIDList)
191      {
192        if(it == retID || retID == 0)
193         {
194             retID = rand();
195             it = s_instance->timerIDList.front();
196         }
197      }
198     timerIDList.push_back(retID);
199
200     return retID;
201 }
202
203 long long ExpiryTimer_Impl::getSeconds(long long sec)
204 {
205     time_t curSEC;
206     time(&curSEC);
207     long long retSEC = curSEC + sec;
208     return retSEC;
209 }