| // Copyright 2017 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. |
| |
| // |
| // Provides an implementation of a simple thread-safe asynchronous |
| // dispatcher based on a Zircon completion port. The implementation |
| // is designed to avoid most dynamic memory allocation except for that |
| // which is required to create the loop in the first place or to manage |
| // the list of running threads. |
| // |
| // See README.md for example usage. |
| // |
| |
| #ifndef LIB_ASYNC_LOOP_LOOP_H_ |
| #define LIB_ASYNC_LOOP_LOOP_H_ |
| |
| #include <lib/async/dispatcher.h> |
| #include <stdbool.h> |
| #include <stddef.h> |
| #include <threads.h> |
| #include <zircon/compiler.h> |
| |
| __BEGIN_CDECLS |
| |
| /// Pointer to a message loop created using |async_loop_create()|. |
| typedef struct async_loop async_loop_t; |
| |
| /// Accessors for getting/setting the "default" async loop for the thread upon |
| /// which an async loop is created. |
| typedef async_dispatcher_t*(async_loop_get_default_dispatcher_t)(void); |
| typedef void(async_loop_set_default_dispatcher_t)(async_dispatcher_t*); |
| typedef struct { |
| async_loop_get_default_dispatcher_t* getter; |
| async_loop_set_default_dispatcher_t* setter; |
| } async_loop_default_accessors_t; |
| |
| /// Message loop configuration structure. |
| typedef void(async_loop_callback_t)(async_loop_t* loop, void* data); |
| typedef struct async_loop_config { |
| /// If specified, these functions will be used to register the loop as the default |
| /// dispatcher on the thread on which they are called and will be used to |
| /// automatically unregister the loop when it is destroyed. |
| /// |
| /// If NULL, the loop will not do this. The loop's creator is then |
| /// responsible for retrieving the loop's dispatcher using |async_loop_get_dispatcher()| |
| /// and passing it around explicitly. |
| /// |
| /// It is an error for only one of the functions to be non-NULL. |
| /// |
| /// Note that the loop can be used even without setting it as the current |
| /// thread's default. |
| async_loop_default_accessors_t default_accessors; |
| |
| /// If true, then uses default_accessors.setter to register the loop as the |
| /// default dispatcher for the thread upon which the loop was created. |
| /// |
| /// TRANSITIONAL BEHAVIOR: |
| /// If default_accesors are not specified and this flag is true, then behaves as if |
| /// async_get_default_dispatcher/async_set_default_dispatcher were specified |
| /// as the default_accessors. |
| bool make_default_for_current_thread; |
| |
| /// A function to call before the dispatcher invokes each handler, or NULL if none. |
| async_loop_callback_t* prologue; |
| |
| /// A function to call after the dispatcher invokes each handler, or NULL if none. |
| async_loop_callback_t* epilogue; |
| |
| /// Data to pass to the callback functions. |
| void* data; |
| |
| /// True if IRQs should be supported |
| bool irq_support; |
| } async_loop_config_t; |
| |
| /// Simple config that when passed to async_loop_create will create a loop |
| /// that is not registered to the current thread or any threads created with |
| /// async_loop_start_thread |
| extern const async_loop_config_t kAsyncLoopConfigNeverAttachToThread; |
| |
| /// Creates a message loop and returns a pointer to it in |out_loop|. |
| /// All operations on the message loop are thread-safe (except destroy). |
| /// |
| /// Note that it's ok to run the loop on a different thread from the one |
| /// upon which it was created. |
| /// |
| /// |config| provides configuration for the message loop. Must not be null. |
| /// |
| /// Returns |ZX_OK| on success. |
| /// Returns |ZX_ERR_NO_MEMORY| if allocation failed. |
| /// May return other errors if the necessary internal handles could not be created. |
| /// |
| /// See also |kAsyncLoopConfigNeverAttachToThread|, |
| /// |kAsyncLoopConfigAttachToCurrentThread|, and |
| /// |kAsyncLoopConfigNoAttachToCurrentThread|. |
| zx_status_t async_loop_create(const async_loop_config_t* config, async_loop_t** out_loop); |
| |
| /// Gets the message loop's asynchronous dispatch interface. |
| async_dispatcher_t* async_loop_get_dispatcher(async_loop_t* loop); |
| |
| /// Gets the message loop associated with the specified asynchronous dispatch interface |
| /// |
| /// This function assumes the dispatcher is backed by an |async_loop_t| which was created |
| /// using |async_loop_create()|. Its behavior is undefined if used with other dispatcher |
| /// implementations. |
| async_loop_t* async_loop_from_dispatcher(async_dispatcher_t* dispatcher); |
| |
| /// Shuts down the message loop, notifies handlers which asked to handle shutdown. |
| /// The message loop must not currently be running on any threads other than |
| /// those started by |async_loop_start_thread()| which this function will join. |
| /// |
| /// Does nothing if already shutting down. |
| void async_loop_shutdown(async_loop_t* loop); |
| |
| /// Destroys the message loop. |
| /// Implicitly calls |async_loop_shutdown()| and joins all threads started |
| /// using |async_loop_start_thread()| before destroying the loop itself. |
| /// |
| /// If `make_default_for_current_thread` was true in the config used to create |
| /// the loop, then this method must be called on the same thread that called |
| /// async_loop_create. |
| void async_loop_destroy(async_loop_t* loop); |
| |
| /// Runs the message loop on the current thread. |
| /// This function can be called on multiple threads to setup a multi-threaded |
| /// dispatcher. |
| /// |
| /// Dispatches events until the |deadline| expires or the loop is quitted. |
| /// Use |ZX_TIME_INFINITE| to dispatch events indefinitely. |
| /// |
| /// If |once| is true, performs a single unit of work then returns. |
| /// |
| /// Returns |ZX_OK| if the dispatcher returns after one cycle. |
| /// Returns |ZX_ERR_TIMED_OUT| if the deadline expired. |
| /// Returns |ZX_ERR_CANCELED| if the loop quitted. |
| /// Returns |ZX_ERR_BAD_STATE| if the loop was shut down with |async_loop_shutdown()|. |
| zx_status_t async_loop_run(async_loop_t* loop, zx_time_t deadline, bool once); |
| |
| /// Dispatches events until there are none remaining, and then returns without |
| /// waiting. This is useful for unit testing, because the behavior doesn't depend |
| /// on time. |
| /// |
| /// Returns |ZX_OK| if the dispatcher reaches an idle state. |
| /// Returns |ZX_ERR_CANCELED| if the loop quitted. |
| /// Returns |ZX_ERR_BAD_STATE| if the loop was shut down with |async_loop_shutdown()|. |
| zx_status_t async_loop_run_until_idle(async_loop_t* loop); |
| |
| /// Quits the message loop. |
| /// Active invocations of |async_loop_run()| and threads started using |
| /// |async_loop_start_thread()| will eventually terminate upon completion of their |
| /// current unit of work. |
| /// |
| /// Subsequent calls to |async_loop_run()| or |async_loop_start_thread()| |
| /// will return immediately until |async_loop_reset_quit()| is called. |
| void async_loop_quit(async_loop_t* loop); |
| |
| /// Resets the quit state of the message loop so that it can be restarted |
| /// using |async_loop_run()| or |async_loop_start_thread()|. |
| /// |
| /// This function must only be called when the message loop is not running. |
| /// The caller must ensure all active invocations of |async_loop_run()| and |
| /// threads started using |async_loop_start_thread()| have terminated before |
| /// resetting the quit state. |
| /// |
| /// Returns |ZX_OK| if the loop's state was |ASYNC_LOOP_RUNNABLE| or |ASYNC_LOOP_QUIT|. |
| /// Returns |ZX_ERR_BAD_STATE| if the loop's state was |ASYNC_LOOP_SHUTDOWN| or if |
| /// the message loop is currently active on one or more threads. |
| zx_status_t async_loop_reset_quit(async_loop_t* loop); |
| |
| /// Returns the current state of the message loop. |
| typedef uint32_t async_loop_state_t; |
| #define ASYNC_LOOP_RUNNABLE ((async_loop_state_t)0) |
| #define ASYNC_LOOP_QUIT ((async_loop_state_t)1) |
| #define ASYNC_LOOP_SHUTDOWN ((async_loop_state_t)2) |
| async_loop_state_t async_loop_get_state(async_loop_t* loop); |
| |
| /// Starts a message loop running on a new thread. |
| /// The thread will run until the loop quits. |
| /// |
| /// |name| is the desired name for the new thread, may be NULL. |
| /// If |out_thread| is not NULL, it is set to the new thread identifier. |
| /// |
| /// Returns |ZX_OK| on success. |
| /// Returns |ZX_ERR_BAD_STATE| if the loop was shut down with |async_loop_shutdown()|. |
| /// Returns |ZX_ERR_NO_MEMORY| if allocation or thread creation failed. |
| zx_status_t async_loop_start_thread(async_loop_t* loop, const char* name, thrd_t* out_thread); |
| |
| /// Blocks until all dispatch threads started with |async_loop_start_thread()| |
| /// have terminated. |
| void async_loop_join_threads(async_loop_t* loop); |
| |
| __END_CDECLS |
| |
| #endif // LIB_ASYNC_LOOP_LOOP_H_ |