Fixed serious race condition: If the thread waiting for a request was

interrupted, another thread closing the other end of the pipe could
invoke thread_unblock() while the first thread already entered
mutex_lock(). This would make the first thread think it successfully
locked the mutex, without removing its (on-stack) wait entry from the
mutex queue, thus leading to crashes.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28195 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2008-10-16 21:40:32 +00:00
parent 9f3fce1eac
commit d52718a5f8

View File

@ -76,23 +76,34 @@ class RingBuffer {
class ReadRequest : public DoublyLinkedListLinkImpl<ReadRequest> {
public:
ReadRequest()
: fThread(find_thread(NULL))
:
fThread(thread_get_current_thread()),
fNotified(true)
{
B_INITIALIZE_SPINLOCK(&fLock);
}
void SetUnnotified() { fNotified = false; }
void SetNotified(bool notified)
{
InterruptsSpinLocker _(fLock);
fNotified = notified;
}
void Notify()
{
InterruptsSpinLocker _(fLock);
if (!fNotified) {
thread_unblock(fThread, B_OK);
SpinLocker threadLocker(gThreadSpinlock);
thread_unblock_locked(fThread, B_OK);
fNotified = true;
}
}
private:
thread_id fThread;
bool fNotified;
spinlock fLock;
struct thread* fThread;
volatile bool fNotified;
};
@ -464,15 +475,20 @@ Inode::RemoveReadRequest(ReadRequest &request)
status_t
Inode::WaitForReadRequest(ReadRequest &request)
{
request.SetUnnotified();
// add the entry to wait on
thread_prepare_to_block(thread_get_current_thread(), B_CAN_INTERRUPT,
THREAD_BLOCK_TYPE_OTHER, "fifo read request");
request.SetNotified(false);
// wait
mutex_unlock(&fRequestLock);
status_t status = thread_block();
// Before going to lock again, we need to make sure no one tries to
// unblock us. Otherwise that would screw with mutex_lock().
request.SetNotified(true);
mutex_lock(&fRequestLock);
return status;