1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. 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, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 #include <osl/time.h> 23 24 #include <vos/timer.hxx> 25 #include <vos/diagnose.hxx> 26 #include <vos/ref.hxx> 27 #include <vos/thread.hxx> 28 #include <vos/conditn.hxx> 29 30 31 // Timer manager 32 class OTimerManagerCleanup; 33 34 class vos::OTimerManager : public vos::OThread 35 { 36 37 public: 38 39 // 40 OTimerManager(); 41 42 // 43 ~OTimerManager(); 44 45 // register timer 46 sal_Bool SAL_CALL registerTimer(vos::OTimer* pTimer); 47 48 // unregister timer 49 sal_Bool SAL_CALL unregisterTimer(vos::OTimer* pTimer); 50 51 // lookup timer 52 sal_Bool SAL_CALL lookupTimer(const vos::OTimer* pTimer); 53 54 // retrieves the "Singleton" TimerManager Instance 55 static OTimerManager* SAL_CALL getTimerManager(); 56 57 58 protected: 59 60 // worker-function of thread 61 virtual void SAL_CALL run(); 62 63 // Checking and triggering of a timer event 64 void SAL_CALL checkForTimeout(); 65 66 // cleanup Method 67 virtual void SAL_CALL onTerminated(); 68 69 // sorted-queue data 70 vos::OTimer* m_pHead; 71 // List Protection 72 vos::OMutex m_Lock; 73 // Signal the insertion of a timer 74 vos::OCondition m_notEmpty; 75 76 // Synchronize access to OTimerManager 77 static vos::OMutex m_Access; 78 79 // "Singleton Pattern" 80 static vos::OTimerManager* m_pManager; 81 82 friend class OTimerManagerCleanup; 83 84 }; 85 86 using namespace vos; 87 88 // Timer class 89 VOS_IMPLEMENT_CLASSINFO(VOS_CLASSNAME(OTimer, vos), 90 VOS_NAMESPACE(OTimer, vos), 91 VOS_NAMESPACE(OObject, vos), 0); 92 93 OTimer::OTimer() 94 { 95 m_TimeOut = 0; 96 m_Expired = 0; 97 m_RepeatDelta = 0; 98 m_pNext = 0; 99 } 100 101 OTimer::OTimer(const TTimeValue& Time) 102 { 103 m_TimeOut = Time; 104 m_RepeatDelta = 0; 105 m_Expired = 0; 106 m_pNext = 0; 107 108 m_TimeOut.normalize(); 109 } 110 111 OTimer::OTimer(const TTimeValue& Time, const TTimeValue& Repeat) 112 { 113 m_TimeOut = Time; 114 m_RepeatDelta = Repeat; 115 m_Expired = 0; 116 m_pNext = 0; 117 118 m_TimeOut.normalize(); 119 m_RepeatDelta.normalize(); 120 } 121 122 OTimer::~OTimer() 123 { 124 stop(); 125 } 126 127 void OTimer::start() 128 { 129 if (! isTicking()) 130 { 131 if (! m_TimeOut.isEmpty()) 132 setRemainingTime(m_TimeOut); 133 134 OTimerManager *pManager = OTimerManager::getTimerManager(); 135 136 VOS_ASSERT(pManager); 137 138 if ( pManager != 0 ) 139 { 140 pManager->registerTimer(this); 141 } 142 } 143 } 144 145 void OTimer::stop() 146 { 147 OTimerManager *pManager = OTimerManager::getTimerManager(); 148 149 VOS_ASSERT(pManager); 150 151 if ( pManager != 0 ) 152 { 153 pManager->unregisterTimer(this); 154 } 155 } 156 157 sal_Bool OTimer::isTicking() const 158 { 159 OTimerManager *pManager = OTimerManager::getTimerManager(); 160 161 VOS_ASSERT(pManager); 162 163 if (pManager) 164 return pManager->lookupTimer(this); 165 else 166 return sal_False; 167 168 } 169 170 sal_Bool OTimer::isExpired() const 171 { 172 TTimeValue Now; 173 174 osl_getSystemTime(&Now); 175 176 return !(Now < m_Expired); 177 } 178 179 sal_Bool OTimer::expiresBefore(const OTimer* pTimer) const 180 { 181 VOS_ASSERT(pTimer); 182 183 if ( pTimer != 0 ) 184 { 185 return m_Expired < pTimer->m_Expired; 186 } 187 else 188 { 189 return sal_False; 190 } 191 } 192 193 void OTimer::setAbsoluteTime(const TTimeValue& Time) 194 { 195 m_TimeOut = 0; 196 m_Expired = Time; 197 m_RepeatDelta = 0; 198 199 m_Expired.normalize(); 200 } 201 202 void OTimer::setRemainingTime(const TTimeValue& Remaining) 203 { 204 osl_getSystemTime(&m_Expired); 205 206 m_Expired.addTime(Remaining); 207 } 208 209 void OTimer::setRemainingTime(const TTimeValue& Remaining, const TTimeValue& Repeat) 210 { 211 osl_getSystemTime(&m_Expired); 212 213 m_Expired.addTime(Remaining); 214 215 m_RepeatDelta = Repeat; 216 } 217 218 void OTimer::addTime(const TTimeValue& Delta) 219 { 220 m_Expired.addTime(Delta); 221 } 222 223 TTimeValue OTimer::getRemainingTime() const 224 { 225 TTimeValue Now; 226 227 osl_getSystemTime(&Now); 228 229 sal_Int32 secs = m_Expired.Seconds - Now.Seconds; 230 231 if (secs < 0) 232 return TTimeValue(0, 0); 233 234 sal_Int32 nsecs = m_Expired.Nanosec - Now.Nanosec; 235 236 if (nsecs < 0) 237 { 238 if (secs > 0) 239 { 240 secs -= 1; 241 nsecs += 1000000000; 242 } 243 else 244 return TTimeValue(0, 0); 245 } 246 247 return TTimeValue(secs, nsecs); 248 } 249 250 251 // Timer manager 252 OMutex vos::OTimerManager::m_Access; 253 OTimerManager* vos::OTimerManager::m_pManager=0; 254 255 OTimerManager::OTimerManager() 256 { 257 OGuard Guard(&m_Access); 258 259 VOS_ASSERT(m_pManager == 0); 260 261 m_pManager = this; 262 263 m_pHead= 0; 264 265 m_notEmpty.reset(); 266 267 // start thread 268 create(); 269 } 270 271 OTimerManager::~OTimerManager() 272 { 273 OGuard Guard(&m_Access); 274 275 if ( m_pManager == this ) 276 m_pManager = 0; 277 } 278 279 void OTimerManager::onTerminated() 280 { 281 delete this; // mfe: AAARRRGGGHHH!!! 282 } 283 284 OTimerManager* OTimerManager::getTimerManager() 285 { 286 OGuard Guard(&m_Access); 287 288 if (! m_pManager) 289 new OTimerManager; 290 291 return (m_pManager); 292 } 293 294 sal_Bool OTimerManager::registerTimer(OTimer* pTimer) 295 { 296 VOS_ASSERT(pTimer); 297 298 if ( pTimer == 0 ) 299 { 300 return sal_False; 301 } 302 303 OGuard Guard(&m_Lock); 304 305 // try to find one with equal or lower remaining time. 306 OTimer** ppIter = &m_pHead; 307 308 while (*ppIter) 309 { 310 if (pTimer->expiresBefore(*ppIter)) 311 { 312 // next element has higher remaining time, 313 // => insert new timer before 314 break; 315 } 316 ppIter= &((*ppIter)->m_pNext); 317 } 318 319 // next element has higher remaining time, 320 // => insert new timer before 321 pTimer->m_pNext= *ppIter; 322 *ppIter = pTimer; 323 324 325 if (pTimer == m_pHead) 326 { 327 // it was inserted as new head 328 // signal it to TimerManager Thread 329 m_notEmpty.set(); 330 } 331 332 return sal_True; 333 } 334 335 sal_Bool OTimerManager::unregisterTimer(OTimer* pTimer) 336 { 337 VOS_ASSERT(pTimer); 338 339 if ( pTimer == 0 ) 340 { 341 return sal_False; 342 } 343 344 // lock access 345 OGuard Guard(&m_Lock); 346 347 OTimer** ppIter = &m_pHead; 348 349 while (*ppIter) 350 { 351 if (pTimer == (*ppIter)) 352 { 353 // remove timer from list 354 *ppIter = (*ppIter)->m_pNext; 355 return sal_True; 356 } 357 ppIter= &((*ppIter)->m_pNext); 358 } 359 360 return sal_False; 361 } 362 363 sal_Bool OTimerManager::lookupTimer(const OTimer* pTimer) 364 { 365 VOS_ASSERT(pTimer); 366 367 if ( pTimer == 0 ) 368 { 369 return sal_False; 370 } 371 372 // lock access 373 OGuard Guard(&m_Lock); 374 375 // check the list 376 for (OTimer* pIter = m_pHead; pIter != 0; pIter= pIter->m_pNext) 377 { 378 if (pIter == pTimer) 379 { 380 return sal_True; 381 } 382 } 383 384 return sal_False; 385 } 386 387 void OTimerManager::checkForTimeout() 388 { 389 390 m_Lock.acquire(); 391 392 if ( m_pHead == 0 ) 393 { 394 m_Lock.release(); 395 return; 396 } 397 398 OTimer* pTimer = m_pHead; 399 400 if (pTimer->isExpired()) 401 { 402 // remove expired timer 403 m_pHead = pTimer->m_pNext; 404 405 pTimer->acquire(); 406 407 m_Lock.release(); 408 409 pTimer->onShot(); 410 411 // restart timer if specified 412 if ( ! pTimer->m_RepeatDelta.isEmpty() ) 413 { 414 TTimeValue Now; 415 416 osl_getSystemTime(&Now); 417 418 Now.Seconds += pTimer->m_RepeatDelta.Seconds; 419 Now.Nanosec += pTimer->m_RepeatDelta.Nanosec; 420 421 pTimer->m_Expired = Now; 422 423 registerTimer(pTimer); 424 } 425 pTimer->release(); 426 } 427 else 428 { 429 m_Lock.release(); 430 } 431 432 433 return; 434 } 435 436 void OTimerManager::run() 437 { 438 setPriority(TPriority_BelowNormal); 439 440 while (schedule()) 441 { 442 TTimeValue delay; 443 TTimeValue* pDelay=0; 444 445 446 m_Lock.acquire(); 447 448 if (m_pHead != 0) 449 { 450 delay = m_pHead->getRemainingTime(); 451 pDelay=&delay; 452 } 453 else 454 { 455 pDelay=0; 456 } 457 458 459 m_notEmpty.reset(); 460 461 m_Lock.release(); 462 463 464 m_notEmpty.wait(pDelay); 465 466 checkForTimeout(); 467 } 468 469 } 470 471 // Timer manager cleanup 472 473 // jbu: 474 // The timer manager cleanup has been removed (no thread is killed anymore). 475 // So the thread leaks. 476 // This will result in a GPF in case the vos-library gets unloaded before 477 // process termination. 478 // -> TODO : rewrite this file, so that the timerManager thread gets destroyed, 479 // when there are no timers anymore ! 480 481 /* vim: set noet sw=4 ts=4: */ 482