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 "pw_span/span.h" 26 #include "pw_status/status.h" 27 #include "pw_trace_tokenized/config.h" 28 #include "pw_trace_tokenized/trace_tokenized.h" 29 30 PW_EXTERN_C_START 31 // The pw_trace_EventCallback is called before the sample is encoded or sent 32 // to the sinks. Bits in the return argument can be set to change the behaviour 33 // of tracing. 34 // - PW_TRACE_EVENT_RETURN_FLAGS_SKIP_EVENT can optionally be set true to 35 // skip this sample. 36 // - PW_TRACE_EVENT_RETURN_FLAGS_DISABLE_AFTER_PROCESSING can be set true to 37 // disable tracing after this sample. 38 // 39 // When registering the callback the parameter 'called_on_every_event' is used 40 // to indicate if the callback should be called even when tracing is disabled. 41 // This behaviour is useful to implment a tracing behaviour, where tracing can 42 // turn on when a specific event occurs. 43 // 44 // If a handle pointer is provided it will be set to a value, which can be later 45 // used to unregister the callback. 46 // 47 // The user_data pointer is provider for use by the application, it can be used 48 // to allow a single function callback to be registered multiple times but act 49 // differently by providing it with different context objects as pointers. 50 // 51 // NOTE: Since callbacks are called within the trace event lock, they should not 52 // register/unregister sinks or callbacks or trigger other trace events. 53 typedef enum { 54 PW_TRACE_CALL_ONLY_WHEN_ENABLED = 0, 55 PW_TRACE_CALL_ON_EVERY_EVENT = 1, 56 } pw_trace_ShouldCallOnEveryEvent; 57 58 enum { 59 PW_TRACE_EVENT_RETURN_FLAGS_NONE = 0, 60 PW_TRACE_EVENT_RETURN_FLAGS_SKIP_EVENT = 1 << 0, 61 PW_TRACE_EVENT_RETURN_FLAGS_DISABLE_AFTER_PROCESSING = 1 << 1 62 }; 63 typedef uint32_t pw_trace_TraceEventReturnFlags; 64 65 typedef size_t pw_trace_EventCallbackHandle; 66 typedef pw_trace_TraceEventReturnFlags (*pw_trace_EventCallback)( 67 void* user_data, pw_trace_tokenized_TraceEvent* event); 68 69 pw_Status pw_trace_RegisterEventCallback( 70 pw_trace_EventCallback callback, 71 pw_trace_ShouldCallOnEveryEvent called_on_every_event, 72 void* user_data, 73 pw_trace_EventCallbackHandle* handle); 74 75 // pw_trace_UnregisterEventCallback will cause the callback to not receive any 76 // more events. 77 pw_Status pw_trace_UnregisterEventCallback(pw_trace_EventCallbackHandle handle); 78 79 // pw_trace_Sink* is called after the trace event is encoded. 80 // Trace will internally handle locking, so every Start event will have a 81 // matching End event before another sequence is started. 82 // The number of bytes sent to AddBytes will be the number provided at the 83 // start, allowing buffers to allocate the required amount at the start when 84 // necessary. 85 // 86 // If OkStatus() is not returned from Start, the events bytes will be skipped. 87 // 88 // NOTE: Called while tracing is locked (which might be a critical section 89 // depending on application), so quick/simple operations only. One trace event 90 // might result in multiple callbacks if the data is split up. 91 // 92 // If a handle pointer is provided it will be set to a value, which can be later 93 // used to unregister the callback. 94 // 95 // The user_data pointer is provider for use by the application, it can be used 96 // to allow a single function callback to be registered multiple times but act 97 // differently by providing it with different user_data values. 98 // 99 // NOTE: Since callbacks are called within the trace event lock, they should not 100 // register/unregister sinks or callbacks or trigger other trace events. 101 typedef void (*pw_trace_SinkStartBlock)(void* user_data, size_t size); 102 typedef void (*pw_trace_SinkAddBytes)(void* user_data, 103 const void* bytes, 104 size_t size); 105 typedef void (*pw_trace_SinkEndBlock)(void* user_data); 106 typedef size_t pw_trace_SinkHandle; 107 pw_Status pw_trace_RegisterSink(pw_trace_SinkStartBlock start_func, 108 pw_trace_SinkAddBytes add_bytes_func, 109 pw_trace_SinkEndBlock end_block_func, 110 void* user_data, 111 pw_trace_SinkHandle* handle); 112 113 // pw_trace_UnregisterSink will cause the sink to stop receiving trace data. 114 pw_Status pw_trace_UnregisterSink(pw_trace_SinkHandle handle); 115 116 PW_EXTERN_C_END 117 118 #ifdef __cplusplus 119 namespace pw { 120 namespace trace { 121 122 // C++ API to the tokenized trace callback system 123 // Example: pw::trace::GetTraceCallbacks().UnregisterAllSinks(); 124 class Callbacks { 125 public: 126 enum CallOnEveryEvent { 127 kCallOnlyWhenEnabled = PW_TRACE_CALL_ONLY_WHEN_ENABLED, 128 kCallOnEveryEvent = PW_TRACE_CALL_ON_EVERY_EVENT, 129 }; 130 using SinkStartBlock = pw_trace_SinkStartBlock; 131 using SinkAddBytes = pw_trace_SinkAddBytes; 132 using SinkEndBlock = pw_trace_SinkEndBlock; 133 using SinkHandle = pw_trace_SinkHandle; 134 struct SinkCallbacks { 135 void* user_data; 136 SinkStartBlock start_block; 137 SinkAddBytes add_bytes; 138 SinkEndBlock end_block; 139 }; 140 using EventCallback = pw_trace_EventCallback; 141 using EventCallbackHandle = pw_trace_EventCallbackHandle; 142 using TraceEvent = pw_trace_tokenized_TraceEvent; 143 struct EventCallbacks { 144 void* user_data; 145 EventCallback callback; 146 CallOnEveryEvent called_on_every_event; 147 }; 148 149 pw::Status RegisterSink(SinkStartBlock start_func, 150 SinkAddBytes add_bytes_func, 151 SinkEndBlock end_block_func, 152 void* user_data = nullptr, 153 SinkHandle* handle = nullptr); 154 pw::Status UnregisterSink(SinkHandle handle); 155 pw::Status UnregisterAllSinks(); 156 SinkCallbacks* GetSink(SinkHandle handle); 157 void CallSinks(span<const std::byte> header, span<const std::byte> data); 158 159 pw::Status RegisterEventCallback( 160 EventCallback callback, 161 CallOnEveryEvent called_on_every_event = kCallOnlyWhenEnabled, 162 void* user_data = nullptr, 163 EventCallbackHandle* handle = nullptr); 164 pw::Status UnregisterEventCallback(EventCallbackHandle handle); 165 pw::Status UnregisterAllEventCallbacks(); 166 EventCallbacks* GetEventCallback(EventCallbackHandle handle); 167 pw_trace_TraceEventReturnFlags CallEventCallbacks( 168 CallOnEveryEvent called_on_every_event, TraceEvent* event); GetCalledOnEveryEventCount()169 size_t GetCalledOnEveryEventCount() const { 170 return called_on_every_event_count_; 171 } 172 173 private: 174 EventCallbacks event_callbacks_[PW_TRACE_CONFIG_MAX_EVENT_CALLBACKS]; 175 SinkCallbacks sink_callbacks_[PW_TRACE_CONFIG_MAX_SINKS]; 176 size_t called_on_every_event_count_ = 0; 177 IsSinkFree(pw_trace_SinkHandle handle)178 bool IsSinkFree(pw_trace_SinkHandle handle) { 179 return sink_callbacks_[handle].start_block == nullptr && 180 sink_callbacks_[handle].add_bytes == nullptr && 181 sink_callbacks_[handle].end_block == nullptr; 182 } 183 }; 184 185 // Returns a reference of the tokenized trace callbacks 186 Callbacks& GetCallbacks(); 187 188 // This is a convenience class to register the callback when the object is 189 // created. For example if the callback should always be registered this can be 190 // created as a global object to avoid needing to call register directly. 191 class RegisterCallbackWhenCreated { 192 public: 193 RegisterCallbackWhenCreated( 194 Callbacks& callbacks, 195 Callbacks::EventCallback event_callback, 196 Callbacks::CallOnEveryEvent called_on_every_event = 197 Callbacks::kCallOnlyWhenEnabled, 198 void* user_data = nullptr) callbacks_(callbacks)199 : callbacks_(callbacks) { 200 callbacks_ 201 .RegisterEventCallback(event_callback, called_on_every_event, user_data) 202 .IgnoreError(); // TODO: b/242598609 - Handle Status properly 203 } 204 RegisterCallbackWhenCreated(Callbacks& callbacks, 205 Callbacks::SinkStartBlock sink_start, 206 Callbacks::SinkAddBytes sink_add_bytes, 207 Callbacks::SinkEndBlock sink_end, 208 void* user_data = nullptr) callbacks_(callbacks)209 : callbacks_(callbacks) { 210 callbacks_.RegisterSink(sink_start, sink_add_bytes, sink_end, user_data) 211 .IgnoreError(); // TODO: b/242598609 - Handle Status properly 212 } 213 214 private: 215 Callbacks& callbacks_; 216 }; 217 218 } // namespace trace 219 } // namespace pw 220 #endif // __cplusplus 221