blob: 2e1dfd53fd2f2dd98de369a32c78481dbabd5d31 [file] [log] [blame]
// 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.
//
// The ABI-stable entry points used by trace instrumentation libraries.
//
// Trace handlers manage the configuration, lifecycle, and external communication
// of the trace engine. The trace engine binds to a single trace handler for
// the duration of a trace. During the trace, the trace engine invokes methods
// on the trace handler to ask about enabled categories and to report relevant
// state changes.
//
// Client code shouldn't be using these APIs directly.
// See <trace/event.h> for instrumentation macros.
//
#pragma once
#include <stdbool.h>
#include <zircon/compiler.h>
#include <zircon/types.h>
#include <lib/async/dispatcher.h>
#include <trace-engine/instrumentation.h>
__BEGIN_CDECLS
// Trace handler interface.
//
// Implementations must supply valid function pointers for each function
// defined in the |ops| structure.
typedef struct trace_handler_ops trace_handler_ops_t;
typedef struct trace_handler {
const trace_handler_ops_t* ops;
} trace_handler_t;
struct trace_handler_ops {
// Called by the trace engine to ask whether the specified category is enabled.
//
// This method may be called frequently so it must be efficiently implemented.
// Clients may cache the results while a trace is running; dynamic changes
// to the enabled categories may go unnoticed until the next trace.
//
// |handler| is the trace handler object itself.
// |category| is the name of the category.
//
// Called by instrumentation on any thread. Must be thread-safe.
bool (*is_category_enabled)(trace_handler_t* handler, const char* category);
// Called by the trace engine to indicate it has completed startup.
void (*trace_started)(trace_handler_t* handler);
// Called by the trace engine when tracing has stopped.
//
// The trace collection status is |ZX_OK| if trace collection was successful.
// An error indicates that the trace data may be inaccurate or incomplete.
//
// |handler| is the trace handler object itself.
// |async| is the trace engine's asynchronous dispatcher.
// |disposition| is |ZX_OK| if tracing stopped normally, otherwise indicates
// that tracing was aborted due to an error.
// |buffer_bytes_written| is number of bytes which were written to the trace buffer.
//
// Called on an asynchronous dispatch thread.
void (*trace_stopped)(trace_handler_t* handler, async_dispatcher_t* dispatcher,
zx_status_t disposition, size_t buffer_bytes_written);
// Called by the trace engine after an attempt to allocate space
// for a new record has failed because the buffer is full.
//
// Called by instrumentation on any thread. Must be thread-safe.
void (*notify_buffer_full)(trace_handler_t* handler,
uint32_t wrapped_count,
uint64_t durable_data_end);
};
// Asynchronously starts the trace engine.
//
// |async| is the asynchronous dispatcher which the trace engine will use for dispatch (borrowed).
// |handler| is the trace handler which will handle lifecycle events (borrowed).
// |buffer| is the trace buffer into which the trace engine will write trace events (borrowed).
// |buffer_num_bytes| is the size of the trace buffer in bytes.
//
// Returns |ZX_OK| if tracing is ready to go.
// Returns |ZX_ERR_BAD_STATE| if tracing is already in progress.
// Returns |ZX_ERR_NO_MEMORY| if allocation failed.
//
// This function is thread-safe.
//
// NOTE: Asynchronous dispatcher shutdown behavior:
//
// The trace engine will attempt to stop itself automatically when the
// asynchronous dispatcher specified in |async| begins the process of shutting
// itself down (usually just prior to the dispatcher's destruction). However,
// the trace engine may fail to come to a complete stop if there remain outstanding
// references to the trace context during dispatcher shutdown. When this happens,
// the trace handler will not be notified of trace completion and subsequent calls
// to |trace_start_engine()| will return |ZX_ERR_BAD_STATE|.
//
// For this reason, it is a good idea to call |trace_stop_engine()| and wait
// for the handler to receive the |trace_handler_ops.trace_stopped()| callback
// prior to shutting down the trace engine's asynchronous dispatcher.
//
// Better yet, don't shut down the trace engine's asynchronous dispatcher unless
// the process is already about to exit.
zx_status_t trace_start_engine(async_dispatcher_t* dispatcher,
trace_handler_t* handler,
trace_buffering_mode_t buffering_mode,
void* buffer,
size_t buffer_num_bytes);
// Asynchronously stops the trace engine.
//
// The trace handler's |trace_stopped()| method will be invoked asynchronously
// when the trace engine transitions to the |TRACE_STOPPED| states.
//
// |disposition| is |ZX_OK| if tracing is being stopped normally, otherwise indicates
// that tracing is being aborted due to an error.
//
// Returns |ZX_OK| if the current state is |TRACE_STARTED| or |TRACE_STOPPING|.
// Returns |ZX_ERR_BAD_STATE| if current state is |TRACE_STOPPED|.
//
// This function is thread-safe.
zx_status_t trace_stop_engine(zx_status_t disposition);
// Asynchronously notifies the engine that buffers up to |wrapped_count|
// have been saved.
//
// Returns |ZX_OK| if the current state is |TRACE_STARTED| or |TRACE_STOPPING|.
// Returns |ZX_ERR_BAD_STATE| if current state is |TRACE_STOPPED|.
//
// This function is thread-safe.
zx_status_t trace_engine_mark_buffer_saved(uint32_t wrapped_count,
uint64_t durable_data_end);
__END_CDECLS