• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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