fix: handle EINTR correctly in get_cpu_mask_from_sysfs
[libside.git] / include / side / trace.h
CommitLineData
67337c4a
MD
1// SPDX-License-Identifier: MIT
2/*
3 * Copyright 2022 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 */
5
6#ifndef _SIDE_TRACE_H
7#define _SIDE_TRACE_H
8
9#include <stdint.h>
10#include <inttypes.h>
11#include <stdlib.h>
12#include <stdio.h>
13#include <math.h>
25ea4c79 14#include <stdbool.h>
441235e7 15#include <stddef.h>
67337c4a
MD
16#include <side/macros.h>
17#include <side/endian.h>
18
19/*
551d8244 20 * SIDE stands for "Software Instrumentation Dynamically Enabled"
67337c4a 21 *
2e197497 22 * This is an instrumentation ABI for Linux user-space, which exposes an
67337c4a
MD
23 * instrumentation type system and facilities allowing a kernel or
24 * user-space tracer to consume user-space instrumentation.
25 *
35e4f870
MD
26 * The extensibility scheme for the SIDE ABI for event state is as
27 * follows:
67337c4a 28 *
b2a84b9f
MD
29 * * If the semantic of the "struct side_event_state_N" fields change,
30 * the SIDE_EVENT_STATE_ABI_VERSION should be increased. The
31 * "struct side_event_state_N" is not extensible and must have its
32 * ABI version increased whenever it is changed. Note that increasing
33 * the version of SIDE_EVENT_DESCRIPTION_ABI_VERSION is not necessary
34 * when changing the layout of "struct side_event_state_N".
67337c4a
MD
35 */
36
b2a84b9f 37#define SIDE_EVENT_STATE_ABI_VERSION 0
67337c4a 38
b8dfb348
MD
39#include <side/abi/event-description.h>
40#include <side/abi/type-argument.h>
57553dfd 41#include <side/instrumentation-c-api.h>
67337c4a
MD
42
43enum side_error {
44 SIDE_ERROR_OK = 0,
45 SIDE_ERROR_INVAL = 1,
46 SIDE_ERROR_EXIST = 2,
47 SIDE_ERROR_NOMEM = 3,
48 SIDE_ERROR_NOENT = 4,
49 SIDE_ERROR_EXITING = 5,
50};
51
0d747f98
MD
52/*
53 * This structure is _not_ packed to allow atomic operations on its
b2a84b9f
MD
54 * fields. Changes to this structure must bump the "Event state ABI
55 * version" and tracers _must_ learn how to deal with this ABI,
56 * otherwise they should reject the event.
0d747f98 57 */
b2a84b9f 58
0d747f98 59struct side_event_state {
b2a84b9f
MD
60 uint32_t version; /* Event state ABI version. */
61};
62
63struct side_event_state_0 {
49aea3ef 64 struct side_event_state parent; /* Required first field. */
3cac1780 65 uint32_t nr_callbacks;
692ffa8b 66 uintptr_t enabled;
7269a8a3
MD
67 const struct side_callback *callbacks;
68 struct side_event_description *desc;
0d747f98
MD
69};
70
67337c4a
MD
71#ifdef __cplusplus
72extern "C" {
73#endif
74
867b4725 75struct side_callback;
f0b01832
MD
76struct side_tracer_handle;
77struct side_statedump_request_handle;
2e197497 78
867b4725 79extern const char side_empty_callback[];
67337c4a 80
0d747f98 81void side_call(const struct side_event_state *state,
67337c4a 82 const struct side_arg_vec *side_arg_vec);
0d747f98 83void side_call_variadic(const struct side_event_state *state,
67337c4a
MD
84 const struct side_arg_vec *side_arg_vec,
85 const struct side_arg_dynamic_struct *var_struct);
86
87struct side_events_register_handle *side_events_register(struct side_event_description **events,
88 uint32_t nr_events);
89void side_events_unregister(struct side_events_register_handle *handle);
90
91/*
92 * Userspace tracer registration API. This allows userspace tracers to
93 * register event notification callbacks to be notified of the currently
94 * registered instrumentation, and to register their callbacks to
95 * specific events.
873bbf16
MD
96 *
97 * Application statedump callbacks are allowed to invoke
98 * side event register/unregister(), but tracer callbacks are _not_
99 * allowed to invoke statedump request notification register/unregister.
100 * The latter could result in hangs across RCU grace period domains.
67337c4a
MD
101 */
102typedef void (*side_tracer_callback_func)(const struct side_event_description *desc,
103 const struct side_arg_vec *side_arg_vec,
5e523511 104 void *priv, void *caller_addr);
67337c4a
MD
105typedef void (*side_tracer_callback_variadic_func)(const struct side_event_description *desc,
106 const struct side_arg_vec *side_arg_vec,
107 const struct side_arg_dynamic_struct *var_struct,
5e523511 108 void *priv, void *caller_addr);
67337c4a 109
bffe9ae3
MD
110int side_tracer_request_key(uint64_t *key);
111
67337c4a
MD
112int side_tracer_callback_register(struct side_event_description *desc,
113 side_tracer_callback_func call,
bffe9ae3 114 void *priv, uint64_t key);
67337c4a
MD
115int side_tracer_callback_variadic_register(struct side_event_description *desc,
116 side_tracer_callback_variadic_func call_variadic,
bffe9ae3 117 void *priv, uint64_t key);
67337c4a
MD
118int side_tracer_callback_unregister(struct side_event_description *desc,
119 side_tracer_callback_func call,
bffe9ae3 120 void *priv, uint64_t key);
67337c4a
MD
121int side_tracer_callback_variadic_unregister(struct side_event_description *desc,
122 side_tracer_callback_variadic_func call_variadic,
bffe9ae3 123 void *priv, uint64_t key);
67337c4a
MD
124
125enum side_tracer_notification {
126 SIDE_TRACER_NOTIFICATION_INSERT_EVENTS,
127 SIDE_TRACER_NOTIFICATION_REMOVE_EVENTS,
128};
129
130/* Callback is invoked with side library internal lock held. */
131struct side_tracer_handle *side_tracer_event_notification_register(
132 void (*cb)(enum side_tracer_notification notif,
133 struct side_event_description **events, uint32_t nr_events, void *priv),
134 void *priv);
135void side_tracer_event_notification_unregister(struct side_tracer_handle *handle);
136
f0b01832
MD
137/*
138 * The side_statedump_call APIs should be used for application/library
139 * state dump.
140 * The statedump callback dumps application state to tracers by invoking
141 * side_statedump_call APIs.
873bbf16
MD
142 * The statedump callback should not invoke libside statedump request
143 * notification register/unregister APIs.
f0b01832
MD
144 */
145void side_statedump_call(const struct side_event_state *state,
3da13b2c
MD
146 const struct side_arg_vec *side_arg_vec,
147 void *statedump_request_key);
f0b01832 148void side_statedump_call_variadic(const struct side_event_state *state,
3da13b2c
MD
149 const struct side_arg_vec *side_arg_vec,
150 const struct side_arg_dynamic_struct *var_struct,
151 void *statedump_request_key);
f0b01832
MD
152
153/*
154 * If side_statedump_request_notification_register is invoked from
155 * library constructors and side_statedump_request_notification_unregister
156 * from library destructors, make sure to:
157 * - invoke side_event_description_ptr_init before registration of the
158 * callback,
159 * - invoke side_event_description_ptr_exit after unregistration of the
160 * callback.
2050bbd9
MD
161 *
162 * In "polling" state dump mode, the application or library is responsible
163 * for periodically invoking side_statedump_run_pending_requests(). This
164 * mechanism is well-suited for single-threaded event-loop driven
165 * applications which do not wish to introduce multithreading nor
166 * locking-based synchronization of their state.
167 *
168 * In "agent thread" state dump mode, libside spawns a helper agent
169 * thread which is responsible for invoking the state dump callbacks
170 * when requested by the tracers. This mechanism is well-suited for
171 * instrumentation of multi-threaded applications which rely on
172 * locking to synchronize their data structures across threads, and
173 * for libraries which have no control on application event loops.
8fc4ab83
MD
174 *
175 * Applications using fork/clone with locks held should not take those
176 * locks (or block on any resource that depend on these locks) within
177 * their statedump callbacks registered with the agent thread. This
178 * could result in deadlocks when pthread_atfork handler waits for
179 * agent thread quiescence.
3da13b2c
MD
180 *
181 * The statedump_request_key received by the statedump_cb is only
182 * valid until the statedump_cb returns.
f0b01832 183 */
2050bbd9
MD
184enum side_statedump_mode {
185 SIDE_STATEDUMP_MODE_POLLING,
186 SIDE_STATEDUMP_MODE_AGENT_THREAD,
187};
188
189struct side_statedump_request_handle *
190 side_statedump_request_notification_register(
191 const char *state_name,
3da13b2c 192 void (*statedump_cb)(void *statedump_request_key),
2050bbd9
MD
193 enum side_statedump_mode mode);
194void side_statedump_request_notification_unregister(
195 struct side_statedump_request_handle *handle);
f0b01832 196
2050bbd9
MD
197/* Returns true if the handle has pending statedump requests. */
198bool side_statedump_poll_pending_requests(struct side_statedump_request_handle *handle);
bffe9ae3 199int side_statedump_run_pending_requests(struct side_statedump_request_handle *handle);
f0b01832 200
2050bbd9
MD
201/*
202 * Request a state dump for tracer callbacks identified with "key".
2050bbd9 203 */
bffe9ae3 204int side_tracer_statedump_request(uint64_t key);
2050bbd9
MD
205/*
206 * Cancel a statedump request.
2050bbd9 207 */
bffe9ae3 208int side_tracer_statedump_request_cancel(uint64_t key);
f0b01832 209
67337c4a
MD
210/*
211 * Explicit hooks to initialize/finalize the side instrumentation
212 * library. Those are also library constructor/destructor.
213 */
214void side_init(void) __attribute__((constructor));
215void side_exit(void) __attribute__((destructor));
216
217/*
218 * The following constructors/destructors perform automatic registration
219 * of the declared side events. Those may have to be called explicitly
220 * in a statically linked library.
221 */
222
223/*
224 * These weak symbols, the constructor, and destructor take care of
225 * registering only _one_ instance of the side instrumentation per
226 * shared-ojbect (or for the whole main program).
227 */
228extern struct side_event_description * __start_side_event_description_ptr[]
229 __attribute__((weak, visibility("hidden")));
230extern struct side_event_description * __stop_side_event_description_ptr[]
231 __attribute__((weak, visibility("hidden")));
232int side_event_description_ptr_registered
233 __attribute__((weak, visibility("hidden")));
234struct side_events_register_handle *side_events_handle
235 __attribute__((weak, visibility("hidden")));
236
237static void
238side_event_description_ptr_init(void)
239 __attribute__((no_instrument_function))
240 __attribute__((constructor));
241static void
242side_event_description_ptr_init(void)
243{
244 if (side_event_description_ptr_registered++)
245 return;
246 side_events_handle = side_events_register(__start_side_event_description_ptr,
247 __stop_side_event_description_ptr - __start_side_event_description_ptr);
248}
249
250static void
251side_event_description_ptr_exit(void)
252 __attribute__((no_instrument_function))
253 __attribute__((destructor));
254static void
255side_event_description_ptr_exit(void)
256{
257 if (--side_event_description_ptr_registered)
258 return;
259 side_events_unregister(side_events_handle);
260 side_events_handle = NULL;
261}
262
263#ifdef __cplusplus
264}
265#endif
266
267#endif /* _SIDE_TRACE_H */
This page took 0.049835 seconds and 4 git commands to generate.