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