blob: 6d9f23defaeec7fe181084f942fb0ec02c878c1c [file] [log] [blame]
// Copyright 2020 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//==============================================================================
//
// The file provides the API for working with callbacks and sinks for the
// tokenized trace module.
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <span>
#include "pw_status/status.h"
#include "pw_trace_tokenized/config.h"
#include "pw_trace_tokenized/trace_tokenized.h"
PW_EXTERN_C_START
// The pw_trace_EventCallback is called before the sample is encoded or sent
// to the sinks. Bits in the return argument can be set to change the behaviour
// of tracing.
// - PW_TRACE_EVENT_RETURN_FLAGS_SKIP_EVENT can optionally be set true to
// skip this sample.
// - PW_TRACE_EVENT_RETURN_FLAGS_DISABLE_AFTER_PROCESSING can be set true to
// disable tracing after this sample.
//
// When registering the callback the parameter 'called_on_every_event' is used
// to indicate if the callback should be called even when tracing is disabled.
// This behaviour is useful to implment a tracing behaviour, where tracing can
// turn on when a specific event occurs.
//
// If a handle pointer is provided it will be set to a value, which can be later
// used to unregister the callback.
//
// The user_data pointer is provider for use by the application, it can be used
// to allow a single function callback to be registered multiple times but act
// differently by providing it with different context objects as pointers.
//
// NOTE: Since callbacks are called within the trace event lock, they should not
// register/unregister sinks or callbacks or trigger other trace events.
typedef enum {
PW_TRACE_CALL_ONLY_WHEN_ENABLED = 0,
PW_TRACE_CALL_ON_EVERY_EVENT = 1,
} pw_trace_ShouldCallOnEveryEvent;
enum {
PW_TRACE_EVENT_RETURN_FLAGS_NONE = 0,
PW_TRACE_EVENT_RETURN_FLAGS_SKIP_EVENT = 1 << 0,
PW_TRACE_EVENT_RETURN_FLAGS_DISABLE_AFTER_PROCESSING = 1 << 1
};
typedef uint32_t pw_trace_TraceEventReturnFlags;
typedef size_t pw_trace_EventCallbackHandle;
typedef pw_trace_TraceEventReturnFlags (*pw_trace_EventCallback)(
void* user_data,
uint32_t trace_ref,
pw_trace_EventType event_type,
const char* module,
uint32_t trace_id,
uint8_t flags);
pw_Status pw_trace_RegisterEventCallback(
pw_trace_EventCallback callback,
pw_trace_ShouldCallOnEveryEvent called_on_every_event,
void* user_data,
pw_trace_EventCallbackHandle* handle);
// pw_trace_UnregisterEventCallback will cause the callback to not receive any
// more events.
pw_Status pw_trace_UnregisterEventCallback(pw_trace_EventCallbackHandle handle);
// pw_trace_Sink* is called after the trace event is encoded.
// Trace will internally handle locking, so every Start event will have a
// matching End event before another sequence is started.
// The number of bytes sent to AddBytes will be the number provided at the
// start, allowing buffers to allocate the required amount at the start when
// necessary.
//
// If OkStatus() is not returned from Start, the events bytes will be skipped.
//
// NOTE: Called while tracing is locked (which might be a critical section
// depending on application), so quick/simple operations only. One trace event
// might result in multiple callbacks if the data is split up.
//
// If a handle pointer is provided it will be set to a value, which can be later
// used to unregister the callback.
//
// The user_data pointer is provider for use by the application, it can be used
// to allow a single function callback to be registered multiple times but act
// differently by providing it with different user_data values.
//
// NOTE: Since callbacks are called within the trace event lock, they should not
// register/unregister sinks or callbacks or trigger other trace events.
typedef void (*pw_trace_SinkStartBlock)(void* user_data, size_t size);
typedef void (*pw_trace_SinkAddBytes)(void* user_data,
const void* bytes,
size_t size);
typedef void (*pw_trace_SinkEndBlock)(void* user_data);
typedef size_t pw_trace_SinkHandle;
pw_Status pw_trace_RegisterSink(pw_trace_SinkStartBlock start_func,
pw_trace_SinkAddBytes add_bytes_func,
pw_trace_SinkEndBlock end_block_func,
void* user_data,
pw_trace_SinkHandle* handle);
// pw_trace_UnregisterSink will cause the sink to stop receiving trace data.
pw_Status pw_trace_UnregisterSink(pw_trace_SinkHandle handle);
PW_EXTERN_C_END
#ifdef __cplusplus
namespace pw {
namespace trace {
class CallbacksImpl {
public:
enum CallOnEveryEvent {
kCallOnlyWhenEnabled = PW_TRACE_CALL_ONLY_WHEN_ENABLED,
kCallOnEveryEvent = PW_TRACE_CALL_ON_EVERY_EVENT,
};
using SinkStartBlock = pw_trace_SinkStartBlock;
using SinkAddBytes = pw_trace_SinkAddBytes;
using SinkEndBlock = pw_trace_SinkEndBlock;
using SinkHandle = pw_trace_SinkHandle;
struct SinkCallbacks {
void* user_data;
SinkStartBlock start_block;
SinkAddBytes add_bytes;
SinkEndBlock end_block;
};
using EventCallback = pw_trace_EventCallback;
using EventCallbackHandle = pw_trace_EventCallbackHandle;
struct EventCallbacks {
void* user_data;
EventCallback callback;
CallOnEveryEvent called_on_every_event;
};
pw::Status RegisterSink(SinkStartBlock start_func,
SinkAddBytes add_bytes_func,
SinkEndBlock end_block_func,
void* user_data = nullptr,
SinkHandle* handle = nullptr);
pw::Status UnregisterSink(SinkHandle handle);
pw::Status UnregisterAllSinks();
SinkCallbacks* GetSink(SinkHandle handle);
void CallSinks(std::span<const std::byte> header,
std::span<const std::byte> data);
pw::Status RegisterEventCallback(
EventCallback callback,
CallOnEveryEvent called_on_every_event = kCallOnlyWhenEnabled,
void* user_data = nullptr,
EventCallbackHandle* handle = nullptr);
pw::Status UnregisterEventCallback(EventCallbackHandle handle);
pw::Status UnregisterAllEventCallbacks();
EventCallbacks* GetEventCallback(EventCallbackHandle handle);
pw_trace_TraceEventReturnFlags CallEventCallbacks(
CallOnEveryEvent called_on_every_event,
uint32_t trace_ref,
EventType event_type,
const char* module,
uint32_t trace_id,
uint8_t flags);
size_t GetCalledOnEveryEventCount() const {
return called_on_every_event_count_;
}
private:
EventCallbacks event_callbacks_[PW_TRACE_CONFIG_MAX_EVENT_CALLBACKS];
SinkCallbacks sink_callbacks_[PW_TRACE_CONFIG_MAX_SINKS];
size_t called_on_every_event_count_ = 0;
bool IsSinkFree(pw_trace_SinkHandle handle) {
return sink_callbacks_[handle].start_block == nullptr &&
sink_callbacks_[handle].add_bytes == nullptr &&
sink_callbacks_[handle].end_block == nullptr;
}
};
// A singleton object of the CallbacksImpl class which can be used to
// interface with trace using the C++ API.
// Example: pw::trace::Callbacks::Instance().UnregisterAllSinks();
class Callbacks {
public:
static CallbacksImpl& Instance() { return instance_; };
private:
static CallbacksImpl instance_;
};
// This is a convenience class to register the callback when the object is
// created. For example if the callback should always be registered this can be
// created as a global object to avoid needing to call register directly.
class RegisterCallbackWhenCreated {
public:
RegisterCallbackWhenCreated(
CallbacksImpl::EventCallback event_callback,
CallbacksImpl::CallOnEveryEvent called_on_every_event =
CallbacksImpl::kCallOnlyWhenEnabled,
void* user_data = nullptr) {
Callbacks::Instance()
.RegisterEventCallback(event_callback, called_on_every_event, user_data)
.IgnoreError(); // TODO(pwbug/387): Handle Status properly
}
RegisterCallbackWhenCreated(CallbacksImpl::SinkStartBlock sink_start,
CallbacksImpl::SinkAddBytes sink_add_bytes,
CallbacksImpl::SinkEndBlock sink_end,
void* user_data = nullptr) {
Callbacks::Instance()
.RegisterSink(sink_start, sink_add_bytes, sink_end, user_data)
.IgnoreError(); // TODO(pwbug/387): Handle Status properly
}
};
} // namespace trace
} // namespace pw
#endif // __cplusplus