blob: d4bb11de705870768cc514ca13f73e29a6e2d3b4 [file] [log] [blame]
// Copyright 2021 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_DRIVER_RUNTIME_INCLUDE_LIB_FDF_DISPATCHER_H_
#define LIB_DRIVER_RUNTIME_INCLUDE_LIB_FDF_DISPATCHER_H_
#include <lib/async/dispatcher.h>
#include <lib/fdf/types.h>
__BEGIN_CDECLS
// Usage Notes:
//
// fdf_dispatcher_t can be used in conjunction with a fdf_channel_t
// to initiate asynchronous read operations. The dispatcher is in
// charge of dispatching the read callbacks.
//
// Example:
//
// void shutdown_handler(fdf_dispatcher_t* dispatcher,
// fdf_dispatcher_shutdown_observer_t* fdf_observer) {
// // Handle dispatcher shutdown.
// // It is now safe to destroy |dispatcher|.
// }
//
// struct dispatcher_shutdown_observer {
// fdf_dispatcher_shutdown_observer_t fdf_observer;
// my_ctx* ctx;
// };
//
// void driver_start() {
// TODO(fxb/85946): update this once scheduler_role is supported.
// const char* scheduler_role = "";
// struct dispatcher_shutdown_observer my_observer;
// my_observer.fdf_observer.handler = shutdown_handler;
// ...
//
// fdf_dispatcher_t* dispatcher;
// fdf_status_t status =
// fdf_dispatcher_create(0, scheduler_role, strlen(scheduler_role),
// &my_observer.fdf_observer, &dispatcher);
//
// fdf_channel_read_t channel_read;
// ...
// status = fdf_channel_wait_async(dispatcher, channel_read, 0);
//
// // The dispatcher will call the channel_read handler when ready.
//
// // This begins the dispatcher shutdown process.
// fdf_dispatcher_shutdown_async(dispatcher);
// }
//
typedef struct fdf_dispatcher fdf_dispatcher_t;
typedef struct fdf_dispatcher_shutdown_observer fdf_dispatcher_shutdown_observer_t;
// Called when the asynchronous shutdown for |dispatcher| has completed.
typedef void(fdf_dispatcher_shutdown_handler_t)(fdf_dispatcher_t* dispatcher,
fdf_dispatcher_shutdown_observer_t* observer);
// Holds context for the observer which will be called when the dispatcher's
// asynchronous shutdown has completed.
//
// After creating the dispatcher, the client is responsible for retaining
// this structure in memory (and unmodified) until the handler runs.
struct fdf_dispatcher_shutdown_observer {
fdf_dispatcher_shutdown_handler_t* handler;
};
// This flag allows parallel calls into callbacks set in the dispatcher.
// Cannot be set in conjunction with FDF_DISPATCHER_OPTION_ALLOW_SYNC_CALLS.
#define FDF_DISPATCHER_OPTION_UNSYNCHRONIZED (1 << 0)
// This flag indicates that the dispatcher may not share zircon threads with other drivers.
// Cannot be set in conjunction with FDF_DISPATCHER_OPTION_UNSYNCHRONIZED.
#define FDF_DISPATCHER_OPTION_ALLOW_SYNC_CALLS (1 << 1)
// |scheduler_role| is a hint. It may or not impact the priority the work scheduler against the
// dispatcher is handled at. It may or may not impact the ability for other drivers to share zircon
// threads with the dispatcher.
// |scheduler_role_len | is the length of the string, without including the terminating
// NULL character.
// TODO(fxb/85946): currently |scheduler_role| is not implemented.
// |observer| will be called after |fdf_dispatcher_shutdown_async| has been called,
// and the dispatcher has completed its asynchronous shutdown.
//
// This must be called from a thread managed by the driver runtime.
fdf_status_t fdf_dispatcher_create(uint32_t options, const char* scheduler_role,
size_t scheduler_role_len,
fdf_dispatcher_shutdown_observer_t* observer,
fdf_dispatcher_t** dispatcher);
// Returns the asynchronous dispatch interface.
async_dispatcher_t* fdf_dispatcher_get_async_dispatcher(fdf_dispatcher_t* dispatcher);
// Returns an unowned dispatcher provided an async dispatcher. If |async_dispatcher| was not
// retrieved via `fdf_dispatcher_get_async_dispatcher`, the call will result in a crash.
fdf_dispatcher_t* fdf_dispatcher_from_async_dispatcher(async_dispatcher_t* async_dispatcher);
// Returns the current thread's dispatcher.
// This will return NULL if not called from a dispatcher managed thread.
fdf_dispatcher_t* fdf_dispatcher_get_current_dispatcher();
// Returns the options set for this dispatcher.
uint32_t fdf_dispatcher_get_options(const fdf_dispatcher_t* dispatcher);
// Shutting down a dispatcher is an asynchronous operation.
//
// Once |fdf_dispatcher_shutdown_async| is called, the dispatcher will no longer
// accept queueing new async_dispatcher_t operations or ChannelRead callbacks.
//
// The dispatcher will asynchronously wait for all pending async_dispatcher_t
// and ChannelRead callbacks to complete. Then it will serially cancel all
// remaining callbacks with ZX_ERR_CANCELED and call the shutdown handler set
// in |fdf_dispatcher_create|.
//
// If the dispatcher is already shutdown, this will do nothing.
void fdf_dispatcher_shutdown_async(fdf_dispatcher_t* dispatcher);
// The dispatcher must be completely shutdown before this is called.
// It is safe to call this from the shutdown handler set in |fdf_dispatcher_create|.
void fdf_dispatcher_destroy(fdf_dispatcher_t* dispatcher);
__END_CDECLS
#endif // LIB_DRIVER_RUNTIME_INCLUDE_LIB_FDF_DISPATCHER_H_