• 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 "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