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 class CallbacksImpl { 123 public: 124 enum CallOnEveryEvent { 125 kCallOnlyWhenEnabled = PW_TRACE_CALL_ONLY_WHEN_ENABLED, 126 kCallOnEveryEvent = PW_TRACE_CALL_ON_EVERY_EVENT, 127 }; 128 using SinkStartBlock = pw_trace_SinkStartBlock; 129 using SinkAddBytes = pw_trace_SinkAddBytes; 130 using SinkEndBlock = pw_trace_SinkEndBlock; 131 using SinkHandle = pw_trace_SinkHandle; 132 struct SinkCallbacks { 133 void* user_data; 134 SinkStartBlock start_block; 135 SinkAddBytes add_bytes; 136 SinkEndBlock end_block; 137 }; 138 using EventCallback = pw_trace_EventCallback; 139 using EventCallbackHandle = pw_trace_EventCallbackHandle; 140 using TraceEvent = pw_trace_tokenized_TraceEvent; 141 struct EventCallbacks { 142 void* user_data; 143 EventCallback callback; 144 CallOnEveryEvent called_on_every_event; 145 }; 146 147 pw::Status RegisterSink(SinkStartBlock start_func, 148 SinkAddBytes add_bytes_func, 149 SinkEndBlock end_block_func, 150 void* user_data = nullptr, 151 SinkHandle* handle = nullptr); 152 pw::Status UnregisterSink(SinkHandle handle); 153 pw::Status UnregisterAllSinks(); 154 SinkCallbacks* GetSink(SinkHandle handle); 155 void CallSinks(span<const std::byte> header, span<const std::byte> data); 156 157 pw::Status RegisterEventCallback( 158 EventCallback callback, 159 CallOnEveryEvent called_on_every_event = kCallOnlyWhenEnabled, 160 void* user_data = nullptr, 161 EventCallbackHandle* handle = nullptr); 162 pw::Status UnregisterEventCallback(EventCallbackHandle handle); 163 pw::Status UnregisterAllEventCallbacks(); 164 EventCallbacks* GetEventCallback(EventCallbackHandle handle); 165 pw_trace_TraceEventReturnFlags CallEventCallbacks( 166 CallOnEveryEvent called_on_every_event, TraceEvent* event); GetCalledOnEveryEventCount()167 size_t GetCalledOnEveryEventCount() const { 168 return called_on_every_event_count_; 169 } 170 171 private: 172 EventCallbacks event_callbacks_[PW_TRACE_CONFIG_MAX_EVENT_CALLBACKS]; 173 SinkCallbacks sink_callbacks_[PW_TRACE_CONFIG_MAX_SINKS]; 174 size_t called_on_every_event_count_ = 0; 175 IsSinkFree(pw_trace_SinkHandle handle)176 bool IsSinkFree(pw_trace_SinkHandle handle) { 177 return sink_callbacks_[handle].start_block == nullptr && 178 sink_callbacks_[handle].add_bytes == nullptr && 179 sink_callbacks_[handle].end_block == nullptr; 180 } 181 }; 182 183 // A singleton object of the CallbacksImpl class which can be used to 184 // interface with trace using the C++ API. 185 // Example: pw::trace::Callbacks::Instance().UnregisterAllSinks(); 186 class Callbacks { 187 public: Instance()188 static CallbacksImpl& Instance() { return instance_; } 189 190 private: 191 static CallbacksImpl instance_; 192 }; 193 194 // This is a convenience class to register the callback when the object is 195 // created. For example if the callback should always be registered this can be 196 // created as a global object to avoid needing to call register directly. 197 class RegisterCallbackWhenCreated { 198 public: 199 RegisterCallbackWhenCreated( 200 CallbacksImpl::EventCallback event_callback, 201 CallbacksImpl::CallOnEveryEvent called_on_every_event = 202 CallbacksImpl::kCallOnlyWhenEnabled, 203 void* user_data = nullptr) { 204 Callbacks::Instance() 205 .RegisterEventCallback(event_callback, called_on_every_event, user_data) 206 .IgnoreError(); // TODO(b/242598609): Handle Status properly 207 } 208 RegisterCallbackWhenCreated(CallbacksImpl::SinkStartBlock sink_start, 209 CallbacksImpl::SinkAddBytes sink_add_bytes, 210 CallbacksImpl::SinkEndBlock sink_end, 211 void* user_data = nullptr) { 212 Callbacks::Instance() 213 .RegisterSink(sink_start, sink_add_bytes, sink_end, user_data) 214 .IgnoreError(); // TODO(b/242598609): Handle Status properly 215 } 216 }; 217 218 } // namespace trace 219 } // namespace pw 220 #endif // __cplusplus 221