1 // Copyright 2020 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 //============================================================================== 15 // 16 // The file provides the API for working with callbacks and sinks for the 17 // tokenized trace module. 18 19 #pragma once 20 21 #include <stdbool.h> 22 #include <stdint.h> 23 #include <string.h> 24 25 #include <span> 26 27 #include "pw_status/status.h" 28 #include "pw_trace_tokenized/config.h" 29 #include "pw_trace_tokenized/trace_tokenized.h" 30 31 PW_EXTERN_C_START 32 // The pw_trace_EventCallback is called before the sample is encoded or sent 33 // to the sinks. Bits in the return argument can be set to change the behaviour 34 // of tracing. 35 // - PW_TRACE_EVENT_RETURN_FLAGS_SKIP_EVENT can optionally be set true to 36 // skip this sample. 37 // - PW_TRACE_EVENT_RETURN_FLAGS_DISABLE_AFTER_PROCESSING can be set true to 38 // disable tracing after this sample. 39 // 40 // When registering the callback the parameter 'called_on_every_event' is used 41 // to indicate if the callback should be called even when tracing is disabled. 42 // This behaviour is useful to implment a tracing behaviour, where tracing can 43 // turn on when a specific event occurs. 44 // 45 // If a handle pointer is provided it will be set to a value, which can be later 46 // used to unregister the callback. 47 // 48 // The user_data pointer is provider for use by the application, it can be used 49 // to allow a single function callback to be registered multiple times but act 50 // differently by providing it with different context objects as pointers. 51 // 52 // NOTE: Since callbacks are called within the trace event lock, they should not 53 // register/unregister sinks or callbacks or trigger other trace events. 54 typedef enum { 55 PW_TRACE_CALL_ONLY_WHEN_ENABLED = 0, 56 PW_TRACE_CALL_ON_EVERY_EVENT = 1, 57 } pw_trace_ShouldCallOnEveryEvent; 58 59 enum { 60 PW_TRACE_EVENT_RETURN_FLAGS_NONE = 0, 61 PW_TRACE_EVENT_RETURN_FLAGS_SKIP_EVENT = 1 << 0, 62 PW_TRACE_EVENT_RETURN_FLAGS_DISABLE_AFTER_PROCESSING = 1 << 1 63 }; 64 typedef uint32_t pw_trace_TraceEventReturnFlags; 65 66 typedef size_t pw_trace_EventCallbackHandle; 67 typedef pw_trace_TraceEventReturnFlags (*pw_trace_EventCallback)( 68 void* user_data, 69 uint32_t trace_ref, 70 pw_trace_EventType event_type, 71 const char* module, 72 uint32_t trace_id, 73 uint8_t flags); 74 75 pw_Status pw_trace_RegisterEventCallback( 76 pw_trace_EventCallback callback, 77 pw_trace_ShouldCallOnEveryEvent called_on_every_event, 78 void* user_data, 79 pw_trace_EventCallbackHandle* handle); 80 81 // pw_trace_UnregisterEventCallback will cause the callback to not receive any 82 // more events. 83 pw_Status pw_trace_UnregisterEventCallback(pw_trace_EventCallbackHandle handle); 84 85 // pw_trace_Sink* is called after the trace event is encoded. 86 // Trace will internally handle locking, so every Start event will have a 87 // matching End event before another sequence is started. 88 // The number of bytes sent to AddBytes will be the number provided at the 89 // start, allowing buffers to allocate the required amount at the start when 90 // necessary. 91 // 92 // If OkStatus() is not returned from Start, the events bytes will be skipped. 93 // 94 // NOTE: Called while tracing is locked (which might be a critical section 95 // depending on application), so quick/simple operations only. One trace event 96 // might result in multiple callbacks if the data is split up. 97 // 98 // If a handle pointer is provided it will be set to a value, which can be later 99 // used to unregister the callback. 100 // 101 // The user_data pointer is provider for use by the application, it can be used 102 // to allow a single function callback to be registered multiple times but act 103 // differently by providing it with different user_data values. 104 // 105 // NOTE: Since callbacks are called within the trace event lock, they should not 106 // register/unregister sinks or callbacks or trigger other trace events. 107 typedef void (*pw_trace_SinkStartBlock)(void* user_data, size_t size); 108 typedef void (*pw_trace_SinkAddBytes)(void* user_data, 109 const void* bytes, 110 size_t size); 111 typedef void (*pw_trace_SinkEndBlock)(void* user_data); 112 typedef size_t pw_trace_SinkHandle; 113 pw_Status pw_trace_RegisterSink(pw_trace_SinkStartBlock start_func, 114 pw_trace_SinkAddBytes add_bytes_func, 115 pw_trace_SinkEndBlock end_block_func, 116 void* user_data, 117 pw_trace_SinkHandle* handle); 118 119 // pw_trace_UnregisterSink will cause the sink to stop receiving trace data. 120 pw_Status pw_trace_UnregisterSink(pw_trace_SinkHandle handle); 121 122 PW_EXTERN_C_END 123 124 #ifdef __cplusplus 125 namespace pw { 126 namespace trace { 127 128 class CallbacksImpl { 129 public: 130 enum CallOnEveryEvent { 131 kCallOnlyWhenEnabled = PW_TRACE_CALL_ONLY_WHEN_ENABLED, 132 kCallOnEveryEvent = PW_TRACE_CALL_ON_EVERY_EVENT, 133 }; 134 using SinkStartBlock = pw_trace_SinkStartBlock; 135 using SinkAddBytes = pw_trace_SinkAddBytes; 136 using SinkEndBlock = pw_trace_SinkEndBlock; 137 using SinkHandle = pw_trace_SinkHandle; 138 struct SinkCallbacks { 139 void* user_data; 140 SinkStartBlock start_block; 141 SinkAddBytes add_bytes; 142 SinkEndBlock end_block; 143 }; 144 using EventCallback = pw_trace_EventCallback; 145 using EventCallbackHandle = pw_trace_EventCallbackHandle; 146 struct EventCallbacks { 147 void* user_data; 148 EventCallback callback; 149 CallOnEveryEvent called_on_every_event; 150 }; 151 152 pw::Status RegisterSink(SinkStartBlock start_func, 153 SinkAddBytes add_bytes_func, 154 SinkEndBlock end_block_func, 155 void* user_data = nullptr, 156 SinkHandle* handle = nullptr); 157 pw::Status UnregisterSink(SinkHandle handle); 158 pw::Status UnregisterAllSinks(); 159 SinkCallbacks* GetSink(SinkHandle handle); 160 void CallSinks(std::span<const std::byte> header, 161 std::span<const std::byte> data); 162 163 pw::Status RegisterEventCallback( 164 EventCallback callback, 165 CallOnEveryEvent called_on_every_event = kCallOnlyWhenEnabled, 166 void* user_data = nullptr, 167 EventCallbackHandle* handle = nullptr); 168 pw::Status UnregisterEventCallback(EventCallbackHandle handle); 169 pw::Status UnregisterAllEventCallbacks(); 170 EventCallbacks* GetEventCallback(EventCallbackHandle handle); 171 pw_trace_TraceEventReturnFlags CallEventCallbacks( 172 CallOnEveryEvent called_on_every_event, 173 uint32_t trace_ref, 174 EventType event_type, 175 const char* module, 176 uint32_t trace_id, 177 uint8_t flags); GetCalledOnEveryEventCount()178 size_t GetCalledOnEveryEventCount() const { 179 return called_on_every_event_count_; 180 } 181 182 private: 183 EventCallbacks event_callbacks_[PW_TRACE_CONFIG_MAX_EVENT_CALLBACKS]; 184 SinkCallbacks sink_callbacks_[PW_TRACE_CONFIG_MAX_SINKS]; 185 size_t called_on_every_event_count_ = 0; 186 IsSinkFree(pw_trace_SinkHandle handle)187 bool IsSinkFree(pw_trace_SinkHandle handle) { 188 return sink_callbacks_[handle].start_block == nullptr && 189 sink_callbacks_[handle].add_bytes == nullptr && 190 sink_callbacks_[handle].end_block == nullptr; 191 } 192 }; 193 194 // A singleton object of the CallbacksImpl class which can be used to 195 // interface with trace using the C++ API. 196 // Example: pw::trace::Callbacks::Instance().UnregisterAllSinks(); 197 class Callbacks { 198 public: Instance()199 static CallbacksImpl& Instance() { return instance_; }; 200 201 private: 202 static CallbacksImpl instance_; 203 }; 204 205 // This is a convenience class to register the callback when the object is 206 // created. For example if the callback should always be registered this can be 207 // created as a global object to avoid needing to call register directly. 208 class RegisterCallbackWhenCreated { 209 public: 210 RegisterCallbackWhenCreated( 211 CallbacksImpl::EventCallback event_callback, 212 CallbacksImpl::CallOnEveryEvent called_on_every_event = 213 CallbacksImpl::kCallOnlyWhenEnabled, 214 void* user_data = nullptr) { 215 Callbacks::Instance().RegisterEventCallback( 216 event_callback, called_on_every_event, user_data); 217 } 218 RegisterCallbackWhenCreated(CallbacksImpl::SinkStartBlock sink_start, 219 CallbacksImpl::SinkAddBytes sink_add_bytes, 220 CallbacksImpl::SinkEndBlock sink_end, 221 void* user_data = nullptr) { 222 Callbacks::Instance().RegisterSink( 223 sink_start, sink_add_bytes, sink_end, user_data); 224 } 225 }; 226 227 } // namespace trace 228 } // namespace pw 229 #endif // __cplusplus