Fixed a race condition on thread exit: There was a gap between releasing

the death stack and reacquiring the thread lock in which another thread
could snatch our stack that we were still going to use for the
scheduler. Now we've got a second spinlock that we can hold while
releasing a semaphore.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22403 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2007-10-01 22:46:56 +00:00
parent 8609f5a242
commit 3c3674113f

View File

@ -87,6 +87,7 @@ static struct death_stack *sDeathStacks;
static unsigned int sNumDeathStacks;
static unsigned int volatile sDeathStackBitmap;
static sem_id sDeathStackSem;
static spinlock sDeathStackLock = 0;
static struct thread *last_thread_dumped = NULL;
@ -524,14 +525,19 @@ get_death_stack(void)
acquire_sem(sDeathStackSem);
// grab the death stack and thread locks, find a free spot and release
state = disable_interrupts();
// grap the thread lock, find a free spot and release
acquire_spinlock(&sDeathStackLock);
GRAB_THREAD_LOCK();
bit = sDeathStackBitmap;
bit = (~bit) & ~((~bit) - 1);
sDeathStackBitmap |= bit;
RELEASE_THREAD_LOCK();
release_spinlock(&sDeathStackLock);
restore_interrupts(state);
@ -553,12 +559,12 @@ get_death_stack(void)
}
/*! Returns the thread's death stack to the pool. */
/*! Returns the thread's death stack to the pool.
Interrupts must be disabled and the sDeathStackLock be held.
*/
static void
put_death_stack(uint32 index)
{
cpu_status state;
TRACE(("put_death_stack...: passed %lu\n", index));
if (index >= sNumDeathStacks)
@ -567,16 +573,12 @@ put_death_stack(uint32 index)
if (!(sDeathStackBitmap & (1 << index)))
panic("put_death_stack: passed invalid stack index %ld\n", index);
state = disable_interrupts();
GRAB_THREAD_LOCK();
sDeathStackBitmap &= ~(1 << index);
RELEASE_THREAD_LOCK();
restore_interrupts(state);
release_sem_etc(sDeathStackSem, 1, B_DO_NOT_RESCHEDULE);
// we must not have acquired the thread lock when releasing a semaphore
// we must not hold the thread lock when releasing a semaphore
}
@ -634,9 +636,14 @@ thread_exit2(void *_args)
// return the death stack and reschedule one last time
// Note that we need to hold sDeathStackLock until we've got the thread
// lock. Otherwise someone else might grab our stack in the meantime.
acquire_spinlock(&sDeathStackLock);
put_death_stack(args.death_stack);
GRAB_THREAD_LOCK();
release_spinlock(&sDeathStackLock);
scheduler_reschedule();
// requires thread lock to be held
@ -1273,6 +1280,7 @@ thread_exit(void)
args.death_sem = cachedDeathSem;
args.original_team_id = teamID;
disable_interrupts();
// set the new kernel stack officially to the death stack, it won't be