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