1 // Copyright 2017 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 #pragma once 6 7 #include <lib/async-loop/loop.h> 8 #include <lib/async/default.h> 9 #include <lib/zx/time.h> 10 #include <stdbool.h> 11 #include <stddef.h> 12 #include <threads.h> 13 #include <zircon/compiler.h> 14 15 namespace async { 16 17 // C++ wrapper for an asynchronous dispatch loop. 18 // 19 // This class is thread-safe. 20 class Loop { 21 public: 22 // Creates a message loop. 23 // All operations on the message loop are thread-safe (except destroy). 24 // 25 // Note that it's ok to run the loop on a different thread from the one 26 // upon which it was created. 27 // 28 // |config| provides configuration for the message loop. Must not be null. 29 // 30 // See also |kAsyncLoopConfigAttachToThread| and |kAsyncLoopConfigNoAttachToThread|. 31 explicit Loop(const async_loop_config_t* config); 32 33 Loop(const Loop&) = delete; 34 Loop(Loop&&) = delete; 35 Loop& operator=(const Loop&) = delete; 36 Loop& operator=(Loop&&) = delete; 37 38 // Destroys the message loop. 39 // Implicitly calls |Shutdown()|. 40 ~Loop(); 41 42 // Gets the underlying message loop structure. loop()43 async_loop_t* loop() const { return loop_; } 44 45 // Gets the loop's asynchronous dispatch interface. dispatcher()46 async_dispatcher_t* dispatcher() const { return async_loop_get_dispatcher(loop_); } 47 48 // Shuts down the message loop, notifies handlers which asked to handle shutdown. 49 // The message loop must not currently be running on any threads other than 50 // those started by |StartThread()| which this function will join. 51 // 52 // Does nothing if already shutting down. 53 void Shutdown(); 54 55 // Runs the message loop on the current thread. 56 // This function can be called on multiple threads to setup a multi-threaded 57 // dispatcher. 58 // 59 // Dispatches events until the |deadline| expires or the loop is quitted. 60 // Use |ZX_TIME_INFINITE| to dispatch events indefinitely. 61 // 62 // If |once| is true, performs a single unit of work then returns. 63 // 64 // Returns |ZX_OK| if the dispatcher returns after one cycle. 65 // Returns |ZX_ERR_TIMED_OUT| if the deadline expired. 66 // Returns |ZX_ERR_CANCELED| if the loop quitted. 67 // Returns |ZX_ERR_BAD_STATE| if the loop was shut down with |Shutdown()|. 68 zx_status_t Run(zx::time deadline = zx::time::infinite(), bool once = false); 69 70 // Dispatches events until there are none remaining, and then returns 71 // without waiting. This is useful for unit testing, because the behavior 72 // doesn't depend on time. 73 // 74 // Returns |ZX_OK| if the dispatcher reaches an idle state. 75 // Returns |ZX_ERR_CANCELED| if the loop quitted. 76 // Returns |ZX_ERR_BAD_STATE| if the loop was shut down with |Shutdown()|. 77 zx_status_t RunUntilIdle(); 78 79 // Quits the message loop. 80 // Active invocations of |Run()| and threads started using |StartThread()| 81 // will eventually terminate upon completion of their current unit of work. 82 // 83 // Subsequent calls to |Run()| or |StartThread()| will return immediately 84 // until |ResetQuit()| is called. 85 void Quit(); 86 87 // Resets the quit state of the message loop so that it can be restarted 88 // using |Run()| or |StartThread()|. 89 // 90 // This function must only be called when the message loop is not running. 91 // The caller must ensure all active invocations of |Run()| and threads 92 // started using |StartThread()| have terminated before resetting the quit state. 93 // 94 // Returns |ZX_OK| if the loop's state was |ASYNC_LOOP_RUNNABLE| or |ASYNC_LOOP_QUIT|. 95 // Returns |ZX_ERR_BAD_STATE| if the loop's state was |ASYNC_LOOP_SHUTDOWN| or if 96 // the message loop is currently active on one or more threads. 97 zx_status_t ResetQuit(); 98 99 // Returns the current state of the message loop. 100 async_loop_state_t GetState() const; 101 102 // Starts a message loop running on a new thread. 103 // The thread will run until the loop quits. 104 // 105 // |name| is the desired name for the new thread, may be NULL. 106 // If |out_thread| is not NULL, it is set to the new thread identifier. 107 // 108 // Returns |ZX_OK| on success. 109 // Returns |ZX_ERR_BAD_STATE| if the loop was shut down with |async_loop_shutdown()|. 110 // Returns |ZX_ERR_NO_MEMORY| if allocation or thread creation failed. 111 zx_status_t StartThread(const char* name = nullptr, thrd_t* out_thread = nullptr); 112 113 // Blocks until all dispatch threads started with |StartThread()| 114 // have terminated. 115 void JoinThreads(); 116 117 private: 118 async_loop_t* loop_; 119 }; 120 121 } // namespace async 122