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.
27static const bigtime_t kMinPeriodicTimerInterval = 100;
28
29static RealTimeUserTimerList sAbsoluteRealTimeTimers;
30static spinlock sAbsoluteRealTimeTimersLock = B_SPINLOCK_INITIALIZER;
31
32
33// #pragma mark - TimerLocker
34
35
36namespace {
37
38struct 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
112UserTimer::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
126UserTimer::~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*/
163void
164UserTimer::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
192UserTimer::HandleTimerHook(struct timer* timer)
193{
194	((UserTimer*)timer->user_data)->HandleTimer();
195	return B_HANDLED_INTERRUPT;
196}
197
198
199void
200UserTimer::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*/
223void
224UserTimer::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*/
249void
250UserTimer::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
270void
271SystemTimeUserTimer::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
307void
308SystemTimeUserTimer::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
325void
326SystemTimeUserTimer::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*/
346void
347SystemTimeUserTimer::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
371void
372RealTimeUserTimer::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*/
431void
432RealTimeUserTimer::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
451void
452RealTimeUserTimer::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
467TeamTimeUserTimer::TeamTimeUserTimer(team_id teamID)
468	:
469	fTeamID(teamID),
470	fTeam(NULL)
471{
472}
473
474
475TeamTimeUserTimer::~TeamTimeUserTimer()
476{
477	ASSERT(fTeam == NULL);
478}
479
480
481void
482TeamTimeUserTimer::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
539void
540TeamTimeUserTimer::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*/
561void
562TeamTimeUserTimer::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*/
592void
593TeamTimeUserTimer::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*/
618void
619TeamTimeUserTimer::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
634void
635TeamTimeUserTimer::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*/
662void
663TeamTimeUserTimer::_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
709TeamUserTimeUserTimer::TeamUserTimeUserTimer(team_id teamID)
710	:
711	fTeamID(teamID),
712	fTeam(NULL)
713{
714}
715
716
717TeamUserTimeUserTimer::~TeamUserTimeUserTimer()
718{
719	ASSERT(fTeam == NULL);
720}
721
722
723void
724TeamUserTimeUserTimer::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
774void
775TeamUserTimeUserTimer::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*/
796void
797TeamUserTimeUserTimer::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*/
813void
814TeamUserTimeUserTimer::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
846ThreadTimeUserTimer::ThreadTimeUserTimer(thread_id threadID)
847	:
848	fThreadID(threadID),
849	fThread(NULL)
850{
851}
852
853
854ThreadTimeUserTimer::~ThreadTimeUserTimer()
855{
856	ASSERT(fThread == NULL);
857}
858
859
860void
861ThreadTimeUserTimer::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
919void
920ThreadTimeUserTimer::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*/
941void
942ThreadTimeUserTimer::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*/
968void
969ThreadTimeUserTimer::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*/
1010void
1011ThreadTimeUserTimer::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*/
1035void
1036ThreadTimeUserTimer::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
1054void
1055ThreadTimeUserTimer::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
1077UserTimerList::UserTimerList()
1078{
1079}
1080
1081
1082UserTimerList::~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*/
1094UserTimer*
1095UserTimerList::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*/
1112void
1113UserTimerList::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*/
1158int32
1159UserTimerList::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
1184static int32
1185create_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*/
1329static void
1330thread_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*/
1348static void
1349team_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*/
1370status_t
1371user_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*/
1392status_t
1393user_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
1427status_t
1428user_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
1487void
1488user_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
1502void
1503user_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
1523void
1524user_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
1544void
1545user_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
1558status_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
1577status_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
1643int32
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
1690status_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
1718status_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
1751status_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