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