[usb][mediatek] Fix thread teardown race.
Currently, zx-primitives are being used to synchronize the halting of a
processing thread. This is racy if the containing object is being
deallocated. This replaces the primitives with a call to thrd_join(),
which fixes the race. This seems to only affect clang-x64 builds.
FLK-244 #done
Test: runtests -t mt-hci-endpoint-test-test -r 1000 (~3% racy before)
Change-Id: Ifa2f58f876d117868d4b2ea7fc0ebc0a52d3dd7a
diff --git a/zircon/system/dev/usb/mt-musb-host/usb-device.cpp b/zircon/system/dev/usb/mt-musb-host/usb-device.cpp
index b582e66..5cf0028 100644
--- a/zircon/system/dev/usb/mt-musb-host/usb-device.cpp
+++ b/zircon/system/dev/usb/mt-musb-host/usb-device.cpp
@@ -65,7 +65,6 @@
for (uint8_t i=0; i<=kMaxEpNum; i++) {
if (ep_[i] != nullptr) {
ep_[i]->Halt();
- ep_[i]->Join();
}
}
}
diff --git a/zircon/system/dev/usb/mt-musb-host/usb-endpoint-test.cpp b/zircon/system/dev/usb/mt-musb-host/usb-endpoint-test.cpp
index 76cf71c..6f0349b 100644
--- a/zircon/system/dev/usb/mt-musb-host/usb-endpoint-test.cpp
+++ b/zircon/system/dev/usb/mt-musb-host/usb-endpoint-test.cpp
@@ -102,7 +102,6 @@
TestingEndpoint te(mmio_->View(0));
EXPECT_OK(te.StartQueueThread());
EXPECT_OK(te.Halt());
- te.Join();
}
TEST_F(TransactionEndpointTest, QueueThread_Enqueue) {
@@ -118,7 +117,6 @@
te.Wait();
EXPECT_OK(te.Halt());
- te.Join();
te.m_dispatch().VerifyAndClear();
}
@@ -158,7 +156,6 @@
te.Wait(5);
EXPECT_OK(te.Halt());
- te.Join();
te.m_dispatch().VerifyAndClear();
}
@@ -198,7 +195,6 @@
te.Wait(5);
EXPECT_OK(te.Halt());
- te.Join();
te.m_dispatch().VerifyAndClear();
}
@@ -238,7 +234,6 @@
te.Wait(5);
EXPECT_OK(te.Halt());
- te.Join();
te.m_dispatch().VerifyAndClear();
}
diff --git a/zircon/system/dev/usb/mt-musb-host/usb-endpoint.cpp b/zircon/system/dev/usb/mt-musb-host/usb-endpoint.cpp
index a8a9caa..b7c759a 100644
--- a/zircon/system/dev/usb/mt-musb-host/usb-endpoint.cpp
+++ b/zircon/system/dev/usb/mt-musb-host/usb-endpoint.cpp
@@ -57,13 +57,27 @@
}
zx_status_t TransactionEndpoint::Halt() {
- fbl::AutoLock _(&pending_lock_);
- if (transaction_) {
- transaction_->Cancel();
+ {
+ fbl::AutoLock _(&pending_lock_);
+ if (transaction_) {
+ transaction_->Cancel();
+ }
+
+ halted_ = true;
+ pending_cond_.Signal();
}
- halted_ = true;
- pending_cond_.Signal();
+ if (pending_thread_) {
+ int rc;
+ int status = thrd_join(pending_thread_, &rc);
+ if (status != thrd_success) {
+ zxlogf(ERROR, "could not join pending_thread\n");
+ return ZX_ERR_INTERNAL;
+ } else if (rc != 0) {
+ zxlogf(ERROR, "pending_thread returned nonzero status: %d\n", rc);
+ return ZX_ERR_INTERNAL;
+ }
+ }
return ZX_OK;
}
@@ -77,7 +91,6 @@
fbl::AutoLock _(&pending_lock_);
if (pending_.is_empty()) {
if (halted_.load()) {
- sync_completion_signal(&complete_);
return 0;
}
@@ -88,7 +101,6 @@
pending_cond_.Wait(&pending_lock_);
if (halted_.load()) {
- sync_completion_signal(&complete_);
return 0;
}
}
diff --git a/zircon/system/dev/usb/mt-musb-host/usb-endpoint.h b/zircon/system/dev/usb/mt-musb-host/usb-endpoint.h
index 6a46207..9dbb7d95 100644
--- a/zircon/system/dev/usb/mt-musb-host/usb-endpoint.h
+++ b/zircon/system/dev/usb/mt-musb-host/usb-endpoint.h
@@ -48,9 +48,6 @@
// Halt endpoint request processing. All outstanding requests will result in a
// ZX_ERR_IO_NOT_PRESENT status, and the queue thread will be shut down.
virtual zx_status_t Halt() = 0;
-
- // Block and wait until this endpoint is fully halted.
- virtual void Join() = 0;
};
// A TransactionEndpoint is an Endpoint which dispatches requests to a Transaction for processing.
@@ -72,7 +69,6 @@
zx_status_t CancelAll() override;
size_t GetMaxTransferSize() override ;
zx_status_t Halt() override;
- void Join() override { __UNUSED auto _ = sync_completion_wait(&complete_, ZX_TIME_INFINITE); }
protected:
// The USB register mmio.
@@ -111,9 +107,6 @@
// Queue dispatch condition and associated mutex.
fbl::Mutex pending_lock_;
fbl::ConditionVariable pending_cond_ TA_GUARDED(pending_lock_);
-
- // A completion that is signaled upon completing the halt process.
- sync_completion_t complete_;
};
// A ControlEndpoint is an Endpoint dispatching control-type transactions.