kernel: Protect UserTimers with sUserTimerLock
This commit is contained in:
parent
4824f7630b
commit
f4b088a992
|
@ -92,7 +92,7 @@ private:
|
||||||
private:
|
private:
|
||||||
ThreadCreationAttributes fCreationAttributes;
|
ThreadCreationAttributes fCreationAttributes;
|
||||||
char fThreadName[B_OS_NAME_LENGTH];
|
char fThreadName[B_OS_NAME_LENGTH];
|
||||||
bool fPendingDPC;
|
int32 fPendingDPC;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,8 @@ protected:
|
||||||
inline void UpdatePeriodicStartTime();
|
inline void UpdatePeriodicStartTime();
|
||||||
inline void CheckPeriodicOverrun(bigtime_t now);
|
inline void CheckPeriodicOverrun(bigtime_t now);
|
||||||
|
|
||||||
|
inline void CancelTimer();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int32 fID;
|
int32 fID;
|
||||||
timer fTimer;
|
timer fTimer;
|
||||||
|
@ -62,6 +64,7 @@ protected:
|
||||||
bigtime_t fInterval;
|
bigtime_t fInterval;
|
||||||
uint32 fOverrunCount;
|
uint32 fOverrunCount;
|
||||||
bool fScheduled; // fTimer scheduled
|
bool fScheduled; // fTimer scheduled
|
||||||
|
int32 fSkip;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,30 +27,33 @@ struct SignalEvent::EventSignal : Signal {
|
||||||
pid_t sendingProcess)
|
pid_t sendingProcess)
|
||||||
:
|
:
|
||||||
Signal(number, signalCode, errorCode, sendingProcess),
|
Signal(number, signalCode, errorCode, sendingProcess),
|
||||||
fInUse(false)
|
fInUse(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MarkUsed()
|
bool MarkUsed()
|
||||||
{
|
{
|
||||||
return atomic_set(reinterpret_cast<vint32*>(&fInUse), true);
|
return atomic_set(&fInUse, 1) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetUnused()
|
void SetUnused()
|
||||||
{
|
{
|
||||||
fInUse = false;
|
fInUse = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Handled()
|
virtual void Handled()
|
||||||
{
|
{
|
||||||
// mark not-in-use
|
// mark not-in-use
|
||||||
fInUse = false;
|
{
|
||||||
|
InterruptsSpinLocker _(gSchedulerLock);
|
||||||
|
fInUse = 0;
|
||||||
|
}
|
||||||
|
|
||||||
Signal::Handled();
|
Signal::Handled();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool fInUse;
|
int32 fInUse;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,12 +121,10 @@ TeamSignalEvent::Fire()
|
||||||
InterruptsSpinLocker locker(gSchedulerLock);
|
InterruptsSpinLocker locker(gSchedulerLock);
|
||||||
status_t error = send_signal_to_team_locked(fTeam, fSignal->Number(),
|
status_t error = send_signal_to_team_locked(fTeam, fSignal->Number(),
|
||||||
fSignal, B_DO_NOT_RESCHEDULE);
|
fSignal, B_DO_NOT_RESCHEDULE);
|
||||||
if (error == B_OK) {
|
// There are situations (for certain signals), in which
|
||||||
// There are situations (for certain signals), in which
|
// send_signal_to_team_locked() succeeds without queuing the signal.
|
||||||
// send_signal_to_team_locked() succeeds without queuing the signal.
|
if (error != B_OK || !fSignal->IsPending())
|
||||||
if (!fSignal->IsPending())
|
fSignal->SetUnused();
|
||||||
fSignal->SetUnused();
|
|
||||||
}
|
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
@ -165,6 +166,8 @@ ThreadSignalEvent::Create(Thread* thread, uint32 signalNumber, int32 signalCode,
|
||||||
status_t
|
status_t
|
||||||
ThreadSignalEvent::Fire()
|
ThreadSignalEvent::Fire()
|
||||||
{
|
{
|
||||||
|
dprintf("THREAD\n");
|
||||||
|
|
||||||
if (fSignal->MarkUsed())
|
if (fSignal->MarkUsed())
|
||||||
return B_BUSY;
|
return B_BUSY;
|
||||||
|
|
||||||
|
@ -174,12 +177,10 @@ ThreadSignalEvent::Fire()
|
||||||
InterruptsSpinLocker locker(gSchedulerLock);
|
InterruptsSpinLocker locker(gSchedulerLock);
|
||||||
status_t error = send_signal_to_thread_locked(fThread, fSignal->Number(),
|
status_t error = send_signal_to_thread_locked(fThread, fSignal->Number(),
|
||||||
fSignal, B_DO_NOT_RESCHEDULE);
|
fSignal, B_DO_NOT_RESCHEDULE);
|
||||||
if (error == B_OK) {
|
// There are situations (for certain signals), in which
|
||||||
// There are situations (for certain signals), in which
|
// send_signal_to_team_locked() succeeds without queuing the signal.
|
||||||
// send_signal_to_team_locked() succeeds without queuing the signal.
|
if (error != B_OK || !fSignal->IsPending())
|
||||||
if (!fSignal->IsPending())
|
fSignal->SetUnused();
|
||||||
fSignal->SetUnused();
|
|
||||||
}
|
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
@ -192,7 +193,7 @@ ThreadSignalEvent::Fire()
|
||||||
CreateThreadEvent::CreateThreadEvent(const ThreadCreationAttributes& attributes)
|
CreateThreadEvent::CreateThreadEvent(const ThreadCreationAttributes& attributes)
|
||||||
:
|
:
|
||||||
fCreationAttributes(attributes),
|
fCreationAttributes(attributes),
|
||||||
fPendingDPC(false)
|
fPendingDPC(0)
|
||||||
{
|
{
|
||||||
// attributes.name is a pointer to a temporary buffer. Copy the name into
|
// attributes.name is a pointer to a temporary buffer. Copy the name into
|
||||||
// our own buffer and replace the name pointer.
|
// our own buffer and replace the name pointer.
|
||||||
|
@ -218,7 +219,7 @@ CreateThreadEvent::Create(const ThreadCreationAttributes& attributes)
|
||||||
status_t
|
status_t
|
||||||
CreateThreadEvent::Fire()
|
CreateThreadEvent::Fire()
|
||||||
{
|
{
|
||||||
bool wasPending = atomic_set(reinterpret_cast<vint32*>(&fPendingDPC), true);
|
bool wasPending = atomic_set(&fPendingDPC, 1) != 0;
|
||||||
if (wasPending)
|
if (wasPending)
|
||||||
return B_BUSY;
|
return B_BUSY;
|
||||||
|
|
||||||
|
@ -232,7 +233,7 @@ void
|
||||||
CreateThreadEvent::DoDPC(DPCQueue* queue)
|
CreateThreadEvent::DoDPC(DPCQueue* queue)
|
||||||
{
|
{
|
||||||
// We're no longer queued in the DPC queue, so we can be reused.
|
// We're no longer queued in the DPC queue, so we can be reused.
|
||||||
fPendingDPC = false;
|
fPendingDPC = 0;
|
||||||
|
|
||||||
// create the thread
|
// create the thread
|
||||||
thread_id threadID = thread_create_thread(fCreationAttributes, false);
|
thread_id threadID = thread_create_thread(fCreationAttributes, false);
|
||||||
|
|
|
@ -29,6 +29,8 @@ static const bigtime_t kMinPeriodicTimerInterval = 100;
|
||||||
static RealTimeUserTimerList sAbsoluteRealTimeTimers;
|
static RealTimeUserTimerList sAbsoluteRealTimeTimers;
|
||||||
static spinlock sAbsoluteRealTimeTimersLock = B_SPINLOCK_INITIALIZER;
|
static spinlock sAbsoluteRealTimeTimersLock = B_SPINLOCK_INITIALIZER;
|
||||||
|
|
||||||
|
static seqlock sUserTimerLock = B_SEQLOCK_INITIALIZER;
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - TimerLocker
|
// #pragma mark - TimerLocker
|
||||||
|
|
||||||
|
@ -116,7 +118,8 @@ UserTimer::UserTimer()
|
||||||
fNextTime(0),
|
fNextTime(0),
|
||||||
fInterval(0),
|
fInterval(0),
|
||||||
fOverrunCount(0),
|
fOverrunCount(0),
|
||||||
fScheduled(false)
|
fScheduled(false),
|
||||||
|
fSkip(0)
|
||||||
{
|
{
|
||||||
// mark the timer unused
|
// mark the timer unused
|
||||||
fTimer.user_data = this;
|
fTimer.user_data = this;
|
||||||
|
@ -191,8 +194,22 @@ UserTimer::Cancel()
|
||||||
/*static*/ int32
|
/*static*/ int32
|
||||||
UserTimer::HandleTimerHook(struct timer* timer)
|
UserTimer::HandleTimerHook(struct timer* timer)
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker _(gSchedulerLock);
|
UserTimer* userTimer = reinterpret_cast<UserTimer*>(timer->user_data);
|
||||||
((UserTimer*)timer->user_data)->HandleTimer();
|
|
||||||
|
InterruptsLocker _;
|
||||||
|
|
||||||
|
bool locked = false;
|
||||||
|
while (!locked && atomic_get(&userTimer->fSkip) == 0) {
|
||||||
|
locked = try_acquire_write_seqlock(&sUserTimerLock);
|
||||||
|
if (!locked)
|
||||||
|
PAUSE();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locked) {
|
||||||
|
userTimer->HandleTimer();
|
||||||
|
release_write_seqlock(&sUserTimerLock);
|
||||||
|
}
|
||||||
|
|
||||||
return B_HANDLED_INTERRUPT;
|
return B_HANDLED_INTERRUPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +236,7 @@ UserTimer::HandleTimer()
|
||||||
/*! Updates the start time for a periodic timer after it expired, enforcing
|
/*! Updates the start time for a periodic timer after it expired, enforcing
|
||||||
sanity limits and updating \c fOverrunCount, if necessary.
|
sanity limits and updating \c fOverrunCount, if necessary.
|
||||||
|
|
||||||
The caller must not hold the scheduler lock.
|
The caller must not hold \c sUserTimerLock.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
UserTimer::UpdatePeriodicStartTime()
|
UserTimer::UpdatePeriodicStartTime()
|
||||||
|
@ -243,7 +260,7 @@ UserTimer::UpdatePeriodicStartTime()
|
||||||
/*! Checks whether the timer start time lies too much in the past and, if so,
|
/*! Checks whether the timer start time lies too much in the past and, if so,
|
||||||
adjusts it and updates \c fOverrunCount.
|
adjusts it and updates \c fOverrunCount.
|
||||||
|
|
||||||
The caller must not hold the scheduler lock.
|
The caller must not hold \c sUserTimerLock.
|
||||||
|
|
||||||
\param now The current time.
|
\param now The current time.
|
||||||
*/
|
*/
|
||||||
|
@ -265,6 +282,17 @@ UserTimer::CheckPeriodicOverrun(bigtime_t now)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
UserTimer::CancelTimer()
|
||||||
|
{
|
||||||
|
ASSERT(fScheduled);
|
||||||
|
|
||||||
|
fSkip = 1;
|
||||||
|
cancel_timer(&fTimer);
|
||||||
|
fSkip = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - SystemTimeUserTimer
|
// #pragma mark - SystemTimeUserTimer
|
||||||
|
|
||||||
|
|
||||||
|
@ -272,14 +300,14 @@ void
|
||||||
SystemTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval,
|
SystemTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval,
|
||||||
uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval)
|
uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval)
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
InterruptsWriteSequentialLocker locker(sUserTimerLock);
|
||||||
|
|
||||||
// get the current time
|
// get the current time
|
||||||
bigtime_t now = system_time();
|
bigtime_t now = system_time();
|
||||||
|
|
||||||
// Cancel the old timer, if still scheduled, and get the previous values.
|
// Cancel the old timer, if still scheduled, and get the previous values.
|
||||||
if (fScheduled) {
|
if (fScheduled) {
|
||||||
cancel_timer(&fTimer);
|
CancelTimer();
|
||||||
|
|
||||||
_oldRemainingTime = fNextTime - now;
|
_oldRemainingTime = fNextTime - now;
|
||||||
_oldInterval = fInterval;
|
_oldInterval = fInterval;
|
||||||
|
@ -309,17 +337,20 @@ void
|
||||||
SystemTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval,
|
SystemTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval,
|
||||||
uint32& _overrunCount)
|
uint32& _overrunCount)
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
uint32 count;
|
||||||
|
do {
|
||||||
|
count = acquire_read_seqlock(&sUserTimerLock);
|
||||||
|
|
||||||
if (fScheduled) {
|
if (fScheduled) {
|
||||||
_remainingTime = fNextTime - system_time();
|
_remainingTime = fNextTime - system_time();
|
||||||
_interval = fInterval;
|
_interval = fInterval;
|
||||||
} else {
|
} else {
|
||||||
_remainingTime = B_INFINITE_TIMEOUT;
|
_remainingTime = B_INFINITE_TIMEOUT;
|
||||||
_interval = 0;
|
_interval = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_overrunCount = fOverrunCount;
|
_overrunCount = fOverrunCount;
|
||||||
|
} while (!release_read_seqlock(&sUserTimerLock, count));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -338,7 +369,7 @@ SystemTimeUserTimer::HandleTimer()
|
||||||
|
|
||||||
/*! Schedules the kernel timer.
|
/*! Schedules the kernel timer.
|
||||||
|
|
||||||
The caller must hold the scheduler lock.
|
The caller must hold \c sUserTimerLock.
|
||||||
|
|
||||||
\param now The current system time to be used.
|
\param now The current system time to be used.
|
||||||
\param checkPeriodicOverrun If \c true, calls CheckPeriodicOverrun() first,
|
\param checkPeriodicOverrun If \c true, calls CheckPeriodicOverrun() first,
|
||||||
|
@ -371,14 +402,14 @@ void
|
||||||
RealTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval,
|
RealTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval,
|
||||||
uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval)
|
uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval)
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
InterruptsWriteSequentialLocker locker(sUserTimerLock);
|
||||||
|
|
||||||
// get the current time
|
// get the current time
|
||||||
bigtime_t now = system_time();
|
bigtime_t now = system_time();
|
||||||
|
|
||||||
// Cancel the old timer, if still scheduled, and get the previous values.
|
// Cancel the old timer, if still scheduled, and get the previous values.
|
||||||
if (fScheduled) {
|
if (fScheduled) {
|
||||||
cancel_timer(&fTimer);
|
CancelTimer();
|
||||||
|
|
||||||
_oldRemainingTime = fNextTime - now;
|
_oldRemainingTime = fNextTime - now;
|
||||||
_oldInterval = fInterval;
|
_oldInterval = fInterval;
|
||||||
|
@ -424,7 +455,7 @@ RealTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval,
|
||||||
|
|
||||||
/*! Called when the real-time clock has been changed.
|
/*! Called when the real-time clock has been changed.
|
||||||
|
|
||||||
The caller must hold the scheduler lock. Optionally the caller may also
|
The caller must hold \c sUserTimerLock. Optionally the caller may also
|
||||||
hold \c sAbsoluteRealTimeTimersLock.
|
hold \c sAbsoluteRealTimeTimersLock.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
|
@ -439,7 +470,7 @@ RealTimeUserTimer::TimeWarped()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// cancel the kernel timer and reschedule it
|
// cancel the kernel timer and reschedule it
|
||||||
cancel_timer(&fTimer);
|
CancelTimer();
|
||||||
|
|
||||||
fNextTime += oldRealTimeOffset - fRealTimeOffset;
|
fNextTime += oldRealTimeOffset - fRealTimeOffset;
|
||||||
|
|
||||||
|
@ -481,6 +512,7 @@ void
|
||||||
TeamTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval,
|
TeamTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval,
|
||||||
uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval)
|
uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval)
|
||||||
{
|
{
|
||||||
|
InterruptsWriteSequentialLocker locker(sUserTimerLock);
|
||||||
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
||||||
|
|
||||||
// get the current time, but only if needed
|
// get the current time, but only if needed
|
||||||
|
@ -490,7 +522,7 @@ TeamTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval,
|
||||||
// Cancel the old timer, if still scheduled, and get the previous values.
|
// Cancel the old timer, if still scheduled, and get the previous values.
|
||||||
if (fTeam != NULL) {
|
if (fTeam != NULL) {
|
||||||
if (fScheduled) {
|
if (fScheduled) {
|
||||||
cancel_timer(&fTimer);
|
CancelTimer();
|
||||||
fScheduled = false;
|
fScheduled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,23 +571,27 @@ void
|
||||||
TeamTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval,
|
TeamTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval,
|
||||||
uint32& _overrunCount)
|
uint32& _overrunCount)
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
uint32 count;
|
||||||
|
do {
|
||||||
|
count = acquire_read_seqlock(&sUserTimerLock);
|
||||||
|
|
||||||
if (fTeam != NULL) {
|
if (fTeam != NULL) {
|
||||||
_remainingTime = fNextTime - fTeam->CPUTime(false);
|
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
||||||
_interval = fInterval;
|
_remainingTime = fNextTime - fTeam->CPUTime(false);
|
||||||
} else {
|
_interval = fInterval;
|
||||||
_remainingTime = B_INFINITE_TIMEOUT;
|
} else {
|
||||||
_interval = 0;
|
_remainingTime = B_INFINITE_TIMEOUT;
|
||||||
}
|
_interval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
_overrunCount = fOverrunCount;
|
_overrunCount = fOverrunCount;
|
||||||
|
} while (!release_read_seqlock(&sUserTimerLock, count));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Deactivates the timer, if it is activated.
|
/*! Deactivates the timer, if it is activated.
|
||||||
|
|
||||||
The caller must hold the scheduler lock.
|
The caller must hold the scheduler lock and \c sUserTimerLock.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
TeamTimeUserTimer::Deactivate()
|
TeamTimeUserTimer::Deactivate()
|
||||||
|
@ -565,7 +601,7 @@ TeamTimeUserTimer::Deactivate()
|
||||||
|
|
||||||
// unschedule, if scheduled
|
// unschedule, if scheduled
|
||||||
if (fScheduled) {
|
if (fScheduled) {
|
||||||
cancel_timer(&fTimer);
|
CancelTimer();
|
||||||
fScheduled = false;
|
fScheduled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,7 +619,7 @@ TeamTimeUserTimer::Deactivate()
|
||||||
was just set. Schedules a kernel timer for the remaining time, respectively
|
was just set. Schedules a kernel timer for the remaining time, respectively
|
||||||
cancels it.
|
cancels it.
|
||||||
|
|
||||||
The caller must hold the scheduler lock.
|
The caller must hold the scheduler lock and \c sUserTimerLock.
|
||||||
|
|
||||||
\param unscheduledThread If not \c NULL, this is the thread that is
|
\param unscheduledThread If not \c NULL, this is the thread that is
|
||||||
currently running and which is in the process of being unscheduled.
|
currently running and which is in the process of being unscheduled.
|
||||||
|
@ -610,7 +646,7 @@ TeamTimeUserTimer::Update(Thread* unscheduledThread)
|
||||||
/*! Called when the team's CPU time clock which this timer refers to has been
|
/*! Called when the team's CPU time clock which this timer refers to has been
|
||||||
set.
|
set.
|
||||||
|
|
||||||
The caller must hold the scheduler lock.
|
The caller must hold the scheduler lock and \c sUserTimerLock.
|
||||||
|
|
||||||
\param changedBy The value by which the clock has changed.
|
\param changedBy The value by which the clock has changed.
|
||||||
*/
|
*/
|
||||||
|
@ -653,7 +689,7 @@ TeamTimeUserTimer::HandleTimer()
|
||||||
/*! Schedules/cancels the kernel timer as necessary.
|
/*! Schedules/cancels the kernel timer as necessary.
|
||||||
|
|
||||||
\c fRunningThreads must be up-to-date.
|
\c fRunningThreads must be up-to-date.
|
||||||
The caller must hold the scheduler lock.
|
The caller must hold the scheduler lock and \c sUserTimerLock.
|
||||||
|
|
||||||
\param unscheduling \c true, when the current thread is in the process of
|
\param unscheduling \c true, when the current thread is in the process of
|
||||||
being unscheduled.
|
being unscheduled.
|
||||||
|
@ -663,7 +699,7 @@ TeamTimeUserTimer::_Update(bool unscheduling)
|
||||||
{
|
{
|
||||||
// unschedule the kernel timer, if scheduled
|
// unschedule the kernel timer, if scheduled
|
||||||
if (fScheduled)
|
if (fScheduled)
|
||||||
cancel_timer(&fTimer);
|
CancelTimer();
|
||||||
|
|
||||||
// if no more threads are running, we're done
|
// if no more threads are running, we're done
|
||||||
if (fRunningThreads == 0) {
|
if (fRunningThreads == 0) {
|
||||||
|
@ -720,6 +756,7 @@ void
|
||||||
TeamUserTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval,
|
TeamUserTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval,
|
||||||
uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval)
|
uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval)
|
||||||
{
|
{
|
||||||
|
InterruptsWriteSequentialLocker locker(sUserTimerLock);
|
||||||
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
||||||
|
|
||||||
// get the current time, but only if needed
|
// get the current time, but only if needed
|
||||||
|
@ -771,23 +808,27 @@ void
|
||||||
TeamUserTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval,
|
TeamUserTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval,
|
||||||
uint32& _overrunCount)
|
uint32& _overrunCount)
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
uint32 count;
|
||||||
|
do {
|
||||||
|
count = acquire_read_seqlock(&sUserTimerLock);
|
||||||
|
|
||||||
if (fTeam != NULL) {
|
if (fTeam != NULL) {
|
||||||
_remainingTime = fNextTime - fTeam->UserCPUTime();
|
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
||||||
_interval = fInterval;
|
_remainingTime = fNextTime - fTeam->UserCPUTime();
|
||||||
} else {
|
_interval = fInterval;
|
||||||
_remainingTime = B_INFINITE_TIMEOUT;
|
} else {
|
||||||
_interval = 0;
|
_remainingTime = B_INFINITE_TIMEOUT;
|
||||||
}
|
_interval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
_overrunCount = fOverrunCount;
|
_overrunCount = fOverrunCount;
|
||||||
|
} while (!release_read_seqlock(&sUserTimerLock, count));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Deactivates the timer, if it is activated.
|
/*! Deactivates the timer, if it is activated.
|
||||||
|
|
||||||
The caller must hold the scheduler lock.
|
The caller must hold the scheduler lock and \c sUserTimerLock.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
TeamUserTimeUserTimer::Deactivate()
|
TeamUserTimeUserTimer::Deactivate()
|
||||||
|
@ -804,7 +845,7 @@ TeamUserTimeUserTimer::Deactivate()
|
||||||
|
|
||||||
/*! Checks whether the timer is up, firing an event, if so.
|
/*! Checks whether the timer is up, firing an event, if so.
|
||||||
|
|
||||||
The caller must hold the scheduler lock.
|
The caller must hold the scheduler lock and \c sUserTimerLock.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
TeamUserTimeUserTimer::Check()
|
TeamUserTimeUserTimer::Check()
|
||||||
|
@ -857,6 +898,7 @@ void
|
||||||
ThreadTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval,
|
ThreadTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval,
|
||||||
uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval)
|
uint32 flags, bigtime_t& _oldRemainingTime, bigtime_t& _oldInterval)
|
||||||
{
|
{
|
||||||
|
InterruptsWriteSequentialLocker locker(sUserTimerLock);
|
||||||
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
||||||
|
|
||||||
// get the current time, but only if needed
|
// get the current time, but only if needed
|
||||||
|
@ -866,7 +908,7 @@ ThreadTimeUserTimer::Schedule(bigtime_t nextTime, bigtime_t interval,
|
||||||
// Cancel the old timer, if still scheduled, and get the previous values.
|
// Cancel the old timer, if still scheduled, and get the previous values.
|
||||||
if (fThread != NULL) {
|
if (fThread != NULL) {
|
||||||
if (fScheduled) {
|
if (fScheduled) {
|
||||||
cancel_timer(&fTimer);
|
CancelTimer();
|
||||||
fScheduled = false;
|
fScheduled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -916,23 +958,27 @@ void
|
||||||
ThreadTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval,
|
ThreadTimeUserTimer::GetInfo(bigtime_t& _remainingTime, bigtime_t& _interval,
|
||||||
uint32& _overrunCount)
|
uint32& _overrunCount)
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
uint32 count;
|
||||||
|
do {
|
||||||
|
count = acquire_read_seqlock(&sUserTimerLock);
|
||||||
|
|
||||||
if (fThread != NULL) {
|
if (fThread != NULL) {
|
||||||
_remainingTime = fNextTime - fThread->CPUTime(false);
|
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
||||||
_interval = fInterval;
|
_remainingTime = fNextTime - fThread->CPUTime(false);
|
||||||
} else {
|
_interval = fInterval;
|
||||||
_remainingTime = B_INFINITE_TIMEOUT;
|
} else {
|
||||||
_interval = 0;
|
_remainingTime = B_INFINITE_TIMEOUT;
|
||||||
}
|
_interval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
_overrunCount = fOverrunCount;
|
_overrunCount = fOverrunCount;
|
||||||
|
} while (!release_read_seqlock(&sUserTimerLock, count));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Deactivates the timer, if it is activated.
|
/*! Deactivates the timer, if it is activated.
|
||||||
|
|
||||||
The caller must hold the scheduler lock.
|
The caller must hold the scheduler lock and \c sUserTimerLock.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ThreadTimeUserTimer::Deactivate()
|
ThreadTimeUserTimer::Deactivate()
|
||||||
|
@ -942,7 +988,7 @@ ThreadTimeUserTimer::Deactivate()
|
||||||
|
|
||||||
// unschedule, if scheduled
|
// unschedule, if scheduled
|
||||||
if (fScheduled) {
|
if (fScheduled) {
|
||||||
cancel_timer(&fTimer);
|
CancelTimer();
|
||||||
fScheduled = false;
|
fScheduled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -959,7 +1005,7 @@ ThreadTimeUserTimer::Deactivate()
|
||||||
scheduled, or, when the timer was just set and the thread is already
|
scheduled, or, when the timer was just set and the thread is already
|
||||||
running. Schedules a kernel timer for the remaining time.
|
running. Schedules a kernel timer for the remaining time.
|
||||||
|
|
||||||
The caller must hold the scheduler lock.
|
The caller must hold the scheduler lock and \c sUserTimerLock.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ThreadTimeUserTimer::Start()
|
ThreadTimeUserTimer::Start()
|
||||||
|
@ -997,7 +1043,7 @@ ThreadTimeUserTimer::Start()
|
||||||
Called when the thread whose CPU time is referred to by the timer is
|
Called when the thread whose CPU time is referred to by the timer is
|
||||||
unscheduled, or, when the timer is canceled.
|
unscheduled, or, when the timer is canceled.
|
||||||
|
|
||||||
The caller must hold the scheduler lock.
|
The caller must hold \c sUserTimerLock.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ThreadTimeUserTimer::Stop()
|
ThreadTimeUserTimer::Stop()
|
||||||
|
@ -1008,7 +1054,7 @@ ThreadTimeUserTimer::Stop()
|
||||||
ASSERT(fScheduled);
|
ASSERT(fScheduled);
|
||||||
|
|
||||||
// cancel the kernel timer
|
// cancel the kernel timer
|
||||||
cancel_timer(&fTimer);
|
CancelTimer();
|
||||||
fScheduled = false;
|
fScheduled = false;
|
||||||
|
|
||||||
// TODO: To avoid odd race conditions, we should check the current time of
|
// TODO: To avoid odd race conditions, we should check the current time of
|
||||||
|
@ -1020,7 +1066,7 @@ ThreadTimeUserTimer::Stop()
|
||||||
/*! Called when the team's CPU time clock which this timer refers to has been
|
/*! Called when the team's CPU time clock which this timer refers to has been
|
||||||
set.
|
set.
|
||||||
|
|
||||||
The caller must hold the scheduler lock.
|
The caller must hold the scheduler lock and \c sUserTimerLock.
|
||||||
|
|
||||||
\param changedBy The value by which the clock has changed.
|
\param changedBy The value by which the clock has changed.
|
||||||
*/
|
*/
|
||||||
|
@ -1480,7 +1526,7 @@ void
|
||||||
user_timer_real_time_clock_changed()
|
user_timer_real_time_clock_changed()
|
||||||
{
|
{
|
||||||
// we need to update all absolute real-time timers
|
// we need to update all absolute real-time timers
|
||||||
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
InterruptsWriteSequentialLocker locker(sUserTimerLock);
|
||||||
SpinLocker globalListLocker(sAbsoluteRealTimeTimersLock);
|
SpinLocker globalListLocker(sAbsoluteRealTimeTimersLock);
|
||||||
|
|
||||||
for (RealTimeUserTimerList::Iterator it
|
for (RealTimeUserTimerList::Iterator it
|
||||||
|
|
Loading…
Reference in New Issue