Changeset 2206
- Timestamp:
- 27/07/2008 21:36:14 (5 months ago)
- Location:
- box/trunk/lib/common
- Files:
-
- 2 modified
Legend:
- Unmodified
- Added
- Removed
-
box/trunk/lib/common/Timer.cpp
r2003 r2206 9 9 // -------------------------------------------------------------------------- 10 10 11 #ifdef WIN32 12 #define _WIN32_WINNT 0x0500 13 #endif 14 11 15 #include "Box.h" 12 16 … … 20 24 std::vector<Timer*>* Timers::spTimers = NULL; 21 25 bool Timers::sRescheduleNeeded = false; 26 27 #define TIMER_ID "timer " << mName << " (" << this << ") " 28 #define TIMER_ID_OF(t) "timer " << (t).GetName() << " (" << &(t) << ") " 22 29 23 30 typedef void (*sighandler_t)(int); … … 36 43 37 44 #if defined WIN32 && ! defined PLATFORM_CYGWIN 38 // no support for signals at all 39 InitTimer(); 40 SetTimerHandler(Timers::SignalHandler); 45 // no init needed 41 46 #else 42 47 struct sigaction newact, oldact; … … 73 78 74 79 #if defined WIN32 && ! defined PLATFORM_CYGWIN 75 // no support for signals at all 76 FiniTimer(); 77 SetTimerHandler(NULL); 80 // no cleanup needed 78 81 #else 79 82 struct itimerval timeout; … … 150 153 } 151 154 155 void Timers::RequestReschedule() 156 { 157 sRescheduleNeeded = true; 158 } 159 160 void Timers::RescheduleIfNeeded() 161 { 162 if (sRescheduleNeeded) 163 { 164 Reschedule(); 165 } 166 } 167 152 168 #define FORMAT_MICROSECONDS(t) \ 153 169 (int)(t / 1000000) << "." << \ 154 (int)(t % 1000000) 170 (int)(t % 1000000) << " seconds" 155 171 156 172 // -------------------------------------------------------------------------- … … 196 212 sRescheduleNeeded = false; 197 213 214 #ifdef WIN32 215 // win32 timers need no management 216 #else 198 217 box_time_t timeNow = GetCurrentBoxTime(); 199 218 … … 213 232 if (timeToExpiry <= 0) 214 233 { 234 /* 215 235 BOX_TRACE("timer " << *i << " has expired, " 216 236 "triggering it"); 237 */ 238 BOX_TRACE(TIMER_ID_OF(**i) "has expired, " 239 "triggering " << 240 FORMAT_MICROSECONDS(-timeToExpiry) << 241 " late"); 217 242 rTimer.OnExpire(); 218 243 spTimers->erase(i); … … 222 247 else 223 248 { 249 /* 224 250 BOX_TRACE("timer " << *i << " has not " 225 251 "expired, triggering in " << 226 252 FORMAT_MICROSECONDS(timeToExpiry) << 227 253 " seconds"); 254 */ 228 255 } 229 256 } … … 234 261 235 262 int64_t timeToNextEvent = 0; 263 std::string nameOfNextEvent; 236 264 237 265 for (std::vector<Timer*>::iterator i = spTimers->begin(); … … 241 269 int64_t timeToExpiry = rTimer.GetExpiryTime() - timeNow; 242 270 271 ASSERT(timeToExpiry > 0) 243 272 if (timeToExpiry <= 0) 244 273 { … … 249 278 { 250 279 timeToNextEvent = timeToExpiry; 280 nameOfNextEvent = rTimer.GetName(); 251 281 } 252 282 } 253 283 254 284 ASSERT(timeToNextEvent >= 0); 255 285 286 if (timeToNextEvent == 0) 287 { 288 BOX_TRACE("timer: no more events, going to sleep."); 289 } 290 else 291 { 292 BOX_TRACE("timer: next event: " << nameOfNextEvent << 293 " expires in " << FORMAT_MICROSECONDS(timeToNextEvent)); 294 } 295 256 296 struct itimerval timeout; 257 297 memset(&timeout, 0, sizeof(timeout)); … … 259 299 timeout.it_value.tv_sec = BoxTimeToSeconds(timeToNextEvent); 260 300 timeout.it_value.tv_usec = (int) 261 (BoxTimeToMicroSeconds(timeToNextEvent) % MICRO_SEC_IN_SEC); 301 (BoxTimeToMicroSeconds(timeToNextEvent) 302 % MICRO_SEC_IN_SEC); 262 303 263 304 if(::setitimer(ITIMER_REAL, &timeout, NULL) != 0) 264 305 { 265 BOX_ERROR("Failed to initialise timer\n");306 BOX_ERROR("Failed to initialise system timer\n"); 266 307 THROW_EXCEPTION(CommonException, Internal) 267 308 } 309 #endif 268 310 } 269 311 … … 280 322 // 281 323 // -------------------------------------------------------------------------- 282 void Timers::SignalHandler(int iUnused)324 void Timers::SignalHandler(int unused) 283 325 { 284 326 // ASSERT(spTimers); … … 286 328 } 287 329 288 Timer::Timer(size_t timeoutSecs) 330 // -------------------------------------------------------------------------- 331 // 332 // Function 333 // Name: Timer::Timer(size_t timeoutSecs, 334 // const std::string& rName) 335 // Purpose: Standard timer constructor, takes a timeout in 336 // seconds from now, and an optional name for 337 // logging purposes. 338 // Created: 27/07/2008 339 // 340 // -------------------------------------------------------------------------- 341 342 Timer::Timer(size_t timeoutSecs, const std::string& rName) 289 343 : mExpires(GetCurrentBoxTime() + SecondsToBoxTime(timeoutSecs)), 290 mExpired(false) 344 mExpired(false), 345 mName(rName) 346 #ifdef WIN32 347 , mTimerHandle(INVALID_HANDLE_VALUE) 348 #endif 291 349 { 292 350 #ifndef NDEBUG 293 351 if (timeoutSecs == 0) 294 352 { 295 BOX_TRACE( "timer " << this << " initialised for " <<296 timeoutSecs <<" secs, will not fire");353 BOX_TRACE(TIMER_ID "initialised for " << timeoutSecs << 354 " secs, will not fire"); 297 355 } 298 356 else 299 357 { 300 BOX_TRACE("timer " << this << " initialised for " << 301 timeoutSecs << " secs, to fire at " << 302 FORMAT_MICROSECONDS(mExpires)); 358 BOX_TRACE(TIMER_ID "initialised for " << timeoutSecs << 359 " secs, to fire at " << FormatTime(mExpires, true)); 303 360 } 304 361 #endif … … 311 368 { 312 369 Timers::Add(*this); 313 } 314 } 370 Start(timeoutSecs * MICRO_SEC_IN_SEC_LL); 371 } 372 } 373 374 // -------------------------------------------------------------------------- 375 // 376 // Function 377 // Name: Timer::Start() 378 // Purpose: This internal function initialises an OS TimerQueue 379 // timer on Windows, while on Unixes there is only a 380 // single global timer, managed by the Timers class, 381 // so this method does nothing. 382 // Created: 27/07/2008 383 // 384 // -------------------------------------------------------------------------- 385 386 void Timer::Start() 387 { 388 #ifdef WIN32 389 box_time_t timeNow = GetCurrentBoxTime(); 390 int64_t timeToExpiry = mExpires - timeNow; 391 392 if (timeToExpiry <= 0) 393 { 394 BOX_WARNING(TIMER_ID << "fudging expiry from -" << 395 FORMAT_MICROSECONDS(-timeToExpiry)) 396 timeToExpiry = 1; 397 } 398 399 Start(timeToExpiry); 400 #endif 401 } 402 403 // -------------------------------------------------------------------------- 404 // 405 // Function 406 // Name: Timer::Start(int64_t delayInMicros) 407 // Purpose: This internal function initialises an OS TimerQueue 408 // timer on Windows, with a specified delay already 409 // calculated to save us doing it again. Like 410 // Timer::Start(), on Unixes it does nothing. 411 // Created: 27/07/2008 412 // 413 // -------------------------------------------------------------------------- 414 415 void Timer::Start(int64_t delayInMicros) 416 { 417 #ifdef WIN32 418 // only call me once! 419 ASSERT(mTimerHandle == INVALID_HANDLE_VALUE); 420 421 int64_t delayInMillis = delayInMicros / 1000; 422 423 // Windows XP always seems to fire timers up to 20 ms late, 424 // at least on my test laptop. Not critical in practice, but our 425 // tests are precise enough that they will fail if we don't 426 // correct for it. 427 delayInMillis -= 20; 428 429 // Set a system timer to call our timer routine 430 if (CreateTimerQueueTimer(&mTimerHandle, NULL, TimerRoutine, 431 (PVOID)this, delayInMillis, 0, WT_EXECUTEINTIMERTHREAD) 432 == FALSE) 433 { 434 BOX_ERROR(TIMER_ID "failed to create timer: " << 435 GetErrorMessage(GetLastError())); 436 mTimerHandle = INVALID_HANDLE_VALUE; 437 } 438 #endif 439 } 440 441 // -------------------------------------------------------------------------- 442 // 443 // Function 444 // Name: Timer::Stop() 445 // Purpose: This internal function deletes the associated OS 446 // TimerQueue timer on Windows, and on Unixes does 447 // nothing. 448 // Created: 27/07/2008 449 // 450 // -------------------------------------------------------------------------- 451 452 void Timer::Stop() 453 { 454 #ifdef WIN32 455 if (mTimerHandle != INVALID_HANDLE_VALUE) 456 { 457 if (DeleteTimerQueueTimer(NULL, mTimerHandle, 458 INVALID_HANDLE_VALUE) == FALSE) 459 { 460 BOX_ERROR(TIMER_ID "failed to delete timer: " << 461 GetErrorMessage(GetLastError())); 462 } 463 mTimerHandle = INVALID_HANDLE_VALUE; 464 } 465 #endif 466 } 467 468 // -------------------------------------------------------------------------- 469 // 470 // Function 471 // Name: Timer::~Timer() 472 // Purpose: Destructor for Timer objects. 473 // Created: 27/07/2008 474 // 475 // -------------------------------------------------------------------------- 315 476 316 477 Timer::~Timer() 317 478 { 318 479 #ifndef NDEBUG 319 BOX_TRACE( "timer " << this << "destroyed");480 BOX_TRACE(TIMER_ID "destroyed"); 320 481 #endif 321 482 322 483 Timers::Remove(*this); 323 } 484 Stop(); 485 } 486 487 // -------------------------------------------------------------------------- 488 // 489 // Function 490 // Name: Timer::Timer(Timer& rToCopy) 491 // Purpose: Copy constructor for Timer objects. Creates a new 492 // timer that will trigger at the same time as the 493 // original. The original will usually be discarded. 494 // Created: 27/07/2008 495 // 496 // -------------------------------------------------------------------------- 324 497 325 498 Timer::Timer(const Timer& rToCopy) 326 499 : mExpires(rToCopy.mExpires), 327 mExpired(rToCopy.mExpired) 500 mExpired(rToCopy.mExpired), 501 mName(rToCopy.mName) 502 #ifdef WIN32 503 , mTimerHandle(INVALID_HANDLE_VALUE) 504 #endif 328 505 { 329 506 #ifndef NDEBUG 330 507 if (mExpired) 331 508 { 332 BOX_TRACE( "timer " << this << " initialised from timer " <<333 &rToCopy << ",already expired, will not fire");509 BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", " 510 "already expired, will not fire"); 334 511 } 335 512 else if (mExpires == 0) 336 513 { 337 BOX_TRACE( "timer " << this << " initialised from timer " <<338 &rToCopy << ",no expiry, will not fire");514 BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", " 515 "no expiry, will not fire"); 339 516 } 340 517 else 341 518 { 342 BOX_TRACE( "timer " << this << " initialised from timer " <<343 &rToCopy << "to fire at " <<519 BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", " 520 "to fire at " << 344 521 (int)(mExpires / 1000000) << "." << 345 522 (int)(mExpires % 1000000)); … … 350 527 { 351 528 Timers::Add(*this); 352 } 353 } 529 Start(); 530 } 531 } 532 533 // -------------------------------------------------------------------------- 534 // 535 // Function 536 // Name: Timer::operator=(const Timer& rToCopy) 537 // Purpose: Assignment operator for Timer objects. Works 538 // exactly the same as the copy constructor, except 539 // that if the receiving timer is already running, 540 // it is stopped first. 541 // Created: 27/07/2008 542 // 543 // -------------------------------------------------------------------------- 354 544 355 545 Timer& Timer::operator=(const Timer& rToCopy) … … 358 548 if (rToCopy.mExpired) 359 549 { 360 BOX_TRACE( "timer " << this << " initialised from timer " <<361 &rToCopy << ",already expired, will not fire");550 BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", " 551 "already expired, will not fire"); 362 552 } 363 553 else if (rToCopy.mExpires == 0) 364 554 { 365 BOX_TRACE( "timer " << this << " initialised from timer " <<366 &rToCopy << ",no expiry, will not fire");555 BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", " 556 "no expiry, will not fire"); 367 557 } 368 558 else 369 559 { 370 BOX_TRACE( "timer " << this << " initialised from timer " <<371 &rToCopy << "to fire at " <<560 BOX_TRACE(TIMER_ID "initialised from timer " << &rToCopy << ", " 561 "to fire at " << 372 562 (int)(rToCopy.mExpires / 1000000) << "." << 373 563 (int)(rToCopy.mExpires % 1000000)); … … 376 566 377 567 Timers::Remove(*this); 568 Stop(); 569 378 570 mExpires = rToCopy.mExpires; 379 571 mExpired = rToCopy.mExpired; 572 380 573 if (!mExpired && mExpires != 0) 381 574 { 382 575 Timers::Add(*this); 383 } 576 Start(); 577 } 578 384 579 return *this; 385 580 } 386 581 582 // -------------------------------------------------------------------------- 583 // 584 // Function 585 // Name: Timer::OnExpire() 586 // Purpose: Method called by Timers::Reschedule (on Unixes) 587 // on next poll after timer expires, or from 588 // Timer::TimerRoutine (on Windows) from a separate 589 // thread managed by the OS. Marks the timer as 590 // expired for future reference. 591 // Created: 27/07/2008 592 // 593 // -------------------------------------------------------------------------- 594 387 595 void Timer::OnExpire() 388 596 { 389 597 #ifndef NDEBUG 390 BOX_TRACE( "timer " << this << "fired");598 BOX_TRACE(TIMER_ID "fired"); 391 599 #endif 392 600 393 601 mExpired = true; 394 602 } 603 604 // -------------------------------------------------------------------------- 605 // 606 // Function 607 // Name: Timer::TimerRoutine(PVOID lpParam, 608 // BOOLEAN TimerOrWaitFired) 609 // Purpose: Static method called by the Windows OS when a 610 // TimerQueue timer expires. 611 // Created: 27/07/2008 612 // 613 // -------------------------------------------------------------------------- 614 615 #ifdef WIN32 616 VOID CALLBACK Timer::TimerRoutine(PVOID lpParam, 617 BOOLEAN TimerOrWaitFired) 618 { 619 Timer* pTimer = (Timer*)lpParam; 620 pTimer->OnExpire(); 621 // is it safe to write to write debug output from a timer? 622 // e.g. to write to the Event Log? 623 } 624 #endif -
box/trunk/lib/common/Timer.h
r1758 r2206 41 41 static bool sRescheduleNeeded; 42 42 static void SignalHandler(int iUnused); 43 43 44 44 public: 45 45 static void Init(); … … 47 47 static void Add (Timer& rTimer); 48 48 static void Remove(Timer& rTimer); 49 static void RequestReschedule() 50 { 51 sRescheduleNeeded = true; 52 } 53 54 static void RescheduleIfNeeded() 55 { 56 if (sRescheduleNeeded) 57 { 58 Reschedule(); 59 } 60 } 49 static void RequestReschedule(); 50 static void RescheduleIfNeeded(); 61 51 }; 62 52 … … 64 54 { 65 55 public: 66 Timer(size_t timeoutSecs );56 Timer(size_t timeoutSecs, const std::string& rName = ""); 67 57 virtual ~Timer(); 68 58 Timer(const Timer &); 69 59 Timer &operator=(const Timer &); 70 60 71 public:72 61 box_time_t GetExpiryTime() { return mExpires; } 73 62 virtual void OnExpire(); … … 77 66 return mExpired; 78 67 } 68 69 const std::string& GetName() const { return mName; } 79 70 80 71 private: 81 box_time_t mExpires; 82 bool mExpired; 72 box_time_t mExpires; 73 bool mExpired; 74 std::string mName; 75 76 void Start(); 77 void Start(int64_t delayInMicros); 78 void Stop(); 79 80 #ifdef WIN32 81 HANDLE mTimerHandle; 82 static VOID CALLBACK TimerRoutine(PVOID lpParam, 83 BOOLEAN TimerOrWaitFired); 84 #endif 83 85 }; 84 86
