kernel/fifo: Don't unlock before unblock.

Otherwise there is a race that can occur if the waiting thread is
interrupted (or hasn't slept yet) while the writing thread tries to
unblock it.

Instead, don't call SetNotified again if we unblocked with a status
of B_OK. This can only happen when we were notified by another thread
successfully.

Should help with #19458.

Change-Id: Iad46b26374a01539f8765231d259392c231c786a
Reviewed-on: https://review.haiku-os.org/c/haiku/+/9085
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Augustin Cavalier
2025-03-06 15:00:31 +00:00
committed by waddlesplash
parent 240f1a0e91
commit 0958031b24
+6 -10
View File
@@ -107,17 +107,11 @@ public:
void Notify(status_t status = B_OK)
{
InterruptsLocker _;
SpinLocker spinLocker(fLock);
InterruptsSpinLocker spinLocker(fLock);
TRACE("ReadRequest %p::Notify(), fNotified %d\n", this, fNotified);
if (!fNotified) {
fNotified = true;
// Whoever calls Notify() must hold the requests lock,
// so we can be sure this Request won't be deleted.
spinLocker.Unlock();
thread_unblock(fThread, status);
}
}
@@ -697,9 +691,11 @@ Inode::WaitForReadRequest(ReadRequest& request)
rw_lock_read_unlock(&fChangeLock);
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);
if (status != B_OK) {
// 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);
}
rw_lock_read_lock(&fChangeLock);