1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef LIB_FIT_SEQUENCER_H_ 6 #define LIB_FIT_SEQUENCER_H_ 7 8 #include <assert.h> 9 10 #include <mutex> 11 12 #include "bridge.h" 13 #include "thread_safety.h" 14 15 namespace fit { 16 17 // A sequencer imposes a first-in-first-out sequential execution order onto a 18 // sequence of promises. Each successively enqueued promise remains suspended 19 // until all previously enqueued promises complete or are abandoned. 20 // 21 // |fit::sequencer| is designed to be used either on its own or chained 22 // onto a promise using |fit::promise::wrap_with()|. 23 // 24 // EXAMPLE 25 // 26 // // This wrapper type is intended to be applied to 27 // // a sequence of promises so we store it in a variable. 28 // fit::sequencer seq; 29 // 30 // // This task consists of some amount of work that must be 31 // // completed sequentially followed by other work that can 32 // // happen in any order. We use |wrap_with()| to wrap the 33 // // sequential work with the sequencer. 34 // fit::promise<> perform_complex_task() { 35 // return fit::make_promise([] { /* do sequential work */ }) 36 // .then([] (fit::result<> result) { /* this will also be wrapped */ }) 37 // .wrap_with(seq) 38 // .then([] (fit::result<> result) { /* do more work */ }); 39 // } 40 // 41 class sequencer final { 42 public: 43 sequencer(); 44 ~sequencer(); 45 46 // Returns a new promise which will invoke |promise| after all previously 47 // enqueued promises on this sequencer have completed or been abandoned. 48 // 49 // This method is thread-safe. 50 template <typename Promise> decltype(auto)51 decltype(auto) wrap(Promise promise) { 52 assert(promise); 53 54 fit::bridge<> bridge; 55 fit::consumer<> prior = swap_prior(std::move(bridge.consumer)); 56 return prior.promise_or(fit::ok()) 57 .then([promise = std::move(promise), 58 completer = std::move(bridge.completer)]( 59 fit::context& context, fit::result<>) mutable { 60 // This handler will run once the completer associated 61 // with the |prior| promise is abandoned. Once the promise 62 // has finished, both the promise and completer will be 63 // destroyed thereby causing the next promise chained onto 64 // the |bridge|'s associated consumer to become runnable. 65 return promise(context); 66 }); 67 } 68 69 sequencer(const sequencer&) = delete; 70 sequencer(sequencer&&) = delete; 71 sequencer& operator=(const sequencer&) = delete; 72 sequencer& operator=(sequencer&&) = delete; 73 74 private: 75 fit::consumer<> swap_prior(fit::consumer<> new_prior); 76 77 std::mutex mutex_; 78 79 // Holds the consumption capability of the most recently wrapped promise. 80 fit::consumer<> prior_ FIT_GUARDED(mutex_); 81 }; 82 83 } // namespace fit 84 85 #endif // LIB_FIT_SEQUENCER_H_ 86