xref: /haiku/src/system/kernel/UserTimer.cpp (revision 529cd177b573aaba391c8adc9c9f5ad76a14bf81)
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