kernel: Fix missing reference to team/thread in signal events.

The signal to the team/thread is only actually sent in a deferred
procedure. To ensure that the team/thread stays valid between the DPC
being queued and it actually running, we need to acquire a reference.

Fixes #11390, where the DPC was run after the team was already
destroyed.
This commit is contained in:
Michael Lotz 2014-10-31 11:58:59 +01:00
parent 6109f53bc6
commit 6a80e6889a
2 changed files with 34 additions and 0 deletions

View File

@ -52,6 +52,8 @@ struct TeamSignalEvent : SignalEvent {
static TeamSignalEvent* Create(Team* team, uint32 signalNumber,
int32 signalCode, int32 errorCode);
virtual status_t Fire();
protected:
virtual void DoDPC(DPCQueue* queue);
@ -69,6 +71,8 @@ struct ThreadSignalEvent : SignalEvent {
int32 signalCode, int32 errorCode,
pid_t sendingTeam);
virtual status_t Fire();
protected:
virtual void DoDPC(DPCQueue* queue);

View File

@ -127,6 +127,20 @@ TeamSignalEvent::Create(Team* team, uint32 signalNumber, int32 signalCode,
}
status_t
TeamSignalEvent::Fire()
{
// We need a reference to the team to guarantee that it is still there when
// the DPC actually runs.
fTeam->AcquireReference();
status_t result = SignalEvent::Fire();
if (result != B_OK)
fTeam->ReleaseReference();
return result;
}
void
TeamSignalEvent::DoDPC(DPCQueue* queue)
{
@ -137,6 +151,7 @@ TeamSignalEvent::DoDPC(DPCQueue* queue)
status_t error = send_signal_to_team_locked(fTeam, fSignal->Number(),
fSignal, B_DO_NOT_RESCHEDULE);
locker.Unlock();
fTeam->ReleaseReference();
// There are situations (for certain signals), in which
// send_signal_to_team_locked() succeeds without queuing the signal.
@ -182,6 +197,20 @@ ThreadSignalEvent::Create(Thread* thread, uint32 signalNumber, int32 signalCode,
}
status_t
ThreadSignalEvent::Fire()
{
// We need a reference to the thread to guarantee that it is still there
// when the DPC actually runs.
fThread->AcquireReference();
status_t result = SignalEvent::Fire();
if (result != B_OK)
fThread->ReleaseReference();
return result;
}
void
ThreadSignalEvent::DoDPC(DPCQueue* queue)
{
@ -193,6 +222,7 @@ ThreadSignalEvent::DoDPC(DPCQueue* queue)
fSignal, B_DO_NOT_RESCHEDULE);
locker.Unlock();
teamLocker.Unlock();
fThread->ReleaseReference();
// There are situations (for certain signals), in which
// send_signal_to_team_locked() succeeds without queuing the signal.