[nand] Fix race where we miss wakeups.
Tested: runtests -t nand-unittest
Change-Id: Ibd986138813d07d8001151ea1b0bb0ccdec8f2b0
diff --git a/zircon/system/dev/nand/nand/nand.cpp b/zircon/system/dev/nand/nand/nand.cpp
index b692d903..5a5d150 100644
--- a/zircon/system/dev/nand/nand/nand.cpp
+++ b/zircon/system/dev/nand/nand/nand.cpp
@@ -190,23 +190,16 @@
// Initialization is complete by the time the thread starts.
zx_status_t NandDevice::WorkerThread() {
for (;;) {
- // Don't loop until txn_queue_ is empty to check for shutdown.
- // between each io.
- for (auto txn = txn_queue_.pop(); txn; txn = txn_queue_.pop()) {
- {
- fbl::AutoLock al(&lock_);
- if (shutdown_) {
- break;
- }
- }
- DoIo(*std::move(txn));
- }
-
fbl::AutoLock al(&lock_);
+ while (txn_queue_.is_empty() && !shutdown_) {
+ worker_event_.Wait(&lock_);
+ }
if (shutdown_) {
break;
}
- worker_event_.Wait(&lock_);
+ auto txn = txn_queue_.pop();
+ al.release();
+ DoIo(*std::move(txn));
}
zxlogf(TRACE, "nand: worker thread terminated\n");
@@ -257,6 +250,7 @@
}
// TODO: UPDATE STATS HERE.
+ fbl::AutoLock al(&lock_);
txn_queue_.push(std::move(txn));
worker_event_.Signal();
}
@@ -276,11 +270,12 @@
{
fbl::AutoLock al(&lock_);
shutdown_ = true;
+ worker_event_.Signal();
}
- worker_event_.Signal();
thrd_join(worker_thread_, nullptr);
// Error out all pending requests.
+ fbl::AutoLock al(&lock_);
txn_queue_.Release();
}
diff --git a/zircon/system/dev/nand/nand/nand.h b/zircon/system/dev/nand/nand/nand.h
index 4bba55f..b286c2e 100644
--- a/zircon/system/dev/nand/nand/nand.h
+++ b/zircon/system/dev/nand/nand/nand.h
@@ -79,10 +79,10 @@
uint32_t num_nand_pages_;
thrd_t worker_thread_;
- nand::UnownedOperationQueue<> txn_queue_;
fbl::Mutex lock_;
- fbl::ConditionVariable worker_event_;
+ nand::UnownedOperationQueue<> txn_queue_ TA_GUARDED(lock_);
+ fbl::ConditionVariable worker_event_ TA_GUARDED(lock_);
bool shutdown_ TA_GUARDED(lock_) = false;
};