haiku/headers/private/kernel/UserTimer.h
Michael Lotz 52d500e5b4 kernel: Workaround for double lock of spinlock in user timers.
The thread that is being [un]scheduled already has its time_lock locked
in {stop|continue}_cpu_timers(). When updating the TeamTimeUserTimer,
the team is asked for its cpu time. Team::CPUTime() then iterates the
threads of the team and locks the time_lock of the thread again.

This workaround passes a possibly locked thread through the relevant
functions so Team::CPUTime() can decide whether or not a thread it
iterates needs to be locked or not.

This works around  and its duplicates  and .
2014-10-29 00:25:37 +01:00

279 lines
7.0 KiB
C++

/*
* Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_USER_TIMER_H
#define _KERNEL_USER_TIMER_H
#include <sys/cdefs.h>
#include <time.h>
#include <util/DoublyLinkedList.h>
#include <ksignal.h>
#include <timer.h>
#include <user_timer_defs.h>
struct thread_creation_attributes;
namespace BKernel {
struct UserEvent;
struct Team;
struct UserTimer : DoublyLinkedListLinkImpl<UserTimer> {
UserTimer();
virtual ~UserTimer();
int32 ID() const
{ return fID; }
void SetID(int32 id)
{ fID = id; }
void SetEvent(UserEvent* event)
{ fEvent = event; }
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval) = 0;
void Cancel();
virtual void GetInfo(bigtime_t& _remainingTime,
bigtime_t& _interval,
uint32& _overrunCount) = 0;
protected:
static int32 HandleTimerHook(struct timer* timer);
virtual void HandleTimer();
inline void UpdatePeriodicStartTime();
inline void CheckPeriodicOverrun(bigtime_t now);
inline void CancelTimer();
protected:
int32 fID;
timer fTimer;
UserEvent* fEvent;
bigtime_t fNextTime;
bigtime_t fInterval;
uint32 fOverrunCount;
bool fScheduled; // fTimer scheduled
int32 fSkip;
};
struct SystemTimeUserTimer : public UserTimer {
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval);
virtual void GetInfo(bigtime_t& _remainingTime,
bigtime_t& _interval,
uint32& _overrunCount);
protected:
virtual void HandleTimer();
void ScheduleKernelTimer(bigtime_t now,
bool checkPeriodicOverrun);
};
struct RealTimeUserTimer : public SystemTimeUserTimer {
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval);
void TimeWarped();
private:
bigtime_t fRealTimeOffset;
bool fAbsolute;
protected:
virtual void HandleTimer();
public:
// conceptually package private
DoublyLinkedListLink<RealTimeUserTimer> fGlobalListLink;
};
struct TeamTimeUserTimer : public UserTimer {
TeamTimeUserTimer(team_id teamID);
~TeamTimeUserTimer();
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval);
virtual void GetInfo(bigtime_t& _remainingTime,
bigtime_t& _interval,
uint32& _overrunCount);
void Deactivate();
void Update(Thread* unscheduledThread,
Thread* lockedThread = NULL);
void TimeWarped(bigtime_t changedBy);
protected:
virtual void HandleTimer();
private:
void _Update(bool unscheduling,
Thread* lockedThread = NULL);
private:
team_id fTeamID;
Team* fTeam;
int32 fRunningThreads;
bool fAbsolute;
public:
// conceptually package private
DoublyLinkedListLink<TeamTimeUserTimer> fCPUTimeListLink;
};
struct TeamUserTimeUserTimer : public UserTimer {
TeamUserTimeUserTimer(team_id teamID);
~TeamUserTimeUserTimer();
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval);
virtual void GetInfo(bigtime_t& _remainingTime,
bigtime_t& _interval,
uint32& _overrunCount);
void Deactivate();
void Check();
private:
team_id fTeamID;
Team* fTeam;
public:
// conceptually package private
DoublyLinkedListLink<TeamUserTimeUserTimer> fCPUTimeListLink;
};
struct ThreadTimeUserTimer : public UserTimer {
ThreadTimeUserTimer(thread_id threadID);
~ThreadTimeUserTimer();
virtual void Schedule(bigtime_t nextTime, bigtime_t interval,
uint32 flags, bigtime_t& _oldRemainingTime,
bigtime_t& _oldInterval);
virtual void GetInfo(bigtime_t& _remainingTime,
bigtime_t& _interval,
uint32& _overrunCount);
void Deactivate();
void Start();
void Stop();
void TimeWarped(bigtime_t changedBy);
protected:
virtual void HandleTimer();
private:
thread_id fThreadID;
Thread* fThread; // != NULL only when active
bool fAbsolute;
public:
// conceptually package private
DoublyLinkedListLink<ThreadTimeUserTimer> fCPUTimeListLink;
};
struct UserTimerList {
UserTimerList();
~UserTimerList();
UserTimer* TimerFor(int32 id) const;
void AddTimer(UserTimer* timer);
void RemoveTimer(UserTimer* timer)
{ fTimers.Remove(timer); }
int32 DeleteTimers(bool userDefinedOnly);
private:
typedef DoublyLinkedList<UserTimer> TimerList;
private:
TimerList fTimers;
};
typedef DoublyLinkedList<RealTimeUserTimer,
DoublyLinkedListMemberGetLink<RealTimeUserTimer,
&RealTimeUserTimer::fGlobalListLink> > RealTimeUserTimerList;
typedef DoublyLinkedList<TeamTimeUserTimer,
DoublyLinkedListMemberGetLink<TeamTimeUserTimer,
&TeamTimeUserTimer::fCPUTimeListLink> > TeamTimeUserTimerList;
typedef DoublyLinkedList<TeamUserTimeUserTimer,
DoublyLinkedListMemberGetLink<TeamUserTimeUserTimer,
&TeamUserTimeUserTimer::fCPUTimeListLink> > TeamUserTimeUserTimerList;
typedef DoublyLinkedList<ThreadTimeUserTimer,
DoublyLinkedListMemberGetLink<ThreadTimeUserTimer,
&ThreadTimeUserTimer::fCPUTimeListLink> > ThreadTimeUserTimerList;
} // namespace BKernel
using BKernel::RealTimeUserTimer;
using BKernel::RealTimeUserTimerList;
using BKernel::SystemTimeUserTimer;
using BKernel::TeamUserTimeUserTimer;
using BKernel::TeamUserTimeUserTimerList;
using BKernel::TeamTimeUserTimer;
using BKernel::TeamTimeUserTimerList;
using BKernel::ThreadTimeUserTimer;
using BKernel::ThreadTimeUserTimerList;
using BKernel::UserTimer;
using BKernel::UserTimerList;
__BEGIN_DECLS
status_t user_timer_create_thread_timers(Team* team, Thread* thread);
status_t user_timer_create_team_timers(Team* team);
status_t user_timer_get_clock(clockid_t clockID, bigtime_t& _time);
void user_timer_real_time_clock_changed();
void user_timer_stop_cpu_timers(Thread* thread, Thread* nextThread);
void user_timer_continue_cpu_timers(Thread* thread,
Thread* previousThread);
void user_timer_check_team_user_timers(Team* team);
status_t _user_get_clock(clockid_t clockID, bigtime_t* _time);
status_t _user_set_clock(clockid_t clockID, bigtime_t time);
int32 _user_create_timer(clockid_t clockID, thread_id threadID,
uint32 flags, const struct sigevent* event,
const thread_creation_attributes* threadAttributes);
status_t _user_delete_timer(int32 timerID, thread_id threadID);
status_t _user_get_timer(int32 timerID, thread_id threadID,
struct user_timer_info* info);
status_t _user_set_timer(int32 timerID, thread_id threadID,
bigtime_t startTime, bigtime_t interval, uint32 flags,
struct user_timer_info* oldInfo);
__END_DECLS
#endif // _KERNEL_USER_TIMER_H