kernel: Make UserEvent::Fire() work without gSchedulerLock held
This commit is contained in:
@@ -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()
|
virtual void Handled()
|
||||||
{
|
{
|
||||||
// mark not-in-use
|
// mark not-in-use
|
||||||
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
|
||||||
fInUse = false;
|
fInUse = false;
|
||||||
schedulerLocker.Unlock();
|
|
||||||
|
|
||||||
Signal::Handled();
|
Signal::Handled();
|
||||||
}
|
}
|
||||||
@@ -111,20 +109,22 @@ TeamSignalEvent::Create(Team* team, uint32 signalNumber, int32 signalCode,
|
|||||||
status_t
|
status_t
|
||||||
TeamSignalEvent::Fire()
|
TeamSignalEvent::Fire()
|
||||||
{
|
{
|
||||||
// called with the scheduler lock held
|
if (fSignal->MarkUsed())
|
||||||
if (fSignal->IsInUse())
|
|
||||||
return B_BUSY;
|
return B_BUSY;
|
||||||
|
|
||||||
fSignal->AcquireReference();
|
fSignal->AcquireReference();
|
||||||
// one reference is transferred to send_signal_to_team_locked
|
// one reference is transferred to send_signal_to_team_locked
|
||||||
|
|
||||||
|
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) {
|
if (error == B_OK) {
|
||||||
// Mark the signal in-use. There are situations (for certain signals),
|
// There are situations (for certain signals), in which
|
||||||
// in which send_signal_to_team_locked() succeeds without queuing the
|
// send_signal_to_team_locked() succeeds without queuing the signal.
|
||||||
// signal.
|
if (!fSignal->IsPending())
|
||||||
fSignal->SetInUse(fSignal->IsPending());
|
fSignal->SetUnused();
|
||||||
}
|
}
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@@ -165,20 +165,22 @@ ThreadSignalEvent::Create(Thread* thread, uint32 signalNumber, int32 signalCode,
|
|||||||
status_t
|
status_t
|
||||||
ThreadSignalEvent::Fire()
|
ThreadSignalEvent::Fire()
|
||||||
{
|
{
|
||||||
// called with the scheduler lock held
|
if (fSignal->MarkUsed())
|
||||||
if (fSignal->IsInUse())
|
|
||||||
return B_BUSY;
|
return B_BUSY;
|
||||||
|
|
||||||
fSignal->AcquireReference();
|
fSignal->AcquireReference();
|
||||||
// one reference is transferred to send_signal_to_team_locked
|
// one reference is transferred to send_signal_to_team_locked
|
||||||
|
|
||||||
|
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) {
|
if (error == B_OK) {
|
||||||
// Mark the signal in-use. There are situations (for certain signals),
|
// There are situations (for certain signals), in which
|
||||||
// in which send_signal_to_team_locked() succeeds without queuing the
|
// send_signal_to_team_locked() succeeds without queuing the signal.
|
||||||
// signal.
|
if (!fSignal->IsPending())
|
||||||
fSignal->SetInUse(fSignal->IsPending());
|
fSignal->SetUnused();
|
||||||
}
|
}
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@@ -216,12 +218,11 @@ CreateThreadEvent::Create(const ThreadCreationAttributes& attributes)
|
|||||||
status_t
|
status_t
|
||||||
CreateThreadEvent::Fire()
|
CreateThreadEvent::Fire()
|
||||||
{
|
{
|
||||||
if (fPendingDPC)
|
bool wasPending = atomic_set(reinterpret_cast<vint32*>(&fPendingDPC), true);
|
||||||
|
if (wasPending)
|
||||||
return B_BUSY;
|
return B_BUSY;
|
||||||
|
|
||||||
fPendingDPC = true;
|
DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Add(this);
|
||||||
|
|
||||||
DPCQueue::DefaultQueue(B_NORMAL_PRIORITY)->Add(this, true);
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -231,10 +232,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;
|
||||||
InterruptsSpinLocker schedulerLocker(gSchedulerLock);
|
|
||||||
fPendingDPC = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the thread
|
// create the thread
|
||||||
thread_id threadID = thread_create_thread(fCreationAttributes, false);
|
thread_id threadID = thread_create_thread(fCreationAttributes, false);
|
||||||
|
|||||||
Reference in New Issue
Block a user