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.
28static const bigtime_t kMinPeriodicTimerInterval = 100;
29
30static RealTimeUserTimerList sAbsoluteRealTimeTimers;
31static spinlock sAbsoluteRealTimeTimersLock = B_SPINLOCK_INITIALIZER;
32
33static seqlock sUserTimerLock = B_SEQLOCK_INITIALIZER;
34
35
36// #pragma mark - TimerLocker
37
38
39namespace {
40
41struct 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
115UserTimer::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
130UserTimer::~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*/
164void
165UserTimer::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
191UserTimer::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
213void
214UserTimer::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*/
237void
238UserTimer::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*/
263void
264UserTimer::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
281void
282UserTimer::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
295void
296SystemTimeUserTimer::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
332void
333SystemTimeUserTimer::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
353void
354SystemTimeUserTimer::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*/
374void
375SystemTimeUserTimer::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
397void
398RealTimeUserTimer::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*/
457void
458RealTimeUserTimer::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
477void
478RealTimeUserTimer::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
493TeamTimeUserTimer::TeamTimeUserTimer(team_id teamID)
494	:
495	fTeamID(teamID),
496	fTeam(NULL)
497{
498}
499
500
501TeamTimeUserTimer::~TeamTimeUserTimer()
502{
503	ASSERT(fTeam == NULL);
504}
505
506
507void
508TeamTimeUserTimer::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
570void
571TeamTimeUserTimer::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*/
596void
597TeamTimeUserTimer::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*/
627void
628TeamTimeUserTimer::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*/
653void
654TeamTimeUserTimer::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
669void
670TeamTimeUserTimer::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*/
697void
698TeamTimeUserTimer::_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
741TeamUserTimeUserTimer::TeamUserTimeUserTimer(team_id teamID)
742	:
743	fTeamID(teamID),
744	fTeam(NULL)
745{
746}
747
748
749TeamUserTimeUserTimer::~TeamUserTimeUserTimer()
750{
751	ASSERT(fTeam == NULL);
752}
753
754
755void
756TeamUserTimeUserTimer::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
811void
812TeamUserTimeUserTimer::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*/
837void
838TeamUserTimeUserTimer::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*/
854void
855TeamUserTimeUserTimer::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
887ThreadTimeUserTimer::ThreadTimeUserTimer(thread_id threadID)
888	:
889	fThreadID(threadID),
890	fThread(NULL)
891{
892}
893
894
895ThreadTimeUserTimer::~ThreadTimeUserTimer()
896{
897	ASSERT(fThread == NULL);
898}
899
900
901void
902ThreadTimeUserTimer::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 != NULL ? &fThread->time_lock : NULL);
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
965void
966ThreadTimeUserTimer::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*/
991void
992ThreadTimeUserTimer::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*/
1018void
1019ThreadTimeUserTimer::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*/
1056void
1057ThreadTimeUserTimer::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*/
1081void
1082ThreadTimeUserTimer::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
1100void
1101ThreadTimeUserTimer::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
1123UserTimerList::UserTimerList()
1124{
1125}
1126
1127
1128UserTimerList::~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*/
1140UserTimer*
1141UserTimerList::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*/
1158void
1159UserTimerList::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*/
1204int32
1205UserTimerList::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
1230static int32
1231create_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*/
1375static void
1376thread_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*/
1394static void
1395team_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*/
1416status_t
1417user_timer_create_thread_timers(Team* team, Thread* thread)
1418{
1419	// create a real time user timer
1420	struct sigevent event = {0};
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*/
1438status_t
1439user_timer_create_team_timers(Team* team)
1440{
1441	// create a real time user timer
1442	struct sigevent event = {0};
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
1473status_t
1474user_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
1533void
1534user_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
1548void
1549user_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
1569void
1570user_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
1590void
1591user_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
1604status_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
1623status_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
1689int32
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 = {0};
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
1736status_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
1764status_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
1797status_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