1 /* 2 * Copyright 2014, Paweł Dziepak, pdziepak@quarnos.org. 3 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include <UserTimer.h> 9 10 #include <algorithm> 11 12 #include <AutoDeleter.h> 13 14 #include <debug.h> 15 #include <kernel.h> 16 #include <real_time_clock.h> 17 #include <team.h> 18 #include <thread_types.h> 19 #include <UserEvent.h> 20 #include <util/AutoLock.h> 21 22 23 // Minimum interval length in microseconds for a periodic timer. This is not a 24 // restriction on the user timer interval length itself, but the minimum time 25 // span by which we advance the start time for kernel timers. A shorted user 26 // timer interval will result in the overrun count to be increased every time 27 // the kernel timer is rescheduled. 28 static const bigtime_t kMinPeriodicTimerInterval = 100; 29 30 static RealTimeUserTimerList sAbsoluteRealTimeTimers; 31 static spinlock sAbsoluteRealTimeTimersLock = B_SPINLOCK_INITIALIZER; 32 33 static seqlock sUserTimerLock = B_SEQLOCK_INITIALIZER; 34 35 36 // #pragma mark - TimerLocker 37 38 39 namespace { 40 41 struct TimerLocker { 42 Team* team; 43 Thread* thread; 44 45 TimerLocker() 46 : 47 team(NULL), 48 thread(NULL) 49 { 50 } 51 52 ~TimerLocker() 53 { 54 Unlock(); 55 } 56 57 void Lock(Team* team, Thread* thread) 58 { 59 this->team = team; 60 team->Lock(); 61 62 this->thread = thread; 63 64 if (thread != NULL) { 65 thread->AcquireReference(); 66 thread->Lock(); 67 } 68 69 // We don't check thread->team != team here, since this method can be 70 // called for new threads not added to the team yet. 71 } 72 73 status_t LockAndGetTimer(thread_id threadID, int32 timerID, 74 UserTimer*& _timer) 75 { 76 team = thread_get_current_thread()->team; 77 team->Lock(); 78 79 if (threadID >= 0) { 80 thread = Thread::GetAndLock(threadID); 81 if (thread == NULL) 82 return B_BAD_THREAD_ID; 83 if (thread->team != team) 84 return B_NOT_ALLOWED; 85 } 86 87 UserTimer* timer = thread != NULL 88 ? thread->UserTimerFor(timerID) : team->UserTimerFor(timerID); 89 if (timer == NULL) 90 return B_BAD_VALUE; 91 92 _timer = timer; 93 return B_OK; 94 } 95 96 void Unlock() 97 { 98 if (thread != NULL) { 99 thread->UnlockAndReleaseReference(); 100 thread = NULL; 101 } 102 if (team != NULL) { 103 team->Unlock(); 104 team = NULL; 105 } 106 } 107 }; 108 109 } // unnamed namespace 110 111 112 // #pragma mark - UserTimer 113 114 115 UserTimer::UserTimer() 116 : 117 fID(-1), 118 fEvent(NULL), 119 fNextTime(0), 120 fInterval(0), 121 fOverrunCount(0), 122 fScheduled(false), 123 fSkip(0) 124 { 125 // mark the timer unused 126 fTimer.user_data = this; 127 } 128 129 130 UserTimer::~UserTimer() 131 { 132 if (fEvent != NULL) 133 fEvent->ReleaseReference(); 134 } 135 136 137 /*! \fn UserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, 138 bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval) 139 Cancels the timer, if it is already scheduled, and optionally schedules it 140 with new parameters. 141 142 \param nextTime The time at which the timer should go off the next time. If 143 \c B_INFINITE_TIMEOUT, the timer will not be scheduled. Whether the 144 value is interpreted as absolute or relative time, depends on \c flags. 145 \param interval If <tt> >0 </tt>, the timer will be scheduled to fire 146 periodically every \a interval microseconds. Otherwise it will fire 147 only once at \a nextTime. If \a nextTime is \c B_INFINITE_TIMEOUT, it 148 will fire never in either case. 149 \param flags Bitwise OR of flags. Currently \c B_ABSOLUTE_TIMEOUT and 150 \c B_RELATIVE_TIMEOUT are supported, indicating whether \a nextTime is 151 an absolute or relative time. 152 \param _oldRemainingTime Return variable that will be set to the 153 microseconds remaining to the time for which the timer was scheduled 154 next before the call. If it wasn't scheduled, the variable is set to 155 \c B_INFINITE_TIMEOUT. 156 \param _oldInterval Return variable that will be set to the interval in 157 microseconds the timer was to be scheduled periodically. If the timer 158 wasn't periodic, the variable is set to \c 0. 159 */ 160 161 162 /*! Cancels the timer, if it is scheduled. 163 */ 164 void 165 UserTimer::Cancel() 166 { 167 bigtime_t oldNextTime; 168 bigtime_t oldInterval; 169 return Schedule(B_INFINITE_TIMEOUT, 0, 0, oldNextTime, oldInterval); 170 } 171 172 173 /*! \fn UserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval, 174 uint32& _overrunCount) 175 Return information on the current timer. 176 177 \param _remainingTime Return variable that will be set to the microseconds 178 remaining to the time for which the timer was scheduled next before the 179 call. If it wasn't scheduled, the variable is set to 180 \c B_INFINITE_TIMEOUT. 181 \param _interval Return variable that will be set to the interval in 182 microseconds the timer is to be scheduled periodically. If the timer 183 isn't periodic, the variable is set to \c 0. 184 \param _overrunCount Return variable that will be set to the number of times 185 the timer went off, but its event couldn't be delivered, since it's 186 previous delivery hasn't been handled yet. 187 */ 188 189 190 /*static*/ int32 191 UserTimer::HandleTimerHook(struct timer* timer) 192 { 193 UserTimer* userTimer = reinterpret_cast<UserTimer*>(timer->user_data); 194 195 InterruptsLocker _; 196 197 bool locked = false; 198 while (!locked && atomic_get(&userTimer->fSkip) == 0) { 199 locked = try_acquire_write_seqlock(&sUserTimerLock); 200 if (!locked) 201 cpu_pause(); 202 } 203 204 if (locked) { 205 userTimer->HandleTimer(); 206 release_write_seqlock(&sUserTimerLock); 207 } 208 209 return B_HANDLED_INTERRUPT; 210 } 211 212 213 void 214 UserTimer::HandleTimer() 215 { 216 if (fEvent != NULL) { 217 // fire the event and update the overrun count, if necessary 218 status_t error = fEvent->Fire(); 219 if (error == B_BUSY) { 220 if (fOverrunCount < MAX_USER_TIMER_OVERRUN_COUNT) 221 fOverrunCount++; 222 } 223 } 224 225 // Since we don't use periodic kernel timers, it isn't scheduled anymore. 226 // If the timer is periodic, the derived class' version will schedule it 227 // again. 228 fScheduled = false; 229 } 230 231 232 /*! Updates the start time for a periodic timer after it expired, enforcing 233 sanity limits and updating \c fOverrunCount, if necessary. 234 235 The caller must not hold \c sUserTimerLock. 236 */ 237 void 238 UserTimer::UpdatePeriodicStartTime() 239 { 240 if (fInterval < kMinPeriodicTimerInterval) { 241 bigtime_t skip = (kMinPeriodicTimerInterval + fInterval - 1) / fInterval; 242 fNextTime += skip * fInterval; 243 244 // One interval is the normal advance, so don't consider it skipped. 245 skip--; 246 247 if (skip + fOverrunCount > MAX_USER_TIMER_OVERRUN_COUNT) 248 fOverrunCount = MAX_USER_TIMER_OVERRUN_COUNT; 249 else 250 fOverrunCount += skip; 251 } else 252 fNextTime += fInterval; 253 } 254 255 256 /*! Checks whether the timer start time lies too much in the past and, if so, 257 adjusts it and updates \c fOverrunCount. 258 259 The caller must not hold \c sUserTimerLock. 260 261 \param now The current time. 262 */ 263 void 264 UserTimer::CheckPeriodicOverrun(bigtime_t now) 265 { 266 if (fNextTime + fInterval > now) 267 return; 268 269 // The start time is a full interval or more in the past. Skip those 270 // intervals. 271 bigtime_t skip = (now - fNextTime) / fInterval; 272 fNextTime += skip * fInterval; 273 274 if (skip + fOverrunCount > MAX_USER_TIMER_OVERRUN_COUNT) 275 fOverrunCount = MAX_USER_TIMER_OVERRUN_COUNT; 276 else 277 fOverrunCount += skip; 278 } 279 280 281 void 282 UserTimer::CancelTimer() 283 { 284 ASSERT(fScheduled); 285 286 atomic_set(&fSkip, 1); 287 cancel_timer(&fTimer); 288 atomic_set(&fSkip, 0); 289 } 290 291 292 // #pragma mark - SystemTimeUserTimer 293 294 295 void 296 SystemTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, 297 uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval) 298 { 299 InterruptsWriteSequentialLocker locker(sUserTimerLock); 300 301 // get the current time 302 bigtime_t now = system_time(); 303 304 // Cancel the old timer, if still scheduled, and get the previous values. 305 if (fScheduled) { 306 CancelTimer(); 307 308 _oldRemainingTime = fNextTime - now; 309 _oldInterval = fInterval; 310 311 fScheduled = false; 312 } else { 313 _oldRemainingTime = B_INFINITE_TIMEOUT; 314 _oldInterval = 0; 315 } 316 317 // schedule the new timer 318 fNextTime = nextTime; 319 fInterval = interval; 320 fOverrunCount = 0; 321 322 if (nextTime == B_INFINITE_TIMEOUT) 323 return; 324 325 if ((flags & B_RELATIVE_TIMEOUT) != 0) 326 fNextTime += now; 327 328 ScheduleKernelTimer(now, fInterval > 0); 329 } 330 331 332 void 333 SystemTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval, 334 uint32& _overrunCount) 335 { 336 uint32 count; 337 do { 338 count = acquire_read_seqlock(&sUserTimerLock); 339 340 if (fScheduled) { 341 _remainingTime = fNextTime - system_time(); 342 _interval = fInterval; 343 } else { 344 _remainingTime = B_INFINITE_TIMEOUT; 345 _interval = 0; 346 } 347 348 _overrunCount = fOverrunCount; 349 } while (!release_read_seqlock(&sUserTimerLock, count)); 350 } 351 352 353 void 354 SystemTimeUserTimer::HandleTimer() 355 { 356 UserTimer::HandleTimer(); 357 358 // if periodic, reschedule the kernel timer 359 if (fInterval > 0) { 360 UpdatePeriodicStartTime(); 361 ScheduleKernelTimer(system_time(), true); 362 } 363 } 364 365 366 /*! Schedules the kernel timer. 367 368 The caller must hold \c sUserTimerLock. 369 370 \param now The current system time to be used. 371 \param checkPeriodicOverrun If \c true, calls CheckPeriodicOverrun() first, 372 i.e. the start time will be adjusted to not lie too much in the past. 373 */ 374 void 375 SystemTimeUserTimer::ScheduleKernelTimer(bigtime_t now, 376 bool checkPeriodicOverrun) 377 { 378 // If periodic, check whether the start time is too far in the past. 379 if (checkPeriodicOverrun) 380 CheckPeriodicOverrun(now); 381 382 uint32 timerFlags = B_ONE_SHOT_ABSOLUTE_TIMER 383 | B_TIMER_USE_TIMER_STRUCT_TIMES; 384 385 fTimer.schedule_time = std::max(fNextTime, (bigtime_t)0); 386 fTimer.period = 0; 387 388 add_timer(&fTimer, &HandleTimerHook, fTimer.schedule_time, timerFlags); 389 390 fScheduled = true; 391 } 392 393 394 // #pragma mark - RealTimeUserTimer 395 396 397 void 398 RealTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, 399 uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval) 400 { 401 InterruptsWriteSequentialLocker locker(sUserTimerLock); 402 403 // get the current time 404 bigtime_t now = system_time(); 405 406 // Cancel the old timer, if still scheduled, and get the previous values. 407 if (fScheduled) { 408 CancelTimer(); 409 410 _oldRemainingTime = fNextTime - now; 411 _oldInterval = fInterval; 412 413 if (fAbsolute) { 414 SpinLocker globalListLocker(sAbsoluteRealTimeTimersLock); 415 sAbsoluteRealTimeTimers.Remove(this); 416 } 417 418 fScheduled = false; 419 } else { 420 _oldRemainingTime = B_INFINITE_TIMEOUT; 421 _oldInterval = 0; 422 } 423 424 // schedule the new timer 425 fNextTime = nextTime; 426 fInterval = interval; 427 fOverrunCount = 0; 428 429 if (nextTime == B_INFINITE_TIMEOUT) 430 return; 431 432 fAbsolute = (flags & B_RELATIVE_TIMEOUT) == 0; 433 434 if (fAbsolute) { 435 fRealTimeOffset = rtc_boot_time(); 436 fNextTime -= fRealTimeOffset; 437 438 // If periodic, check whether the start time is too far in the past. 439 if (fInterval > 0) 440 CheckPeriodicOverrun(now); 441 442 // add the absolute timer to the global list 443 SpinLocker globalListLocker(sAbsoluteRealTimeTimersLock); 444 sAbsoluteRealTimeTimers.Insert(this); 445 } else 446 fNextTime += now; 447 448 ScheduleKernelTimer(now, false); 449 } 450 451 452 /*! Called when the real-time clock has been changed. 453 454 The caller must hold \c sUserTimerLock. Optionally the caller may also 455 hold \c sAbsoluteRealTimeTimersLock. 456 */ 457 void 458 RealTimeUserTimer::TimeWarped() 459 { 460 ASSERT(fScheduled && fAbsolute); 461 462 // get the new real-time offset 463 bigtime_t oldRealTimeOffset = fRealTimeOffset; 464 fRealTimeOffset = rtc_boot_time(); 465 if (fRealTimeOffset == oldRealTimeOffset) 466 return; 467 468 // cancel the kernel timer and reschedule it 469 CancelTimer(); 470 471 fNextTime += oldRealTimeOffset - fRealTimeOffset; 472 473 ScheduleKernelTimer(system_time(), fInterval > 0); 474 } 475 476 477 void 478 RealTimeUserTimer::HandleTimer() 479 { 480 SystemTimeUserTimer::HandleTimer(); 481 482 // remove from global list, if no longer scheduled 483 if (!fScheduled && fAbsolute) { 484 SpinLocker globalListLocker(sAbsoluteRealTimeTimersLock); 485 sAbsoluteRealTimeTimers.Remove(this); 486 } 487 } 488 489 490 // #pragma mark - TeamTimeUserTimer 491 492 493 TeamTimeUserTimer::TeamTimeUserTimer(team_id teamID) 494 : 495 fTeamID(teamID), 496 fTeam(NULL) 497 { 498 } 499 500 501 TeamTimeUserTimer::~TeamTimeUserTimer() 502 { 503 ASSERT(fTeam == NULL); 504 } 505 506 507 void 508 TeamTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, 509 uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval) 510 { 511 InterruptsWriteSequentialLocker locker(sUserTimerLock); 512 SpinLocker timeLocker(fTeam != NULL ? &fTeam->time_lock : NULL); 513 514 // get the current time, but only if needed 515 bool nowValid = fTeam != NULL; 516 bigtime_t now = nowValid ? fTeam->CPUTime(false) : 0; 517 518 // Cancel the old timer, if still scheduled, and get the previous values. 519 if (fTeam != NULL) { 520 if (fScheduled) { 521 CancelTimer(); 522 fScheduled = false; 523 } 524 525 _oldRemainingTime = fNextTime - now; 526 _oldInterval = fInterval; 527 528 fTeam->UserTimerDeactivated(this); 529 fTeam->ReleaseReference(); 530 fTeam = NULL; 531 } else { 532 _oldRemainingTime = B_INFINITE_TIMEOUT; 533 _oldInterval = 0; 534 } 535 536 // schedule the new timer 537 fNextTime = nextTime; 538 fInterval = interval; 539 fOverrunCount = 0; 540 541 if (fNextTime == B_INFINITE_TIMEOUT) 542 return; 543 544 // Get the team. If it doesn't exist anymore, just don't schedule the 545 // timer anymore. 546 Team* newTeam = Team::Get(fTeamID); 547 if (newTeam == NULL) { 548 fTeam = NULL; 549 return; 550 } else if (fTeam == NULL) 551 timeLocker.SetTo(newTeam->time_lock, false); 552 fTeam = newTeam; 553 554 fAbsolute = (flags & B_RELATIVE_TIMEOUT) == 0; 555 556 // convert relative to absolute timeouts 557 if (!fAbsolute) { 558 if (!nowValid) 559 now = fTeam->CPUTime(false); 560 fNextTime += now; 561 } 562 563 fTeam->UserTimerActivated(this); 564 565 // schedule/udpate the kernel timer 566 Update(NULL); 567 } 568 569 570 void 571 TeamTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval, 572 uint32& _overrunCount) 573 { 574 uint32 count; 575 do { 576 count = acquire_read_seqlock(&sUserTimerLock); 577 578 if (fTeam != NULL) { 579 InterruptsSpinLocker timeLocker(fTeam->time_lock); 580 _remainingTime = fNextTime - fTeam->CPUTime(false); 581 _interval = fInterval; 582 } else { 583 _remainingTime = B_INFINITE_TIMEOUT; 584 _interval = 0; 585 } 586 587 _overrunCount = fOverrunCount; 588 } while (!release_read_seqlock(&sUserTimerLock, count)); 589 } 590 591 592 /*! Deactivates the timer, if it is activated. 593 594 The caller must hold \c time_lock and \c sUserTimerLock. 595 */ 596 void 597 TeamTimeUserTimer::Deactivate() 598 { 599 if (fTeam == NULL) 600 return; 601 602 // unschedule, if scheduled 603 if (fScheduled) { 604 CancelTimer(); 605 fScheduled = false; 606 } 607 608 // deactivate 609 fTeam->UserTimerDeactivated(this); 610 fTeam->ReleaseReference(); 611 fTeam = NULL; 612 } 613 614 615 /*! Starts/stops the timer as necessary, if it is active. 616 617 Called whenever threads of the team whose CPU time is referred to by the 618 timer are scheduled or unscheduled (or leave the team), or when the timer 619 was just set. Schedules a kernel timer for the remaining time, respectively 620 cancels it. 621 622 The caller must hold \c time_lock and \c sUserTimerLock. 623 624 \param unscheduledThread If not \c NULL, this is the thread that is 625 currently running and which is in the process of being unscheduled. 626 */ 627 void 628 TeamTimeUserTimer::Update(Thread* unscheduledThread, Thread* lockedThread) 629 { 630 if (fTeam == NULL) 631 return; 632 633 // determine how many of the team's threads are currently running 634 fRunningThreads = 0; 635 int32 cpuCount = smp_get_num_cpus(); 636 for (int32 i = 0; i < cpuCount; i++) { 637 Thread* thread = gCPU[i].running_thread; 638 if (thread != unscheduledThread && thread->team == fTeam) 639 fRunningThreads++; 640 } 641 642 _Update(unscheduledThread != NULL, lockedThread); 643 } 644 645 646 /*! Called when the team's CPU time clock which this timer refers to has been 647 set. 648 649 The caller must hold \c time_lock and \c sUserTimerLock. 650 651 \param changedBy The value by which the clock has changed. 652 */ 653 void 654 TeamTimeUserTimer::TimeWarped(bigtime_t changedBy) 655 { 656 if (fTeam == NULL || changedBy == 0) 657 return; 658 659 // If this is a relative timer, adjust fNextTime by the value the clock has 660 // changed. 661 if (!fAbsolute) 662 fNextTime += changedBy; 663 664 // reschedule the kernel timer 665 _Update(false); 666 } 667 668 669 void 670 TeamTimeUserTimer::HandleTimer() 671 { 672 UserTimer::HandleTimer(); 673 674 // If the timer is not periodic, it is no longer active. Otherwise 675 // reschedule the kernel timer. 676 if (fTeam != NULL) { 677 if (fInterval == 0) { 678 fTeam->UserTimerDeactivated(this); 679 fTeam->ReleaseReference(); 680 fTeam = NULL; 681 } else { 682 UpdatePeriodicStartTime(); 683 _Update(false); 684 } 685 } 686 } 687 688 689 /*! Schedules/cancels the kernel timer as necessary. 690 691 \c fRunningThreads must be up-to-date. 692 The caller must hold \c time_lock and \c sUserTimerLock. 693 694 \param unscheduling \c true, when the current thread is in the process of 695 being unscheduled. 696 */ 697 void 698 TeamTimeUserTimer::_Update(bool unscheduling, Thread* lockedThread) 699 { 700 // unschedule the kernel timer, if scheduled 701 if (fScheduled) 702 CancelTimer(); 703 704 // if no more threads are running, we're done 705 if (fRunningThreads == 0) { 706 fScheduled = false; 707 return; 708 } 709 710 // There are still threads running. Reschedule the kernel timer. 711 bigtime_t now = fTeam->CPUTime(unscheduling, lockedThread); 712 713 // If periodic, check whether the start time is too far in the past. 714 if (fInterval > 0) 715 CheckPeriodicOverrun(now); 716 717 if (fNextTime > now) { 718 fTimer.schedule_time = system_time() 719 + (fNextTime - now + fRunningThreads - 1) / fRunningThreads; 720 // check for overflow 721 if (fTimer.schedule_time < 0) 722 fTimer.schedule_time = B_INFINITE_TIMEOUT; 723 } else 724 fTimer.schedule_time = 0; 725 fTimer.period = 0; 726 // We reschedule periodic timers manually in HandleTimer() to avoid 727 // rounding errors. 728 729 add_timer(&fTimer, &HandleTimerHook, fTimer.schedule_time, 730 B_ONE_SHOT_ABSOLUTE_TIMER | B_TIMER_USE_TIMER_STRUCT_TIMES); 731 // We use B_TIMER_USE_TIMER_STRUCT_TIMES, so period remains 0, which 732 // our base class expects. 733 734 fScheduled = true; 735 } 736 737 738 // #pragma mark - TeamUserTimeUserTimer 739 740 741 TeamUserTimeUserTimer::TeamUserTimeUserTimer(team_id teamID) 742 : 743 fTeamID(teamID), 744 fTeam(NULL) 745 { 746 } 747 748 749 TeamUserTimeUserTimer::~TeamUserTimeUserTimer() 750 { 751 ASSERT(fTeam == NULL); 752 } 753 754 755 void 756 TeamUserTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, 757 uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval) 758 { 759 InterruptsWriteSequentialLocker locker(sUserTimerLock); 760 SpinLocker timeLocker(fTeam != NULL ? &fTeam->time_lock : NULL); 761 762 // get the current time, but only if needed 763 bool nowValid = fTeam != NULL; 764 bigtime_t now = nowValid ? fTeam->UserCPUTime() : 0; 765 766 // Cancel the old timer, if still active, and get the previous values. 767 if (fTeam != NULL) { 768 _oldRemainingTime = fNextTime - now; 769 _oldInterval = fInterval; 770 771 fTeam->UserTimerDeactivated(this); 772 fTeam->ReleaseReference(); 773 fTeam = NULL; 774 } else { 775 _oldRemainingTime = B_INFINITE_TIMEOUT; 776 _oldInterval = 0; 777 } 778 779 // schedule the new timer 780 fNextTime = nextTime; 781 fInterval = interval; 782 fOverrunCount = 0; 783 784 if (fNextTime == B_INFINITE_TIMEOUT) 785 return; 786 787 // Get the team. If it doesn't exist anymore, just don't schedule the 788 // timer anymore. 789 Team* newTeam = Team::Get(fTeamID); 790 if (newTeam == NULL) { 791 fTeam = NULL; 792 return; 793 } else if (fTeam == NULL) 794 timeLocker.SetTo(newTeam->time_lock, false); 795 fTeam = newTeam; 796 797 // convert relative to absolute timeouts 798 if ((flags & B_RELATIVE_TIMEOUT) != 0) { 799 if (!nowValid) 800 now = fTeam->CPUTime(false); 801 fNextTime += now; 802 } 803 804 fTeam->UserTimerActivated(this); 805 806 // fire the event, if already timed out 807 Check(); 808 } 809 810 811 void 812 TeamUserTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval, 813 uint32& _overrunCount) 814 { 815 uint32 count; 816 do { 817 count = acquire_read_seqlock(&sUserTimerLock); 818 819 if (fTeam != NULL) { 820 InterruptsSpinLocker timeLocker(fTeam->time_lock); 821 _remainingTime = fNextTime - fTeam->UserCPUTime(); 822 _interval = fInterval; 823 } else { 824 _remainingTime = B_INFINITE_TIMEOUT; 825 _interval = 0; 826 } 827 828 _overrunCount = fOverrunCount; 829 } while (!release_read_seqlock(&sUserTimerLock, count)); 830 } 831 832 833 /*! Deactivates the timer, if it is activated. 834 835 The caller must hold \c time_lock and \c sUserTimerLock. 836 */ 837 void 838 TeamUserTimeUserTimer::Deactivate() 839 { 840 if (fTeam == NULL) 841 return; 842 843 // deactivate 844 fTeam->UserTimerDeactivated(this); 845 fTeam->ReleaseReference(); 846 fTeam = NULL; 847 } 848 849 850 /*! Checks whether the timer is up, firing an event, if so. 851 852 The caller must hold \c time_lock and \c sUserTimerLock. 853 */ 854 void 855 TeamUserTimeUserTimer::Check() 856 { 857 if (fTeam == NULL) 858 return; 859 860 // check whether we need to fire the event yet 861 bigtime_t now = fTeam->UserCPUTime(); 862 if (now < fNextTime) 863 return; 864 865 HandleTimer(); 866 867 // If the timer is not periodic, it is no longer active. Otherwise compute 868 // the event time. 869 if (fInterval == 0) { 870 fTeam->UserTimerDeactivated(this); 871 fTeam->ReleaseReference(); 872 fTeam = NULL; 873 return; 874 } 875 876 // First validate fNextTime, then increment it, so that fNextTime is > now 877 // (CheckPeriodicOverrun() only makes it > now - fInterval). 878 CheckPeriodicOverrun(now); 879 fNextTime += fInterval; 880 fScheduled = true; 881 } 882 883 884 // #pragma mark - ThreadTimeUserTimer 885 886 887 ThreadTimeUserTimer::ThreadTimeUserTimer(thread_id threadID) 888 : 889 fThreadID(threadID), 890 fThread(NULL) 891 { 892 } 893 894 895 ThreadTimeUserTimer::~ThreadTimeUserTimer() 896 { 897 ASSERT(fThread == NULL); 898 } 899 900 901 void 902 ThreadTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval, 903 uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval) 904 { 905 InterruptsWriteSequentialLocker locker(sUserTimerLock); 906 SpinLocker timeLocker(fThread->time_lock); 907 908 // get the current time, but only if needed 909 bool nowValid = fThread != NULL; 910 bigtime_t now = nowValid ? fThread->CPUTime(false) : 0; 911 912 // Cancel the old timer, if still scheduled, and get the previous values. 913 if (fThread != NULL) { 914 if (fScheduled) { 915 CancelTimer(); 916 fScheduled = false; 917 } 918 919 _oldRemainingTime = fNextTime - now; 920 _oldInterval = fInterval; 921 922 fThread->UserTimerDeactivated(this); 923 fThread->ReleaseReference(); 924 fThread = NULL; 925 } else { 926 _oldRemainingTime = B_INFINITE_TIMEOUT; 927 _oldInterval = 0; 928 } 929 930 // schedule the new timer 931 fNextTime = nextTime; 932 fInterval = interval; 933 fOverrunCount = 0; 934 935 if (fNextTime == B_INFINITE_TIMEOUT) 936 return; 937 938 // Get the thread. If it doesn't exist anymore, just don't schedule the 939 // timer anymore. 940 Thread* newThread = Thread::Get(fThreadID); 941 if (newThread == NULL) { 942 fThread = NULL; 943 return; 944 } else if (fThread == NULL) 945 timeLocker.SetTo(newThread->time_lock, false); 946 fThread = newThread; 947 948 fAbsolute = (flags & B_RELATIVE_TIMEOUT) == 0; 949 950 // convert relative to absolute timeouts 951 if (!fAbsolute) { 952 if (!nowValid) 953 now = fThread->CPUTime(false); 954 fNextTime += now; 955 } 956 957 fThread->UserTimerActivated(this); 958 959 // If the thread is currently running, also schedule a kernel timer. 960 if (fThread->cpu != NULL) 961 Start(); 962 } 963 964 965 void 966 ThreadTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval, 967 uint32& _overrunCount) 968 { 969 uint32 count; 970 do { 971 count = acquire_read_seqlock(&sUserTimerLock); 972 973 if (fThread != NULL) { 974 SpinLocker timeLocker(fThread->time_lock); 975 _remainingTime = fNextTime - fThread->CPUTime(false); 976 _interval = fInterval; 977 } else { 978 _remainingTime = B_INFINITE_TIMEOUT; 979 _interval = 0; 980 } 981 982 _overrunCount = fOverrunCount; 983 } while (!release_read_seqlock(&sUserTimerLock, count)); 984 } 985 986 987 /*! Deactivates the timer, if it is activated. 988 989 The caller must hold \c time_lock and \c sUserTimerLock. 990 */ 991 void 992 ThreadTimeUserTimer::Deactivate() 993 { 994 if (fThread == NULL) 995 return; 996 997 // unschedule, if scheduled 998 if (fScheduled) { 999 CancelTimer(); 1000 fScheduled = false; 1001 } 1002 1003 // deactivate 1004 fThread->UserTimerDeactivated(this); 1005 fThread->ReleaseReference(); 1006 fThread = NULL; 1007 } 1008 1009 1010 /*! Starts the timer, if it is active. 1011 1012 Called when the thread whose CPU time is referred to by the timer is 1013 scheduled, or, when the timer was just set and the thread is already 1014 running. Schedules a kernel timer for the remaining time. 1015 1016 The caller must hold \c time_lock and \c sUserTimerLock. 1017 */ 1018 void 1019 ThreadTimeUserTimer::Start() 1020 { 1021 if (fThread == NULL) 1022 return; 1023 1024 ASSERT(!fScheduled); 1025 1026 // add the kernel timer 1027 bigtime_t now = fThread->CPUTime(false); 1028 1029 // If periodic, check whether the start time is too far in the past. 1030 if (fInterval > 0) 1031 CheckPeriodicOverrun(now); 1032 1033 if (fNextTime > now) { 1034 fTimer.schedule_time = system_time() + fNextTime - now; 1035 // check for overflow 1036 if (fTimer.schedule_time < 0) 1037 fTimer.schedule_time = B_INFINITE_TIMEOUT; 1038 } else 1039 fTimer.schedule_time = 0; 1040 fTimer.period = 0; 1041 1042 uint32 flags = B_ONE_SHOT_ABSOLUTE_TIMER | B_TIMER_USE_TIMER_STRUCT_TIMES; 1043 add_timer(&fTimer, &HandleTimerHook, fTimer.schedule_time, flags); 1044 1045 fScheduled = true; 1046 } 1047 1048 1049 /*! Stops the timer, if it is active. 1050 1051 Called when the thread whose CPU time is referred to by the timer is 1052 unscheduled, or, when the timer is canceled. 1053 1054 The caller must hold \c sUserTimerLock. 1055 */ 1056 void 1057 ThreadTimeUserTimer::Stop() 1058 { 1059 if (fThread == NULL) 1060 return; 1061 1062 ASSERT(fScheduled); 1063 1064 // cancel the kernel timer 1065 CancelTimer(); 1066 fScheduled = false; 1067 1068 // TODO: To avoid odd race conditions, we should check the current time of 1069 // the thread (ignoring the time since last_time) and manually fire the 1070 // user event, if necessary. 1071 } 1072 1073 1074 /*! Called when the team's CPU time clock which this timer refers to has been 1075 set. 1076 1077 The caller must hold \c time_lock and \c sUserTimerLock. 1078 1079 \param changedBy The value by which the clock has changed. 1080 */ 1081 void 1082 ThreadTimeUserTimer::TimeWarped(bigtime_t changedBy) 1083 { 1084 if (fThread == NULL || changedBy == 0) 1085 return; 1086 1087 // If this is a relative timer, adjust fNextTime by the value the clock has 1088 // changed. 1089 if (!fAbsolute) 1090 fNextTime += changedBy; 1091 1092 // reschedule the kernel timer 1093 if (fScheduled) { 1094 Stop(); 1095 Start(); 1096 } 1097 } 1098 1099 1100 void 1101 ThreadTimeUserTimer::HandleTimer() 1102 { 1103 UserTimer::HandleTimer(); 1104 1105 if (fThread != NULL) { 1106 // If the timer is periodic, reschedule the kernel timer. Otherwise it 1107 // is no longer active. 1108 if (fInterval > 0) { 1109 UpdatePeriodicStartTime(); 1110 Start(); 1111 } else { 1112 fThread->UserTimerDeactivated(this); 1113 fThread->ReleaseReference(); 1114 fThread = NULL; 1115 } 1116 } 1117 } 1118 1119 1120 // #pragma mark - UserTimerList 1121 1122 1123 UserTimerList::UserTimerList() 1124 { 1125 } 1126 1127 1128 UserTimerList::~UserTimerList() 1129 { 1130 ASSERT(fTimers.IsEmpty()); 1131 } 1132 1133 1134 /*! Returns the user timer with the given ID. 1135 1136 \param id The timer's ID 1137 \return The user timer with the given ID or \c NULL, if there is no such 1138 timer. 1139 */ 1140 UserTimer* 1141 UserTimerList::TimerFor(int32 id) const 1142 { 1143 // TODO: Use a more efficient data structure. E.g. a sorted array. 1144 for (TimerList::ConstIterator it = fTimers.GetIterator(); 1145 UserTimer* timer = it.Next();) { 1146 if (timer->ID() == id) 1147 return timer; 1148 } 1149 1150 return NULL; 1151 } 1152 1153 1154 /*! Adds the given user timer and assigns it an ID. 1155 1156 \param timer The timer to be added. 1157 */ 1158 void 1159 UserTimerList::AddTimer(UserTimer* timer) 1160 { 1161 int32 id = timer->ID(); 1162 if (id < 0) { 1163 // user-defined timer -- find an usused ID 1164 id = USER_TIMER_FIRST_USER_DEFINED_ID; 1165 UserTimer* insertAfter = NULL; 1166 for (TimerList::Iterator it = fTimers.GetIterator(); 1167 UserTimer* other = it.Next();) { 1168 if (other->ID() > id) 1169 break; 1170 if (other->ID() == id) 1171 id++; 1172 insertAfter = other; 1173 } 1174 1175 // insert the timer 1176 timer->SetID(id); 1177 fTimers.InsertAfter(insertAfter, timer); 1178 } else { 1179 // default timer -- find the insertion point 1180 UserTimer* insertAfter = NULL; 1181 for (TimerList::Iterator it = fTimers.GetIterator(); 1182 UserTimer* other = it.Next();) { 1183 if (other->ID() > id) 1184 break; 1185 if (other->ID() == id) { 1186 panic("UserTimerList::AddTimer(): timer with ID %" B_PRId32 1187 " already exists!", id); 1188 } 1189 insertAfter = other; 1190 } 1191 1192 // insert the timer 1193 fTimers.InsertAfter(insertAfter, timer); 1194 } 1195 } 1196 1197 1198 /*! Deletes all (or all user-defined) user timers. 1199 1200 \param userDefinedOnly If \c true, only the user-defined timers are deleted, 1201 otherwise all timers are deleted. 1202 \return The number of user-defined timers that were removed and deleted. 1203 */ 1204 int32 1205 UserTimerList::DeleteTimers(bool userDefinedOnly) 1206 { 1207 int32 userDefinedCount = 0; 1208 1209 for (TimerList::Iterator it = fTimers.GetIterator(); 1210 UserTimer* timer = it.Next();) { 1211 if (timer->ID() < USER_TIMER_FIRST_USER_DEFINED_ID) { 1212 if (userDefinedOnly) 1213 continue; 1214 } else 1215 userDefinedCount++; 1216 1217 // remove, cancel, and delete the timer 1218 it.Remove(); 1219 timer->Cancel(); 1220 delete timer; 1221 } 1222 1223 return userDefinedCount; 1224 } 1225 1226 1227 // #pragma mark - private 1228 1229 1230 static int32 1231 create_timer(clockid_t clockID, int32 timerID, Team* team, Thread* thread, 1232 uint32 flags, const struct sigevent& event, 1233 ThreadCreationAttributes* threadAttributes, bool isDefaultEvent) 1234 { 1235 // create the timer object 1236 UserTimer* timer; 1237 switch (clockID) { 1238 case CLOCK_MONOTONIC: 1239 timer = new(std::nothrow) SystemTimeUserTimer; 1240 break; 1241 1242 case CLOCK_REALTIME: 1243 timer = new(std::nothrow) RealTimeUserTimer; 1244 break; 1245 1246 case CLOCK_THREAD_CPUTIME_ID: 1247 timer = new(std::nothrow) ThreadTimeUserTimer( 1248 thread_get_current_thread()->id); 1249 break; 1250 1251 case CLOCK_PROCESS_CPUTIME_ID: 1252 if (team == NULL) 1253 return B_BAD_VALUE; 1254 timer = new(std::nothrow) TeamTimeUserTimer(team->id); 1255 break; 1256 1257 case CLOCK_PROCESS_USER_CPUTIME_ID: 1258 if (team == NULL) 1259 return B_BAD_VALUE; 1260 timer = new(std::nothrow) TeamUserTimeUserTimer(team->id); 1261 break; 1262 1263 default: 1264 { 1265 // The clock ID is a ID of the team whose CPU time the clock refers 1266 // to. Check whether the team exists and we have permission to 1267 // access its clock. 1268 if (clockID <= 0) 1269 return B_BAD_VALUE; 1270 if (clockID == team_get_kernel_team_id()) 1271 return B_NOT_ALLOWED; 1272 1273 Team* timedTeam = Team::GetAndLock(clockID); 1274 if (timedTeam == NULL) 1275 return B_BAD_VALUE; 1276 1277 uid_t uid = geteuid(); 1278 uid_t teamUID = timedTeam->effective_uid; 1279 1280 timedTeam->UnlockAndReleaseReference(); 1281 1282 if (uid != 0 && uid != teamUID) 1283 return B_NOT_ALLOWED; 1284 1285 timer = new(std::nothrow) TeamTimeUserTimer(clockID); 1286 break; 1287 } 1288 } 1289 1290 if (timer == NULL) 1291 return B_NO_MEMORY; 1292 ObjectDeleter<UserTimer> timerDeleter(timer); 1293 1294 if (timerID >= 0) 1295 timer->SetID(timerID); 1296 1297 SignalEvent* signalEvent = NULL; 1298 1299 switch (event.sigev_notify) { 1300 case SIGEV_NONE: 1301 // the timer's event remains NULL 1302 break; 1303 1304 case SIGEV_SIGNAL: 1305 { 1306 if (event.sigev_signo <= 0 || event.sigev_signo > MAX_SIGNAL_NUMBER) 1307 return B_BAD_VALUE; 1308 1309 if (thread != NULL && (flags & USER_TIMER_SIGNAL_THREAD) != 0) { 1310 // The signal shall be sent to the thread. 1311 signalEvent = ThreadSignalEvent::Create(thread, 1312 event.sigev_signo, SI_TIMER, 0, team->id); 1313 } else { 1314 // The signal shall be sent to the team. 1315 signalEvent = TeamSignalEvent::Create(team, event.sigev_signo, 1316 SI_TIMER, 0); 1317 } 1318 1319 if (signalEvent == NULL) 1320 return B_NO_MEMORY; 1321 1322 timer->SetEvent(signalEvent); 1323 break; 1324 } 1325 1326 case SIGEV_THREAD: 1327 { 1328 if (threadAttributes == NULL) 1329 return B_BAD_VALUE; 1330 1331 CreateThreadEvent* event 1332 = CreateThreadEvent::Create(*threadAttributes); 1333 if (event == NULL) 1334 return B_NO_MEMORY; 1335 1336 timer->SetEvent(event); 1337 break; 1338 } 1339 1340 default: 1341 return B_BAD_VALUE; 1342 } 1343 1344 // add it to the team/thread 1345 TimerLocker timerLocker; 1346 timerLocker.Lock(team, thread); 1347 1348 status_t error = thread != NULL 1349 ? thread->AddUserTimer(timer) : team->AddUserTimer(timer); 1350 if (error != B_OK) 1351 return error; 1352 1353 // set a signal event's user value 1354 if (signalEvent != NULL) { 1355 // If no sigevent structure was given, use the timer ID. 1356 union sigval signalValue = event.sigev_value; 1357 if (isDefaultEvent) 1358 signalValue.sival_int = timer->ID(); 1359 1360 signalEvent->SetUserValue(signalValue); 1361 } 1362 1363 return timerDeleter.Detach()->ID(); 1364 } 1365 1366 1367 /*! Called when the CPU time clock of the given thread has been set. 1368 1369 The caller must hold \c time_lock. 1370 1371 \param thread The thread whose CPU time clock has been set. 1372 \param changedBy The value by which the CPU time clock has changed 1373 (new = old + changedBy). 1374 */ 1375 static void 1376 thread_clock_changed(Thread* thread, bigtime_t changedBy) 1377 { 1378 for (ThreadTimeUserTimerList::ConstIterator it 1379 = thread->CPUTimeUserTimerIterator(); 1380 ThreadTimeUserTimer* timer = it.Next();) { 1381 timer->TimeWarped(changedBy); 1382 } 1383 } 1384 1385 1386 /*! Called when the CPU time clock of the given team has been set. 1387 1388 The caller must hold \c time_lock. 1389 1390 \param team The team whose CPU time clock has been set. 1391 \param changedBy The value by which the CPU time clock has changed 1392 (new = old + changedBy). 1393 */ 1394 static void 1395 team_clock_changed(Team* team, bigtime_t changedBy) 1396 { 1397 for (TeamTimeUserTimerList::ConstIterator it 1398 = team->CPUTimeUserTimerIterator(); 1399 TeamTimeUserTimer* timer = it.Next();) { 1400 timer->TimeWarped(changedBy); 1401 } 1402 } 1403 1404 1405 // #pragma mark - kernel private 1406 1407 1408 /*! Creates the pre-defined user timers for the given thread. 1409 The thread may not have been added to its team yet, hence the team must be 1410 passed 1411 1412 \param team The thread's (future) team. 1413 \param thread The thread whose pre-defined timers shall be created. 1414 \return \c B_OK, when everything when fine, another error code otherwise. 1415 */ 1416 status_t 1417 user_timer_create_thread_timers(Team* team, Thread* thread) 1418 { 1419 // create a real time user timer 1420 struct sigevent event; 1421 event.sigev_notify = SIGEV_SIGNAL; 1422 event.sigev_signo = SIGALRM; 1423 1424 int32 timerID = create_timer(CLOCK_MONOTONIC, USER_TIMER_REAL_TIME_ID, 1425 team, thread, USER_TIMER_SIGNAL_THREAD, event, NULL, true); 1426 if (timerID < 0) 1427 return timerID; 1428 1429 return B_OK; 1430 } 1431 1432 1433 /*! Creates the pre-defined user timers for the given team. 1434 1435 \param team The team whose pre-defined timers shall be created. 1436 \return \c B_OK, when everything when fine, another error code otherwise. 1437 */ 1438 status_t 1439 user_timer_create_team_timers(Team* team) 1440 { 1441 // create a real time user timer 1442 struct sigevent event; 1443 event.sigev_notify = SIGEV_SIGNAL; 1444 event.sigev_signo = SIGALRM; 1445 1446 int32 timerID = create_timer(CLOCK_MONOTONIC, USER_TIMER_REAL_TIME_ID, 1447 team, NULL, 0, event, NULL, true); 1448 if (timerID < 0) 1449 return timerID; 1450 1451 // create a total CPU time user timer 1452 event.sigev_notify = SIGEV_SIGNAL; 1453 event.sigev_signo = SIGPROF; 1454 1455 timerID = create_timer(CLOCK_PROCESS_CPUTIME_ID, 1456 USER_TIMER_TEAM_TOTAL_TIME_ID, team, NULL, 0, event, NULL, true); 1457 if (timerID < 0) 1458 return timerID; 1459 1460 // create a user CPU time user timer 1461 event.sigev_notify = SIGEV_SIGNAL; 1462 event.sigev_signo = SIGVTALRM; 1463 1464 timerID = create_timer(CLOCK_PROCESS_USER_CPUTIME_ID, 1465 USER_TIMER_TEAM_USER_TIME_ID, team, NULL, 0, event, NULL, true); 1466 if (timerID < 0) 1467 return timerID; 1468 1469 return B_OK; 1470 } 1471 1472 1473 status_t 1474 user_timer_get_clock(clockid_t clockID, bigtime_t& _time) 1475 { 1476 switch (clockID) { 1477 case CLOCK_MONOTONIC: 1478 _time = system_time(); 1479 return B_OK; 1480 1481 case CLOCK_REALTIME: 1482 _time = real_time_clock_usecs(); 1483 return B_OK; 1484 1485 case CLOCK_THREAD_CPUTIME_ID: 1486 { 1487 Thread* thread = thread_get_current_thread(); 1488 InterruptsSpinLocker timeLocker(thread->time_lock); 1489 _time = thread->CPUTime(false); 1490 return B_OK; 1491 } 1492 1493 case CLOCK_PROCESS_USER_CPUTIME_ID: 1494 { 1495 Team* team = thread_get_current_thread()->team; 1496 InterruptsSpinLocker timeLocker(team->time_lock); 1497 _time = team->UserCPUTime(); 1498 return B_OK; 1499 } 1500 1501 case CLOCK_PROCESS_CPUTIME_ID: 1502 default: 1503 { 1504 // get the ID of the target team (or the respective placeholder) 1505 team_id teamID; 1506 if (clockID == CLOCK_PROCESS_CPUTIME_ID) { 1507 teamID = B_CURRENT_TEAM; 1508 } else { 1509 if (clockID < 0) 1510 return B_BAD_VALUE; 1511 if (clockID == team_get_kernel_team_id()) 1512 return B_NOT_ALLOWED; 1513 1514 teamID = clockID; 1515 } 1516 1517 // get the team 1518 Team* team = Team::Get(teamID); 1519 if (team == NULL) 1520 return B_BAD_VALUE; 1521 BReference<Team> teamReference(team, true); 1522 1523 // get the time 1524 InterruptsSpinLocker timeLocker(team->time_lock); 1525 _time = team->CPUTime(false); 1526 1527 return B_OK; 1528 } 1529 } 1530 } 1531 1532 1533 void 1534 user_timer_real_time_clock_changed() 1535 { 1536 // we need to update all absolute real-time timers 1537 InterruptsWriteSequentialLocker locker(sUserTimerLock); 1538 SpinLocker globalListLocker(sAbsoluteRealTimeTimersLock); 1539 1540 for (RealTimeUserTimerList::Iterator it 1541 = sAbsoluteRealTimeTimers.GetIterator(); 1542 RealTimeUserTimer* timer = it.Next();) { 1543 timer->TimeWarped(); 1544 } 1545 } 1546 1547 1548 void 1549 user_timer_stop_cpu_timers(Thread* thread, Thread* nextThread) 1550 { 1551 // stop thread timers 1552 for (ThreadTimeUserTimerList::ConstIterator it 1553 = thread->CPUTimeUserTimerIterator(); 1554 ThreadTimeUserTimer* timer = it.Next();) { 1555 timer->Stop(); 1556 } 1557 1558 // update team timers 1559 if (nextThread == NULL || nextThread->team != thread->team) { 1560 for (TeamTimeUserTimerList::ConstIterator it 1561 = thread->team->CPUTimeUserTimerIterator(); 1562 TeamTimeUserTimer* timer = it.Next();) { 1563 timer->Update(thread, thread); 1564 } 1565 } 1566 } 1567 1568 1569 void 1570 user_timer_continue_cpu_timers(Thread* thread, Thread* previousThread) 1571 { 1572 // update team timers 1573 if (previousThread == NULL || previousThread->team != thread->team) { 1574 for (TeamTimeUserTimerList::ConstIterator it 1575 = thread->team->CPUTimeUserTimerIterator(); 1576 TeamTimeUserTimer* timer = it.Next();) { 1577 timer->Update(NULL, thread); 1578 } 1579 } 1580 1581 // start thread timers 1582 for (ThreadTimeUserTimerList::ConstIterator it 1583 = thread->CPUTimeUserTimerIterator(); 1584 ThreadTimeUserTimer* timer = it.Next();) { 1585 timer->Start(); 1586 } 1587 } 1588 1589 1590 void 1591 user_timer_check_team_user_timers(Team* team) 1592 { 1593 for (TeamUserTimeUserTimerList::ConstIterator it 1594 = team->UserTimeUserTimerIterator(); 1595 TeamUserTimeUserTimer* timer = it.Next();) { 1596 timer->Check(); 1597 } 1598 } 1599 1600 1601 // #pragma mark - syscalls 1602 1603 1604 status_t 1605 _user_get_clock(clockid_t clockID, bigtime_t* userTime) 1606 { 1607 // get the time 1608 bigtime_t time; 1609 status_t error = user_timer_get_clock(clockID, time); 1610 if (error != B_OK) 1611 return error; 1612 1613 // copy the value back to userland 1614 if (userTime == NULL || !IS_USER_ADDRESS(userTime) 1615 || user_memcpy(userTime, &time, sizeof(time)) != B_OK) { 1616 return B_BAD_ADDRESS; 1617 } 1618 1619 return B_OK; 1620 } 1621 1622 1623 status_t 1624 _user_set_clock(clockid_t clockID, bigtime_t time) 1625 { 1626 switch (clockID) { 1627 case CLOCK_MONOTONIC: 1628 return B_BAD_VALUE; 1629 1630 case CLOCK_REALTIME: 1631 // only root may set the time 1632 if (geteuid() != 0) 1633 return B_NOT_ALLOWED; 1634 1635 set_real_time_clock_usecs(time); 1636 return B_OK; 1637 1638 case CLOCK_THREAD_CPUTIME_ID: 1639 { 1640 Thread* thread = thread_get_current_thread(); 1641 InterruptsSpinLocker timeLocker(thread->time_lock); 1642 bigtime_t diff = time - thread->CPUTime(false); 1643 thread->cpu_clock_offset += diff; 1644 1645 thread_clock_changed(thread, diff); 1646 return B_OK; 1647 } 1648 1649 case CLOCK_PROCESS_USER_CPUTIME_ID: 1650 // not supported -- this clock is an Haiku-internal extension 1651 return B_BAD_VALUE; 1652 1653 case CLOCK_PROCESS_CPUTIME_ID: 1654 default: 1655 { 1656 // get the ID of the target team (or the respective placeholder) 1657 team_id teamID; 1658 if (clockID == CLOCK_PROCESS_CPUTIME_ID) { 1659 teamID = B_CURRENT_TEAM; 1660 } else { 1661 if (clockID < 0) 1662 return B_BAD_VALUE; 1663 if (clockID == team_get_kernel_team_id()) 1664 return B_NOT_ALLOWED; 1665 1666 teamID = clockID; 1667 } 1668 1669 // get the team 1670 Team* team = Team::Get(teamID); 1671 if (team == NULL) 1672 return B_BAD_VALUE; 1673 BReference<Team> teamReference(team, true); 1674 1675 // set the time offset 1676 InterruptsSpinLocker timeLocker(team->time_lock); 1677 bigtime_t diff = time - team->CPUTime(false); 1678 team->cpu_clock_offset += diff; 1679 1680 team_clock_changed(team, diff); 1681 return B_OK; 1682 } 1683 } 1684 1685 return B_OK; 1686 } 1687 1688 1689 int32 1690 _user_create_timer(clockid_t clockID, thread_id threadID, uint32 flags, 1691 const struct sigevent* userEvent, 1692 const thread_creation_attributes* userThreadAttributes) 1693 { 1694 // copy the sigevent structure from userland 1695 struct sigevent event; 1696 if (userEvent != NULL) { 1697 if (!IS_USER_ADDRESS(userEvent) 1698 || user_memcpy(&event, userEvent, sizeof(event)) != B_OK) { 1699 return B_BAD_ADDRESS; 1700 } 1701 } else { 1702 // none given -- use defaults 1703 event.sigev_notify = SIGEV_SIGNAL; 1704 event.sigev_signo = SIGALRM; 1705 } 1706 1707 // copy thread creation attributes from userland, if specified 1708 char nameBuffer[B_OS_NAME_LENGTH]; 1709 ThreadCreationAttributes threadAttributes; 1710 if (event.sigev_notify == SIGEV_THREAD) { 1711 status_t error = threadAttributes.InitFromUserAttributes( 1712 userThreadAttributes, nameBuffer); 1713 if (error != B_OK) 1714 return error; 1715 } 1716 1717 // get team and thread 1718 Team* team = thread_get_current_thread()->team; 1719 Thread* thread = NULL; 1720 if (threadID >= 0) { 1721 thread = Thread::GetAndLock(threadID); 1722 if (thread == NULL) 1723 return B_BAD_THREAD_ID; 1724 1725 thread->Unlock(); 1726 } 1727 BReference<Thread> threadReference(thread, true); 1728 1729 // create the timer 1730 return create_timer(clockID, -1, team, thread, flags, event, 1731 userThreadAttributes != NULL ? &threadAttributes : NULL, 1732 userEvent == NULL); 1733 } 1734 1735 1736 status_t 1737 _user_delete_timer(int32 timerID, thread_id threadID) 1738 { 1739 // can only delete user-defined timers 1740 if (timerID < USER_TIMER_FIRST_USER_DEFINED_ID) 1741 return B_BAD_VALUE; 1742 1743 // get the timer 1744 TimerLocker timerLocker; 1745 UserTimer* timer; 1746 status_t error = timerLocker.LockAndGetTimer(threadID, timerID, timer); 1747 if (error != B_OK) 1748 return error; 1749 1750 // cancel, remove, and delete it 1751 timer->Cancel(); 1752 1753 if (threadID >= 0) 1754 timerLocker.thread->RemoveUserTimer(timer); 1755 else 1756 timerLocker.team->RemoveUserTimer(timer); 1757 1758 delete timer; 1759 1760 return B_OK; 1761 } 1762 1763 1764 status_t 1765 _user_get_timer(int32 timerID, thread_id threadID, 1766 struct user_timer_info* userInfo) 1767 { 1768 // get the timer 1769 TimerLocker timerLocker; 1770 UserTimer* timer; 1771 status_t error = timerLocker.LockAndGetTimer(threadID, timerID, timer); 1772 if (error != B_OK) 1773 return error; 1774 1775 // get the info 1776 user_timer_info info; 1777 timer->GetInfo(info.remaining_time, info.interval, info.overrun_count); 1778 1779 // Sanitize remaining_time. If it's <= 0, we set it to 1, the least valid 1780 // value. 1781 if (info.remaining_time <= 0) 1782 info.remaining_time = 1; 1783 1784 timerLocker.Unlock(); 1785 1786 // copy it back to userland 1787 if (userInfo != NULL 1788 && (!IS_USER_ADDRESS(userInfo) 1789 || user_memcpy(userInfo, &info, sizeof(info)) != B_OK)) { 1790 return B_BAD_ADDRESS; 1791 } 1792 1793 return B_OK; 1794 } 1795 1796 1797 status_t 1798 _user_set_timer(int32 timerID, thread_id threadID, bigtime_t startTime, 1799 bigtime_t interval, uint32 flags, struct user_timer_info* userOldInfo) 1800 { 1801 // check the values 1802 if (startTime < 0 || interval < 0) 1803 return B_BAD_VALUE; 1804 1805 // get the timer 1806 TimerLocker timerLocker; 1807 UserTimer* timer; 1808 status_t error = timerLocker.LockAndGetTimer(threadID, timerID, timer); 1809 if (error != B_OK) 1810 return error; 1811 1812 // schedule the timer 1813 user_timer_info oldInfo; 1814 timer->Schedule(startTime, interval, flags, oldInfo.remaining_time, 1815 oldInfo.interval); 1816 1817 // Sanitize remaining_time. If it's <= 0, we set it to 1, the least valid 1818 // value. 1819 if (oldInfo.remaining_time <= 0) 1820 oldInfo.remaining_time = 1; 1821 1822 timerLocker.Unlock(); 1823 1824 // copy back the old info 1825 if (userOldInfo != NULL 1826 && (!IS_USER_ADDRESS(userOldInfo) 1827 || user_memcpy(userOldInfo, &oldInfo, sizeof(oldInfo)) != B_OK)) { 1828 return B_BAD_ADDRESS; 1829 } 1830 1831 return B_OK; 1832 } 1833