diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 573f866548a21..905c8dcdf24de 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -495,6 +495,9 @@ FILE: ../../../flutter/fml/platform/win/errors_win.h FILE: ../../../flutter/fml/platform/win/file_win.cc FILE: ../../../flutter/fml/platform/win/native_library_win.cc FILE: ../../../flutter/fml/platform/win/wstring_conversion.h +FILE: ../../../flutter/fml/synchronization/count_down_latch.cc +FILE: ../../../flutter/fml/synchronization/count_down_latch.h +FILE: ../../../flutter/fml/synchronization/count_down_latch_unittests.cc FILE: ../../../flutter/fml/unique_fd.cc FILE: ../../../flutter/fml/unique_fd.h FILE: ../../../flutter/fml/unique_object.h diff --git a/fml/BUILD.gn b/fml/BUILD.gn index 25e065c8b1fe9..4edc9aadf5e45 100644 --- a/fml/BUILD.gn +++ b/fml/BUILD.gn @@ -46,6 +46,8 @@ source_set("fml") { "paths.h", "string_view.cc", "string_view.h", + "synchronization/count_down_latch.cc", + "synchronization/count_down_latch.h", "synchronization/thread_annotations.h", "synchronization/thread_checker.h", "synchronization/waitable_event.cc", @@ -176,6 +178,7 @@ executable("fml_unittests") { "message_unittests.cc", "paths_unittests.cc", "string_view_unittest.cc", + "synchronization/count_down_latch_unittests.cc", "synchronization/thread_annotations_unittest.cc", "synchronization/thread_checker_unittest.cc", "synchronization/waitable_event_unittest.cc", diff --git a/fml/synchronization/count_down_latch.cc b/fml/synchronization/count_down_latch.cc new file mode 100644 index 0000000000000..5eeb012b97e4a --- /dev/null +++ b/fml/synchronization/count_down_latch.cc @@ -0,0 +1,29 @@ +// Copyright 2018 The Flutter 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 "flutter/fml/synchronization/count_down_latch.h" + +#include "flutter/fml/logging.h" + +namespace fml { + +CountDownLatch::CountDownLatch(size_t count) : count_(count) { + if (count_ == 0) { + waitable_event_.Signal(); + } +} + +CountDownLatch::~CountDownLatch() = default; + +void CountDownLatch::Wait() { + waitable_event_.Wait(); +} + +void CountDownLatch::CountDown() { + if (--count_ == 0) { + waitable_event_.Signal(); + } +} + +} // namespace fml diff --git a/fml/synchronization/count_down_latch.h b/fml/synchronization/count_down_latch.h new file mode 100644 index 0000000000000..87148f6df0367 --- /dev/null +++ b/fml/synchronization/count_down_latch.h @@ -0,0 +1,29 @@ +// Copyright 2018 The Flutter 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 + +#include "flutter/fml/macros.h" +#include "flutter/fml/synchronization/waitable_event.h" + +namespace fml { + +class CountDownLatch { + public: + CountDownLatch(size_t count); + + ~CountDownLatch(); + + void Wait(); + + void CountDown(); + + private: + std::atomic_size_t count_; + ManualResetWaitableEvent waitable_event_; + + FML_DISALLOW_COPY_AND_ASSIGN(CountDownLatch); +}; + +} // namespace fml diff --git a/fml/synchronization/count_down_latch_unittests.cc b/fml/synchronization/count_down_latch_unittests.cc new file mode 100644 index 0000000000000..2c85b9474612b --- /dev/null +++ b/fml/synchronization/count_down_latch_unittests.cc @@ -0,0 +1,39 @@ +// Copyright 2018 The Flutter 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 +#include + +#include "flutter/fml/synchronization/count_down_latch.h" +#include "flutter/fml/thread.h" +#include "flutter/testing/testing.h" + +namespace fml { + +TEST(CountDownLatchTest, CanWaitOnZero) { + CountDownLatch latch(0); + latch.Wait(); +} + +TEST(CountDownLatchTest, CanWait) { + fml::Thread thread("test_thread"); + const size_t count = 100; + size_t current_count = 0; + CountDownLatch latch(count); + auto decrement_latch_on_thread = [runner = thread.GetTaskRunner(), &latch, + ¤t_count]() { + runner->PostTask([&latch, ¤t_count]() { + std::this_thread::sleep_for(std::chrono::microseconds(100)); + current_count++; + latch.CountDown(); + }); + }; + for (size_t i = 0; i < count; ++i) { + decrement_latch_on_thread(); + } + latch.Wait(); + ASSERT_EQ(current_count, count); +} + +} // namespace fml