aboutsummaryrefslogtreecommitdiff
path: root/pw_trace_tokenized/public/pw_trace_tokenized/trace_callback.h
blob: 1140f75ad3938548500b8101198a326cc7a9a5cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// Copyright 2020 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//==============================================================================
//
// The file provides the API for working with callbacks and sinks for the
// tokenized trace module.

#pragma once

#include <stdbool.h>
#include <stdint.h>
#include <string.h>

#include "pw_span/span.h"
#include "pw_status/status.h"
#include "pw_trace_tokenized/config.h"
#include "pw_trace_tokenized/trace_tokenized.h"

PW_EXTERN_C_START
// The pw_trace_EventCallback is called before the sample is encoded or sent
// to the sinks. Bits in the return argument can be set to change the behaviour
// of tracing.
//    - PW_TRACE_EVENT_RETURN_FLAGS_SKIP_EVENT can optionally be set true to
//    skip this sample.
//    - PW_TRACE_EVENT_RETURN_FLAGS_DISABLE_AFTER_PROCESSING can be set true to
//      disable tracing after this sample.
//
// When registering the callback the parameter 'called_on_every_event' is used
// to indicate if the callback should be called even when tracing is disabled.
// This behaviour is useful to implment a tracing behaviour, where tracing can
// turn on when a specific event occurs.
//
// If a handle pointer is provided it will be set to a value, which can be later
// used to unregister the callback.
//
// The user_data pointer is provider for use by the application, it can be used
// to allow a single function callback to be registered multiple times but act
// differently by providing it with different context objects as pointers.
//
// NOTE: Since callbacks are called within the trace event lock, they should not
// register/unregister sinks or callbacks or trigger other trace events.
typedef enum {
  PW_TRACE_CALL_ONLY_WHEN_ENABLED = 0,
  PW_TRACE_CALL_ON_EVERY_EVENT = 1,
} pw_trace_ShouldCallOnEveryEvent;

enum {
  PW_TRACE_EVENT_RETURN_FLAGS_NONE = 0,
  PW_TRACE_EVENT_RETURN_FLAGS_SKIP_EVENT = 1 << 0,
  PW_TRACE_EVENT_RETURN_FLAGS_DISABLE_AFTER_PROCESSING = 1 << 1
};
typedef uint32_t pw_trace_TraceEventReturnFlags;

typedef size_t pw_trace_EventCallbackHandle;
typedef pw_trace_TraceEventReturnFlags (*pw_trace_EventCallback)(
    void* user_data, pw_trace_tokenized_TraceEvent* event);

pw_Status pw_trace_RegisterEventCallback(
    pw_trace_EventCallback callback,
    pw_trace_ShouldCallOnEveryEvent called_on_every_event,
    void* user_data,
    pw_trace_EventCallbackHandle* handle);

// pw_trace_UnregisterEventCallback will cause the callback to not receive any
// more events.
pw_Status pw_trace_UnregisterEventCallback(pw_trace_EventCallbackHandle handle);

// pw_trace_Sink* is called after the trace event is encoded.
// Trace will internally handle locking, so every Start event will have a
// matching End event before another sequence is started.
// The number of bytes sent to AddBytes will be the number provided at the
// start, allowing buffers to allocate the required amount at the start when
// necessary.
//
// If OkStatus() is not returned from Start, the events bytes will be skipped.
//
// NOTE: Called while tracing is locked (which might be a critical section
// depending on application), so quick/simple operations only. One trace event
// might result in multiple callbacks if the data is split up.
//
// If a handle pointer is provided it will be set to a value, which can be later
// used to unregister the callback.
//
// The user_data pointer is provider for use by the application, it can be used
// to allow a single function callback to be registered multiple times but act
// differently by providing it with different user_data values.
//
// NOTE: Since callbacks are called within the trace event lock, they should not
// register/unregister sinks or callbacks or trigger other trace events.
typedef void (*pw_trace_SinkStartBlock)(void* user_data, size_t size);
typedef void (*pw_trace_SinkAddBytes)(void* user_data,
                                      const void* bytes,
                                      size_t size);
typedef void (*pw_trace_SinkEndBlock)(void* user_data);
typedef size_t pw_trace_SinkHandle;
pw_Status pw_trace_RegisterSink(pw_trace_SinkStartBlock start_func,
                                pw_trace_SinkAddBytes add_bytes_func,
                                pw_trace_SinkEndBlock end_block_func,
                                void* user_data,
                                pw_trace_SinkHandle* handle);

// pw_trace_UnregisterSink will cause the sink to stop receiving trace data.
pw_Status pw_trace_UnregisterSink(pw_trace_SinkHandle handle);

PW_EXTERN_C_END

#ifdef __cplusplus
namespace pw {
namespace trace {

// C++ API to the tokenized trace callback system
// Example: pw::trace::GetTraceCallbacks().UnregisterAllSinks();
class Callbacks {
 public:
  enum CallOnEveryEvent {
    kCallOnlyWhenEnabled = PW_TRACE_CALL_ONLY_WHEN_ENABLED,
    kCallOnEveryEvent = PW_TRACE_CALL_ON_EVERY_EVENT,
  };
  using SinkStartBlock = pw_trace_SinkStartBlock;
  using SinkAddBytes = pw_trace_SinkAddBytes;
  using SinkEndBlock = pw_trace_SinkEndBlock;
  using SinkHandle = pw_trace_SinkHandle;
  struct SinkCallbacks {
    void* user_data;
    SinkStartBlock start_block;
    SinkAddBytes add_bytes;
    SinkEndBlock end_block;
  };
  using EventCallback = pw_trace_EventCallback;
  using EventCallbackHandle = pw_trace_EventCallbackHandle;
  using TraceEvent = pw_trace_tokenized_TraceEvent;
  struct EventCallbacks {
    void* user_data;
    EventCallback callback;
    CallOnEveryEvent called_on_every_event;
  };

  pw::Status RegisterSink(SinkStartBlock start_func,
                          SinkAddBytes add_bytes_func,
                          SinkEndBlock end_block_func,
                          void* user_data = nullptr,
                          SinkHandle* handle = nullptr);
  pw::Status UnregisterSink(SinkHandle handle);
  pw::Status UnregisterAllSinks();
  SinkCallbacks* GetSink(SinkHandle handle);
  void CallSinks(span<const std::byte> header, span<const std::byte> data);

  pw::Status RegisterEventCallback(
      EventCallback callback,
      CallOnEveryEvent called_on_every_event = kCallOnlyWhenEnabled,
      void* user_data = nullptr,
      EventCallbackHandle* handle = nullptr);
  pw::Status UnregisterEventCallback(EventCallbackHandle handle);
  pw::Status UnregisterAllEventCallbacks();
  EventCallbacks* GetEventCallback(EventCallbackHandle handle);
  pw_trace_TraceEventReturnFlags CallEventCallbacks(
      CallOnEveryEvent called_on_every_event, TraceEvent* event);
  size_t GetCalledOnEveryEventCount() const {
    return called_on_every_event_count_;
  }

 private:
  EventCallbacks event_callbacks_[PW_TRACE_CONFIG_MAX_EVENT_CALLBACKS];
  SinkCallbacks sink_callbacks_[PW_TRACE_CONFIG_MAX_SINKS];
  size_t called_on_every_event_count_ = 0;

  bool IsSinkFree(pw_trace_SinkHandle handle) {
    return sink_callbacks_[handle].start_block == nullptr &&
           sink_callbacks_[handle].add_bytes == nullptr &&
           sink_callbacks_[handle].end_block == nullptr;
  }
};

// Returns a reference of the tokenized trace callbacks
Callbacks& GetCallbacks();

// This is a convenience class to register the callback when the object is
// created. For example if the callback should always be registered this can be
// created as a global object to avoid needing to call register directly.
class RegisterCallbackWhenCreated {
 public:
  RegisterCallbackWhenCreated(
      Callbacks& callbacks,
      Callbacks::EventCallback event_callback,
      Callbacks::CallOnEveryEvent called_on_every_event =
          Callbacks::kCallOnlyWhenEnabled,
      void* user_data = nullptr)
      : callbacks_(callbacks) {
    callbacks_
        .RegisterEventCallback(event_callback, called_on_every_event, user_data)
        .IgnoreError();  // TODO: b/242598609 - Handle Status properly
  }
  RegisterCallbackWhenCreated(Callbacks& callbacks,
                              Callbacks::SinkStartBlock sink_start,
                              Callbacks::SinkAddBytes sink_add_bytes,
                              Callbacks::SinkEndBlock sink_end,
                              void* user_data = nullptr)
      : callbacks_(callbacks) {
    callbacks_.RegisterSink(sink_start, sink_add_bytes, sink_end, user_data)
        .IgnoreError();  // TODO: b/242598609 - Handle Status properly
  }

 private:
  Callbacks& callbacks_;
};

}  // namespace trace
}  // namespace pw
#endif  // __cplusplus