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