| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "lib/fidl/cpp/internal/weak_stub_controller.h" |
| |
| namespace fidl { |
| namespace internal { |
| |
| WeakStubController::WeakStubController(StubController* controller) |
| : ref_count_(1u), |
| controller_(controller), |
| #if ZX_DEBUG_ASSERT_IMPLEMENTED |
| thread_(thrd_current()) |
| #else |
| thread_(thrd_t{}) |
| #endif |
| { |
| #if !ZX_DEBUG_ASSERT_IMPLEMENTED |
| // convince the compiler that thread_ is "used" in release |
| (void)thread_; |
| #endif |
| } |
| |
| WeakStubController::~WeakStubController() = default; |
| |
| void WeakStubController::AddRef() { |
| ZX_DEBUG_ASSERT_COND(IsCurrentThreadOk()); |
| ZX_DEBUG_ASSERT(ref_count_ != 0); |
| ++ref_count_; |
| } |
| |
| void WeakStubController::Release() { |
| // We have to allow !controller_ here, due to async::Loop::Shutdown() calling Invalidate(), |
| // Release() from a thread other than async::Loop::StartThread(), after the |
| // async::Loop::StartThread() thread has been joined. |
| ZX_DEBUG_ASSERT_COND(IsCurrentThreadOk() || !controller_); |
| ZX_DEBUG_ASSERT(ref_count_ > 0); |
| if (--ref_count_ == 0) |
| delete this; |
| } |
| |
| void WeakStubController::Invalidate() { |
| // This call can occur during async::Loop::Shutdown(), from a thread other than the thread created |
| // by async::Loop::StartThread(). In that usage path, it's typically ok, and in this method we |
| // don't attempt to detect cases that are not ok. In correct usage, the |
| // async::Loop::StartThread() thread has been joined, so that thread can't be touching |
| // WeakStubController. |
| controller_ = nullptr; |
| } |
| |
| StubController* WeakStubController::controller() const { |
| ZX_DEBUG_ASSERT_COND(IsCurrentThreadOk()); |
| return controller_; |
| } |
| |
| #if ZX_DEBUG_ASSERT_IMPLEMENTED |
| bool WeakStubController::IsCurrentThreadOk() const { |
| // The check for thrd_t{} will always be false, unless the release build constructor ran somehow |
| // despite the present method being debug-only. The extra check is to avoid asserting if the |
| // release constructor was used followed by debug methods. That's not expected to be common, but |
| // avoid asserting in mixed debug/release builds like that, just in case. |
| return (thrd_current() == thread_) || (thread_ == thrd_t{}); |
| } |
| #endif |
| |
| } // namespace internal |
| } // namespace fidl |