[revert][fit][scope] Revert "[fit][scope] Add a mechanism for scoping promises."

This reverts commit 4c6dbccd6c3fbb0f98a2297b1ad9b3361efd11bf.

Reason for revert: Causing roller failures.

Original change's description:
> [fit][scope] Add a mechanism for scoping promises.
>
> fit::scope is a mechanism for wrapping promises such that they will
> automatically be abandoned if the scope is exited before they complete.
> Can be very useful when handing out promises that capture references
> to "this" or to local variables.
>
> Test: fit-test
> Change-Id: I31a37d67e745156d3ee255fa1ed1060379d32bab

TBR=jeffbrown@google.com,thatguy@google.com,geb@google.com

Change-Id: I93594ec7daa97be647c8c241e0aa75381ba0c525
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
diff --git a/system/ulib/fit/include/lib/fit/scope.h b/system/ulib/fit/include/lib/fit/scope.h
deleted file mode 100644
index 6dc0bfc..0000000
--- a/system/ulib/fit/include/lib/fit/scope.h
+++ /dev/null
@@ -1,279 +0,0 @@
-// 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.
-
-#ifndef LIB_FIT_SCOPE_H_
-#define LIB_FIT_SCOPE_H_
-
-#include <assert.h>
-
-#include <atomic>
-#include <mutex>
-
-#include "promise.h"
-#include "thread_safety.h"
-
-namespace fit {
-
-// Provides a mechanism for binding promises to the lifetime of another object
-// such that they are destroyed before that object goes out of scope.  It is
-// particularly useful for ensuring that the lifetime of a promise does not
-// exceed the lifetime of any variables that it has captured by reference.
-//
-// A scope is thread-safe but non-reentrant: it must not be destroyed while
-// any of its associated promises are running.
-//
-// EXAMPLE
-//
-// Define a |fit::scope| as a member of the object to whose lifetime the
-// promises should be bound.
-//
-//     // We mark this class final because its destructor has side-effects
-//     // that rely on the order of destruction.  If this object were
-//     // subclassed there would be a possibility for promises bound to its
-//     // scope to inadvertently access the subclass's state while the object
-//     // was being destroyed.
-//     class accumulator final {
-//     public:
-//         accumulator() = default;
-//         ~accumulator() = default;
-//
-//         fit::promise<int> accumulate(int value);
-//
-//     private:
-//         int prior_total_ = 0;
-//
-//         // This member is last so that the scope is exited before all
-//         // other members of the object are destroyed.  Alternately, we
-//         // could enforce this ordering by explicitly invoking
-//         // |fit::scope::exit()| where appropriate.
-//         fit::scope scope_;
-//     };
-//
-// Use |fit::promise::wrap_with()| to wrap up promises that capture pointers
-// to the object.  In this example, the captured pointer is "this".
-//
-//     fit::promise<int> accumulator::accumulate(int value) {
-//         return fit::make_promise([this, value] {
-//             prior_total_ += value;
-//             return fit::ok(prior_total_);
-//         }).wrap_with(scope_); /* binding to scope happens here */
-//     }
-//
-class scope final {
-public:
-    // Creates a new scope.
-    scope();
-
-    // Exits the scope and destroys all of its wrapped promises.
-    // Asserts that no promises are currently running.
-    ~scope();
-
-    // Returns true if the scope has been exited.
-    //
-    // This method is thread-safe.
-    bool exited() const { return state_->exited(); }
-
-    // Exits the scope and destroys all of its wrapped promises.
-    // Assets that no promises are currently running.
-    //
-    // This method is thread-safe.
-    void exit() { return state_->exit(false /*scope_was_destroyed*/); }
-
-    // Returns a promise which wraps the specified |promise| and binds the
-    // promise to this scope.
-    //
-    // The specified promise will automatically be destroyed when its wrapper
-    // is destroyed or when the scope is exited.  If the scope has already
-    // exited then the wrapped promise will be immediately destroyed.
-    //
-    // When the returned promise is invoked before the scope is exited,
-    // the promise that it wraps will be invoked as usual.  However, when
-    // the returned promise is invoked after the scope is exited, it
-    // immediately returns a pending result (since the promise that it
-    // previously wrapped has already been destroyed).  By returning a
-    // pending result, the return promise effectively indicates to the
-    // executor that the task has been "abandoned" due to the scope being
-    // exited.
-    //
-    // This method is thread-safe.
-    template <typename Promise>
-    decltype(auto) wrap(Promise promise) {
-        assert(promise);
-        return fit::make_promise_with_continuation(
-            scoped_continuation<Promise>(
-                state_->link_promise(
-                    new promise_holder<Promise>(std::move(promise)))));
-    }
-
-    scope(const scope&) = delete;
-    scope(scope&&) = delete;
-    scope& operator=(const scope&) = delete;
-    scope& operator=(scope&&) = delete;
-
-private:
-    class state;
-    class promise_holder_base;
-
-    // Holds a reference to a promise that is owned by the state.
-    class promise_handle final {
-    public:
-        promise_handle() = default;
-
-    private:
-        // |state| and |promise_holder| belong to the state object.
-        // Invariant: If |promise_holder| is non-null then |state| is
-        // also non-null.
-        friend state;
-        promise_handle(state* state, promise_holder_base* promise_holder)
-            : state(state), promise_holder(promise_holder) {}
-
-        state* state = nullptr;
-        promise_holder_base* promise_holder = nullptr;
-    };
-
-    // Holds the shared state of the scope.
-    // This object is destroyed once the scope and all of its promises
-    // have been destroyed.
-    class state final {
-    public:
-        state();
-        ~state();
-
-        // The following methods are called from the |scope|.
-
-        bool exited() const;
-        void exit(bool scope_was_destroyed);
-
-        // The following methods are called from the |scoped_continuation|.
-
-        // Links a promise to the scope's lifecycle such that it will be
-        // destroyed when the scope is exited.  Returns a handle that may
-        // be used to access the promise later.
-        // The state takes ownership of the promise.
-        promise_handle link_promise(promise_holder_base* promise_holder);
-
-        // Unlinks a promise from the scope's lifecycle given its handle
-        // and causes the underlying promise to be destroyed if it hasn't
-        // already been destroyed due to the scope exiting.
-        // Does nothing if the handle was default-initialized.
-        static void unlink_and_drop_promise(promise_handle promise_handle);
-
-        // Acquires a promise given its handle.
-        // Returns nullptr if the handle was default-initialized or if
-        // the scope exited, meaning that the promise was not acquired.
-        // The promise must be released before it can be acquired again.
-        static promise_holder_base* try_acquire_promise(
-            promise_handle promise_handle);
-
-        // Releases a promise that was successfully acquired.
-        static void release_promise(promise_handle promise_handle);
-
-        state(const state&) = delete;
-        state(state&&) = delete;
-        state& operator=(const state&) = delete;
-        state& operator=(state&&) = delete;
-
-    private:
-        bool should_delete_self() const FIT_GUARDED(mutex_) {
-            return scope_was_destroyed_ && promise_handle_count_ == 0;
-        }
-
-        static constexpr uint64_t scope_exited = static_cast<uint64_t>(1u) << 63;
-
-        // Tracks of the number of promises currently running ("acquired").
-        // The top bit is set when the scope is exited, at which point no
-        // new promises can be acquired.  After exiting, the count can
-        // be incremented transiently but is immediately decremented again
-        // until all promise handles have been released.  Once no promise
-        // handles remain, the count will equal |scope_exited| and will not
-        // change again.
-        std::atomic_uint64_t acquired_promise_count_{0};
-
-        mutable std::mutex mutex_;
-        bool scope_was_destroyed_ FIT_GUARDED(mutex_) = false;
-        uint64_t promise_handle_count_ FIT_GUARDED(mutex_) = 0;
-        promise_holder_base* head_promise_holder_ FIT_GUARDED(mutex_) = nullptr;
-    };
-
-    // Base type for managing the lifetime of a promise of any type.
-    // It is owned by the state and retained indirectly by the continuation
-    // using a |promise_handle|.
-    class promise_holder_base {
-    public:
-        promise_holder_base() = default;
-        virtual ~promise_holder_base() = default;
-
-        promise_holder_base(const promise_holder_base&) = delete;
-        promise_holder_base(promise_holder_base&&) = delete;
-        promise_holder_base& operator=(const promise_holder_base&) = delete;
-        promise_holder_base& operator=(promise_holder_base&&) = delete;
-
-    private:
-        // |next| and |prev| belong to the state object.
-        friend class state;
-        promise_holder_base* next = nullptr;
-        promise_holder_base* prev = nullptr;
-    };
-
-    // Holder for a promise of a particular type.
-    template <typename Promise>
-    class promise_holder final : public promise_holder_base {
-    public:
-        explicit promise_holder(Promise promise)
-            : promise(std::move(promise)) {}
-        ~promise_holder() override = default;
-
-        Promise promise;
-    };
-
-    // Wraps a promise whose lifetime is managed by the scope.
-    template <typename Promise>
-    class scoped_continuation final {
-    public:
-        explicit scoped_continuation(promise_handle promise_handle)
-            : promise_handle_(promise_handle) {}
-
-        scoped_continuation(scoped_continuation&& other)
-            : promise_handle_(other.promise_handle_) {
-            other.promise_handle_ = promise_handle{};
-        }
-
-        ~scoped_continuation() {
-            state::unlink_and_drop_promise(promise_handle_);
-        }
-
-        typename Promise::result_type operator()(context& context) {
-            typename Promise::result_type result;
-            auto holder = static_cast<promise_holder<Promise>*>(
-                state::try_acquire_promise(promise_handle_));
-            if (holder) {
-                result = holder->promise(context);
-                state::release_promise(promise_handle_);
-            }
-            return result;
-        }
-
-        scoped_continuation& operator=(scoped_continuation&& other) {
-            if (this != &other) {
-                state::unlink_and_drop_promise(promise_handle_);
-                promise_handle_ = other.promise_handle_;
-                other.promise_handle_ = promise_handle{};
-            }
-            return *this;
-        }
-
-        scoped_continuation(const scoped_continuation&) = delete;
-        scoped_continuation& operator=(const scoped_continuation&) = delete;
-
-    private:
-        promise_handle promise_handle_;
-    };
-
-    // The scope's shared state.
-    state* const state_;
-};
-
-} // namespace fit
-
-#endif // LIB_FIT_SCOPE_H_
diff --git a/system/ulib/fit/rules.mk b/system/ulib/fit/rules.mk
index 692bbb7..80e0b82 100644
--- a/system/ulib/fit/rules.mk
+++ b/system/ulib/fit/rules.mk
@@ -7,7 +7,6 @@
 fit_srcs := \
     $(LOCAL_DIR)/promise.cpp \
     $(LOCAL_DIR)/scheduler.cpp \
-    $(LOCAL_DIR)/scope.cpp \
     $(LOCAL_DIR)/sequencer.cpp \
     $(LOCAL_DIR)/single_threaded_executor.cpp \
 
diff --git a/system/ulib/fit/scope.cpp b/system/ulib/fit/scope.cpp
deleted file mode 100644
index c1cbea7..0000000
--- a/system/ulib/fit/scope.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-// 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.
-
-// Can't compile this for Zircon userspace yet since libstdc++ isn't available.
-#ifndef FIT_NO_STD_FOR_ZIRCON_USERSPACE
-
-#include <lib/fit/scope.h>
-
-namespace fit {
-
-scope::scope()
-    : state_(new state()) {}
-
-scope::~scope() {
-    state_->exit(true /*scope_was_destroyed*/);
-}
-
-scope::state::state() = default;
-
-scope::state::~state() {
-    assert(acquired_promise_count_.load(std::memory_order_relaxed) ==
-           scope_exited);
-    assert(scope_was_destroyed_);
-    assert(promise_handle_count_ == 0);
-    assert(head_promise_holder_ == nullptr);
-}
-
-bool scope::state::exited() const {
-    return acquired_promise_count_.load(std::memory_order_relaxed) & scope_exited;
-}
-
-void scope::state::exit(bool scope_was_destroyed) {
-    promise_holder_base* release_head = nullptr;
-    bool delete_self = false;
-    {
-        std::lock_guard<std::mutex> lock(mutex_);
-        assert(!scope_was_destroyed_);
-        scope_was_destroyed_ = scope_was_destroyed;
-
-        // Atomically exit the scope.  We cannot do this safely if there are
-        // any running promises since they might still be accessing state which
-        // is guarded by the scope.  Worse, if a promise re-entrantly destroys
-        // the scope during its execution then as a side-effect the promise
-        // itself will be destroyed.  So assert!
-        uint64_t prior_count = acquired_promise_count_.exchange(
-            scope_exited, std::memory_order_relaxed);
-        if (!(prior_count & scope_exited)) {
-            // Cannot exit fit::scope while any of its promises are running!
-            assert(prior_count == 0);
-
-            // Take the promises so they can be deleted outside of the lock.
-            release_head = head_promise_holder_;
-            head_promise_holder_ = nullptr;
-        }
-
-        // If there are no more handles then we can delete the state now.
-        delete_self = should_delete_self();
-    }
-
-    // Delete aborted promises and self outside of the lock.
-    while (release_head) {
-        promise_holder_base* release_next = release_head->next;
-        delete release_head;
-        release_head = release_next;
-    }
-    if (delete_self) {
-        delete this;
-    }
-}
-
-scope::promise_handle scope::state::link_promise(
-    promise_holder_base* promise_holder) {
-    {
-        std::lock_guard<std::mutex> lock(mutex_);
-        assert(!scope_was_destroyed_); // otherwise how did we get here?
-
-        // If the scope hasn't been exited yet, link the promise and mint
-        // a new handle.  Otherwise we will abort the promise.
-        if (!exited()) {
-            if (head_promise_holder_) {
-                head_promise_holder_->prev = promise_holder;
-                promise_holder->next = head_promise_holder_;
-            }
-            head_promise_holder_ = promise_holder;
-            promise_handle_count_++;
-            return promise_handle(this, promise_holder);
-        }
-    }
-
-    // Delete aborted promise outside of the lock.
-    delete promise_holder;
-    return promise_handle{};
-}
-
-void scope::state::unlink_and_drop_promise(promise_handle promise_handle) {
-    if (!promise_handle.promise_holder) {
-        return; // invalid handle, nothing to do
-    }
-
-    {
-        std::lock_guard<std::mutex> lock(promise_handle.state->mutex_);
-
-        // If the scope hasn't been exited yet, unlink the promise and
-        // prepare to destroy it.  Otherwise, it's already been unlinked
-        // and destroyed so release the handle but don't touch the pointer!
-        assert(promise_handle.state->promise_handle_count_ > 0);
-        promise_handle.state->promise_handle_count_--;
-        if (!promise_handle.state->exited()) {
-            if (promise_handle.promise_holder->next) {
-                promise_handle.promise_holder->next->prev =
-                    promise_handle.promise_holder->prev;
-            }
-            if (promise_handle.promise_holder->prev) {
-                promise_handle.promise_holder->prev->next =
-                    promise_handle.promise_holder->next;
-            } else {
-                promise_handle.state->head_promise_holder_ =
-                    promise_handle.promise_holder->next;
-            }
-            // Fallthrough to delete the promise.
-        } else if (!promise_handle.state->should_delete_self()) {
-            return;
-        } else {
-            // Fallthrough to delete self.
-            promise_handle.promise_holder = nullptr;
-        }
-    }
-
-    // Delete the promise or scope outside of the lock.
-    if (promise_handle.promise_holder) {
-        delete promise_handle.promise_holder;
-    } else {
-        delete promise_handle.state;
-    }
-}
-
-scope::promise_holder_base* scope::state::try_acquire_promise(
-    promise_handle promise_handle) {
-    if (promise_handle.promise_holder) {
-        uint64_t prior_count = promise_handle.state->acquired_promise_count_.fetch_add(
-            1u, std::memory_order_relaxed);
-        if (!(prior_count & scope_exited)) {
-            return promise_handle.promise_holder;
-        }
-        promise_handle.state->acquired_promise_count_.fetch_sub(
-            1u, std::memory_order_relaxed);
-    }
-    return nullptr;
-}
-
-void scope::state::release_promise(promise_handle promise_handle) {
-    promise_handle.state->acquired_promise_count_.fetch_sub(
-        1u, std::memory_order_relaxed);
-}
-
-} // namespace fit
-
-#endif // FIT_NO_STD_FOR_ZIRCON_USERSPACE
diff --git a/system/utest/fit/rules.mk b/system/utest/fit/rules.mk
index efaa2aa..9443e4a 100644
--- a/system/utest/fit/rules.mk
+++ b/system/utest/fit/rules.mk
@@ -21,7 +21,6 @@
     $(LOCAL_DIR)/promise_tests.cpp \
     $(LOCAL_DIR)/result_tests.cpp \
     $(LOCAL_DIR)/scheduler_tests.cpp \
-    $(LOCAL_DIR)/scope_tests.cpp \
     $(LOCAL_DIR)/sequencer_tests.cpp \
     $(LOCAL_DIR)/single_threaded_executor_tests.cpp \
     $(LOCAL_DIR)/suspended_task_tests.cpp \
diff --git a/system/utest/fit/scope_tests.cpp b/system/utest/fit/scope_tests.cpp
deleted file mode 100644
index aa41cdf..0000000
--- a/system/utest/fit/scope_tests.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-// 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 <unistd.h>
-
-#include <thread>
-
-#include <lib/fit/bridge.h>
-#include <lib/fit/defer.h>
-#include <lib/fit/scope.h>
-#include <lib/fit/single_threaded_executor.h>
-#include <unittest/unittest.h>
-
-#include "unittest_utils.h"
-
-namespace {
-
-class fake_context : public fit::context {
-public:
-    fit::executor* executor() const override {
-        ASSERT_CRITICAL(false);
-    }
-    fit::suspended_task suspend_task() override {
-        ASSERT_CRITICAL(false);
-    }
-};
-
-// Asynchronously accumulates a sum.
-// This is an example of an object that offers promises that captures
-// the "this" pointer, thereby needing a scope to prevent dangling pointers
-// in case it is destroyed before the promises complete.
-class accumulator {
-public:
-    // Adds a value to the counter then returns it.
-    // Takes time proportional to the value being added.
-    fit::promise<uint32_t> add(uint32_t value) {
-        return fit::make_promise(
-                   [this, cycles = value](fit::context& context) mutable
-                   -> fit::result<uint32_t> {
-                       if (cycles == 0)
-                           return fit::ok(counter_);
-                       counter_++;
-                       cycles--;
-                       context.suspend_task().resume_task();
-                       return fit::pending();
-                   })
-            .wrap_with(scope_);
-    }
-
-    // Gets the current count, immediately.
-    uint32_t count() const { return counter_; }
-
-private:
-    fit::scope scope_;
-    uint32_t counter_ = 0;
-};
-
-bool scoping_tasks() {
-    BEGIN_TEST;
-
-    auto acc = std::make_unique<accumulator>();
-    fit::single_threaded_executor executor;
-    uint32_t sums[4] = {};
-
-    // Schedule some tasks which accumulate values asynchronously.
-    executor.schedule_task(acc->add(2).and_then(
-        [&](uint32_t value) { sums[0] = value; }));
-    executor.schedule_task(acc->add(1).and_then(
-        [&](uint32_t value) { sums[1] = value; }));
-    executor.schedule_task(acc->add(5).and_then(
-        [&](uint32_t value) { sums[2] = value; }));
-
-    // Schedule a task which accumulates and then destroys the accumulator
-    // so that the scope is exited.  Any remaining promises will be aborted.
-    uint32_t last_count = 0;
-    executor.schedule_task(acc->add(3).and_then(
-        [&](uint32_t value) {
-            sums[3] = value;
-            // Schedule destruction in another task to avoid re-entrance.
-            executor.schedule_task(fit::make_promise([&] {
-                last_count = acc->count();
-                acc.reset();
-            }));
-        }));
-
-    // Run the tasks.
-    executor.run();
-
-    // The counts reflect the fact that the scope is exited part-way through
-    // the cycle.  For example, the sums[2] task doesn't get to run since
-    // it only runs after 5 cycles and the scope is exited on the third.
-    EXPECT_EQ(11, last_count);
-    EXPECT_EQ(7, sums[0]);
-    EXPECT_EQ(5, sums[1]);
-    EXPECT_EQ(0, sums[2]);
-    EXPECT_EQ(10, sums[3]);
-
-    END_TEST;
-}
-
-bool exit_destroys_wrapped_promises() {
-    BEGIN_TEST;
-
-    fit::scope scope;
-    EXPECT_FALSE(scope.exited());
-
-    // Set up three wrapped promises.
-    bool destroyed[4] = {};
-    auto p0 = scope.wrap(fit::make_promise(
-        [d = fit::defer([&] { destroyed[0] = true; })] { return fit::ok(); }));
-    auto p1 = scope.wrap(fit::make_promise(
-        [d = fit::defer([&] { destroyed[1] = true; })] { return fit::ok(); }));
-    auto p2 = scope.wrap(fit::make_promise(
-        [d = fit::defer([&] { destroyed[2] = true; })] { return fit::ok(); }));
-    EXPECT_FALSE(destroyed[0]);
-    EXPECT_FALSE(destroyed[1]);
-    EXPECT_FALSE(destroyed[2]);
-
-    // Execute one of them to completion, causing it to be destroyed.
-    EXPECT_TRUE(fit::run_single_threaded(std::move(p1)).is_ok());
-    EXPECT_FALSE(destroyed[0]);
-    EXPECT_TRUE(destroyed[1]);
-    EXPECT_FALSE(destroyed[2]);
-
-    // Exit the scope, causing the wrapped promise to be destroyed
-    // while still leaving the wrapper alive (but aborted).
-    scope.exit();
-    EXPECT_TRUE(scope.exited());
-    EXPECT_TRUE(destroyed[0]);
-    EXPECT_TRUE(destroyed[1]);
-    EXPECT_TRUE(destroyed[2]);
-
-    // Wrapping another promise causes the wrapped promise to be immediately
-    // destroyed.
-    auto p3 = scope.wrap(fit::make_promise(
-        [d = fit::defer([&] { destroyed[3] = true; })] { return fit::ok(); }));
-    EXPECT_TRUE(destroyed[3]);
-
-    // Executing the wrapped promises returns pending.
-    EXPECT_TRUE(fit::run_single_threaded(std::move(p0)).is_pending());
-    EXPECT_TRUE(fit::run_single_threaded(std::move(p2)).is_pending());
-    EXPECT_TRUE(fit::run_single_threaded(std::move(p3)).is_pending());
-
-    // Exiting again has no effect.
-    scope.exit();
-    EXPECT_TRUE(scope.exited());
-
-    END_TEST;
-}
-
-bool double_wrap() {
-    BEGIN_TEST;
-
-    fit::scope scope;
-    fake_context context;
-
-    // Here we wrap a task that's already been wrapped to see what happens
-    // when the scope is exited.  This is interesting because it means that
-    // the destruction of one wrapped promise will cause the destruction of
-    // another wrapped promise and could uncover re-entrance issues.
-    uint32_t run_count = 0;
-    bool destroyed = false;
-    auto promise =
-        fit::make_promise(
-            [&, d = fit::defer([&] { destroyed = true; })](fit::context& context) {
-                run_count++;
-                return fit::pending();
-            })
-            .wrap_with(scope)
-            .wrap_with(scope); // wrap again!
-
-    // Run the promise once to show that we can.
-    EXPECT_EQ(fit::result_state::pending, promise(context).state());
-    EXPECT_EQ(1, run_count);
-    EXPECT_FALSE(destroyed);
-
-    // Now exit the scope, which should cause the promise to be destroyed.
-    scope.exit();
-    EXPECT_EQ(1, run_count);
-    EXPECT_TRUE(destroyed);
-
-    // Running the promise again should do nothing.
-    EXPECT_EQ(fit::result_state::pending, promise(context).state());
-    EXPECT_EQ(1, run_count);
-    EXPECT_TRUE(destroyed);
-
-    END_TEST;
-}
-
-bool thread_safety() {
-    BEGIN_TEST;
-
-    fit::scope scope;
-    fit::single_threaded_executor executor;
-    uint64_t run_count = 0;
-
-    // Schedule work from a few threads, just to show that we can.
-    // Part way through, exit the scope.
-    constexpr int num_threads = 4;
-    constexpr int num_tasks_per_thread = 100;
-    constexpr int exit_threshold = 75;
-    std::thread threads[num_threads];
-    for (int i = 0; i < num_threads; i++) {
-        fit::bridge bridge;
-        threads[i] =
-            std::thread([&, completer = std::move(bridge.completer)]() mutable {
-                for (int j = 0; j < num_tasks_per_thread; j++) {
-                    if (j == exit_threshold) {
-                        executor.schedule_task(fit::make_promise([&] {
-                            scope.exit();
-                        }));
-                    }
-
-                    executor.schedule_task(
-                        fit::make_promise([&] {
-                            run_count++;
-                        }).wrap_with(scope));
-                }
-                completer.complete_ok();
-            });
-        executor.schedule_task(bridge.consumer.promise());
-    }
-
-    // Run the tasks.
-    executor.run();
-    for (int i = 0; i < num_threads; i++)
-        threads[i].join();
-
-    // We expect some non-deterministic number of tasks to have run
-    // related to the exit threshold.
-    // We scheduled num_threads * num_tasks_per_thread tasks, but on each thread
-    // we exited the (common) scope after scheduling its first exit_threshold
-    // tasks.  Once one of those threads exits the scope, no more tasks
-    // (scheduled by any thread) will run within the scope, so the number of
-    // executed tasks cannot increase any further.  Therefore we know that at
-    // least exit_threshold tasks have run but we could have run as many as
-    // num_threads * exit_threshold in a perfect world where all of the threads
-    // called scope.exit() at the same time.
-    EXPECT_GE(run_count, exit_threshold);
-    EXPECT_LE(run_count, num_threads * exit_threshold);
-
-    END_TEST;
-}
-
-} // namespace
-
-BEGIN_TEST_CASE(scope_tests)
-RUN_TEST(scoping_tasks)
-RUN_TEST(exit_destroys_wrapped_promises)
-RUN_TEST(double_wrap)
-RUN_TEST(thread_safety)
-END_TEST_CASE(scope_tests)