kernel: Make UserEvent::Fire() work without gSchedulerLock held

This commit is contained in:
Pawel Dziepak 2013-11-04 23:53:20 +01:00
parent 3c819aaa72
commit 958f6d00aa
1 changed files with 24 additions and 26 deletions

View File

@ -31,22 +31,20 @@ struct SignalEvent::EventSignal : Signal {
{
}
bool IsInUse() const
bool MarkUsed()
{
return fInUse;
return atomic_set(reinterpret_cast<vint32*>(&fInUse), true);
}
void SetInUse(bool inUse)
void SetUnused()
{
fInUse = inUse;
fInUse = false;
}
virtual void Handled()
{
// mark not-in-use
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
fInUse = false;
schedulerLocker.Unlock();
Signal::Handled();
}
@ -111,20 +109,22 @@ TeamSignalEvent::Create(Team* team, uint32 signalNumber, int32 signalCode,
status_t
TeamSignalEvent::Fire()
{
// called with the scheduler lock held
if (fSignal->IsInUse())
if (fSignal->MarkUsed())
return B_BUSY;
fSignal->AcquireReference();
// one reference is transferred to send_signal_to_team_locked
InterruptsSpinLocker locker(gSchedulerLock);
status_t error = send_signal_to_team_locked(fTeam, fSignal->Number(),
fSignal, B_DO_NOT_RESCHEDULE);
if (error == B_OK) {
// Mark the signal in-use. There are situations (for certain signals),
// in which send_signal_to_team_locked() succeeds without queuing the
// signal.
fSignal->SetInUse(fSignal->IsPending());
// There are situations (for certain signals), in which
// send_signal_to_team_locked() succeeds without queuing the signal.
if (!fSignal->IsPending())
fSignal->SetUnused();
}
locker.Unlock();
return error;
}
@ -165,20 +165,22 @@ ThreadSignalEvent::Create(Thread* thread, uint32 signalNumber, int32 signalCode,
status_t
ThreadSignalEvent::Fire()
{
// called with the scheduler lock held
if (fSignal->IsInUse())
if (fSignal->MarkUsed())
return B_BUSY;
fSignal->AcquireReference();
// one reference is transferred to send_signal_to_team_locked
InterruptsSpinLocker locker(gSchedulerLock);
status_t error = send_signal_to_thread_locked(fThread, fSignal->Number(),
fSignal, B_DO_NOT_RESCHEDULE);
if (error == B_OK) {
// Mark the signal in-use. There are situations (for certain signals),
// in which send_signal_to_team_locked() succeeds without queuing the
// signal.
fSignal->SetInUse(fSignal->IsPending());
// There are situations (for certain signals), in which
// send_signal_to_team_locked() succeeds without queuing the signal.
if (!fSignal->IsPending())
fSignal->SetUnused();
}
locker.Unlock();
return error;
}
@ -216,12 +218,11 @@ CreateThreadEvent::Create(const ThreadCreationAttributes& attributes)
status_t
CreateThreadEvent::Fire()
{
if (fPendingDPC)
bool wasPending = atomic_set(reinterpret_cast<vint32*>(&fPendingDPC), true);
if (wasPending)
return B_BUSY;
fPendingDPC = true;
DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Add(this, true);
DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Add(this);
return B_OK;
}
@ -231,10 +232,7 @@ void
CreateThreadEvent::DoDPC(DPCQueue* queue)
{
// We're no longer queued in the DPC queue, so we can be reused.
{
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
fPendingDPC = false;
}
fPendingDPC = false;
// create the thread
thread_id threadID = thread_create_thread(fCreationAttributes, false);