Move to kernel style SPDX license identifiers
[lttng-ust.git] / liblttng-ust / event-notifier-notification.c
1 /*
2 * SPDX-License-Identifier: LGPL-2.1-only
3 *
4 * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
5 */
6
7 #define _LGPL_SOURCE
8
9 #include <assert.h>
10 #include <errno.h>
11 #include <lttng/ust-events.h>
12 #include <lttng/ust-endian.h>
13 #include <usterr-signal-safe.h>
14
15 #include "../libmsgpack/msgpack.h"
16 #include "lttng-bytecode.h"
17 #include "share.h"
18
19 /*
20 * We want this write to be atomic AND non-blocking, meaning that we
21 * want to write either everything OR nothing.
22 * According to `pipe(7)`, writes that are less than `PIPE_BUF` bytes must be
23 * atomic, so we bound the capture buffer size to the `PIPE_BUF` minus the size
24 * of the notification struct we are sending alongside the capture buffer.
25 */
26 #define CAPTURE_BUFFER_SIZE \
27 (PIPE_BUF - sizeof(struct lttng_ust_event_notifier_notification) - 1)
28
29 struct lttng_event_notifier_notification {
30 int notification_fd;
31 uint64_t event_notifier_token;
32 uint8_t capture_buf[CAPTURE_BUFFER_SIZE];
33 struct lttng_msgpack_writer writer;
34 bool has_captures;
35 };
36
37 static
38 void capture_enum(struct lttng_msgpack_writer *writer,
39 struct lttng_interpreter_output *output)
40 {
41 lttng_msgpack_begin_map(writer, 2);
42 lttng_msgpack_write_str(writer, "type");
43 lttng_msgpack_write_str(writer, "enum");
44
45 lttng_msgpack_write_str(writer, "value");
46
47 switch (output->type) {
48 case LTTNG_INTERPRETER_TYPE_SIGNED_ENUM:
49 lttng_msgpack_write_signed_integer(writer, output->u.s);
50 break;
51 case LTTNG_INTERPRETER_TYPE_UNSIGNED_ENUM:
52 lttng_msgpack_write_signed_integer(writer, output->u.u);
53 break;
54 default:
55 abort();
56 }
57
58 lttng_msgpack_end_map(writer);
59 }
60
61 static
62 int64_t capture_sequence_element_signed(uint8_t *ptr,
63 const struct lttng_integer_type *type)
64 {
65 int64_t value;
66 unsigned int size = type->size;
67 bool byte_order_reversed = type->reverse_byte_order;
68
69 switch (size) {
70 case 8:
71 value = *ptr;
72 break;
73 case 16:
74 {
75 int16_t tmp;
76 tmp = *(int16_t *) ptr;
77 if (byte_order_reversed)
78 tmp = bswap_16(tmp);
79
80 value = tmp;
81 break;
82 }
83 case 32:
84 {
85 int32_t tmp;
86 tmp = *(int32_t *) ptr;
87 if (byte_order_reversed)
88 tmp = bswap_32(tmp);
89
90 value = tmp;
91 break;
92 }
93 case 64:
94 {
95 int64_t tmp;
96 tmp = *(int64_t *) ptr;
97 if (byte_order_reversed)
98 tmp = bswap_64(tmp);
99
100 value = tmp;
101 break;
102 }
103 default:
104 abort();
105 }
106
107 return value;
108 }
109
110 static
111 uint64_t capture_sequence_element_unsigned(uint8_t *ptr,
112 const struct lttng_integer_type *type)
113 {
114 uint64_t value;
115 unsigned int size = type->size;
116 bool byte_order_reversed = type->reverse_byte_order;
117
118 switch (size) {
119 case 8:
120 value = *ptr;
121 break;
122 case 16:
123 {
124 uint16_t tmp;
125 tmp = *(uint16_t *) ptr;
126 if (byte_order_reversed)
127 tmp = bswap_16(tmp);
128
129 value = tmp;
130 break;
131 }
132 case 32:
133 {
134 uint32_t tmp;
135 tmp = *(uint32_t *) ptr;
136 if (byte_order_reversed)
137 tmp = bswap_32(tmp);
138
139 value = tmp;
140 break;
141 }
142 case 64:
143 {
144 uint64_t tmp;
145 tmp = *(uint64_t *) ptr;
146 if (byte_order_reversed)
147 tmp = bswap_64(tmp);
148
149 value = tmp;
150 break;
151 }
152 default:
153 abort();
154 }
155
156 return value;
157 }
158
159 static
160 void capture_sequence(struct lttng_msgpack_writer *writer,
161 struct lttng_interpreter_output *output)
162 {
163 const struct lttng_integer_type *integer_type;
164 const struct lttng_type *nested_type;
165 uint8_t *ptr;
166 bool signedness;
167 int i;
168
169 lttng_msgpack_begin_array(writer, output->u.sequence.nr_elem);
170
171 ptr = (uint8_t *) output->u.sequence.ptr;
172 nested_type = output->u.sequence.nested_type;
173 switch (nested_type->atype) {
174 case atype_integer:
175 integer_type = &nested_type->u.integer;
176 break;
177 case atype_enum:
178 /* Treat enumeration as an integer. */
179 integer_type = &nested_type->u.enum_nestable.container_type->u.integer;
180 break;
181 default:
182 /* Capture of array of non-integer are not supported. */
183 abort();
184 }
185 signedness = integer_type->signedness;
186 for (i = 0; i < output->u.sequence.nr_elem; i++) {
187 if (signedness) {
188 lttng_msgpack_write_signed_integer(writer,
189 capture_sequence_element_signed(ptr, integer_type));
190 } else {
191 lttng_msgpack_write_unsigned_integer(writer,
192 capture_sequence_element_unsigned(ptr, integer_type));
193 }
194
195 /*
196 * We assume that alignment is smaller or equal to the size.
197 * This currently holds true but if it changes in the future,
198 * we will want to change the pointer arithmetics below to
199 * take into account that the next element might be further
200 * away.
201 */
202 assert(integer_type->alignment <= integer_type->size);
203
204 /* Size is in number of bits. */
205 ptr += (integer_type->size / CHAR_BIT) ;
206 }
207
208 lttng_msgpack_end_array(writer);
209 }
210
211 static
212 void notification_init(struct lttng_event_notifier_notification *notif,
213 struct lttng_event_notifier *event_notifier)
214 {
215 struct lttng_msgpack_writer *writer = &notif->writer;
216
217 notif->event_notifier_token = event_notifier->user_token;
218 notif->notification_fd = event_notifier->group->notification_fd;
219 notif->has_captures = false;
220
221 if (event_notifier->num_captures > 0) {
222 lttng_msgpack_writer_init(writer, notif->capture_buf,
223 CAPTURE_BUFFER_SIZE);
224
225 lttng_msgpack_begin_array(writer, event_notifier->num_captures);
226 notif->has_captures = true;
227 }
228 }
229
230 static
231 void notification_append_capture(
232 struct lttng_event_notifier_notification *notif,
233 struct lttng_interpreter_output *output)
234 {
235 struct lttng_msgpack_writer *writer = &notif->writer;
236
237 switch (output->type) {
238 case LTTNG_INTERPRETER_TYPE_S64:
239 lttng_msgpack_write_signed_integer(writer, output->u.s);
240 break;
241 case LTTNG_INTERPRETER_TYPE_U64:
242 lttng_msgpack_write_unsigned_integer(writer, output->u.u);
243 break;
244 case LTTNG_INTERPRETER_TYPE_DOUBLE:
245 lttng_msgpack_write_double(writer, output->u.d);
246 break;
247 case LTTNG_INTERPRETER_TYPE_STRING:
248 lttng_msgpack_write_str(writer, output->u.str.str);
249 break;
250 case LTTNG_INTERPRETER_TYPE_SEQUENCE:
251 capture_sequence(writer, output);
252 break;
253 case LTTNG_INTERPRETER_TYPE_SIGNED_ENUM:
254 case LTTNG_INTERPRETER_TYPE_UNSIGNED_ENUM:
255 capture_enum(writer, output);
256 break;
257 default:
258 abort();
259 }
260 }
261
262 static
263 void notification_append_empty_capture(
264 struct lttng_event_notifier_notification *notif)
265 {
266 lttng_msgpack_write_nil(&notif->writer);
267 }
268
269 static void record_error(struct lttng_event_notifier *event_notifier)
270 {
271 struct lttng_event_notifier_group *event_notifier_group =
272 event_notifier->group;
273 struct lttng_counter *error_counter;
274 size_t dimension_index[1];
275 int ret;
276
277 error_counter = CMM_LOAD_SHARED(event_notifier_group->error_counter);
278 /*
279 * load-acquire paired with store-release orders creation of the
280 * error counter and setting error_counter_len before the
281 * error_counter is used.
282 * Currently a full memory barrier is used, which could be
283 * turned into acquire-release barriers.
284 */
285 cmm_smp_mb();
286 /* This group may not have an error counter attached to it. */
287 if (!error_counter)
288 return;
289
290 dimension_index[0] = event_notifier->error_counter_index;
291 ret = event_notifier_group->error_counter->ops->counter_add(
292 error_counter->counter, dimension_index, 1);
293 if (ret)
294 WARN_ON_ONCE(1);
295 }
296
297 static
298 void notification_send(struct lttng_event_notifier_notification *notif,
299 struct lttng_event_notifier *event_notifier)
300 {
301 ssize_t ret;
302 size_t content_len;
303 int iovec_count = 1;
304 struct lttng_ust_event_notifier_notification ust_notif = {0};
305 struct iovec iov[2];
306
307 assert(notif);
308
309 ust_notif.token = event_notifier->user_token;
310
311 /*
312 * Prepare sending the notification from multiple buffers using an
313 * array of `struct iovec`. The first buffer of the vector is
314 * notification structure itself and is always present.
315 */
316 iov[0].iov_base = &ust_notif;
317 iov[0].iov_len = sizeof(ust_notif);
318
319 if (notif->has_captures) {
320 /*
321 * If captures were requested, the second buffer of the array
322 * is the capture buffer.
323 */
324 assert(notif->writer.buffer);
325 content_len = notif->writer.write_pos - notif->writer.buffer;
326
327 assert(content_len > 0 && content_len <= CAPTURE_BUFFER_SIZE);
328
329 iov[1].iov_base = notif->capture_buf;
330 iov[1].iov_len = content_len;
331
332 iovec_count++;
333 } else {
334 content_len = 0;
335 }
336
337 /*
338 * Update the capture buffer size so that receiver of the buffer will
339 * know how much to expect.
340 */
341 ust_notif.capture_buf_size = content_len;
342
343 /* Send all the buffers. */
344 ret = patient_writev(notif->notification_fd, iov, iovec_count);
345 if (ret == -1) {
346 if (errno == EAGAIN) {
347 record_error(event_notifier);
348 DBG("Cannot send event_notifier notification without blocking: %s",
349 strerror(errno));
350 } else {
351 DBG("Error to sending event notifier notification: %s",
352 strerror(errno));
353 abort();
354 }
355 }
356 }
357
358 void lttng_event_notifier_notification_send(
359 struct lttng_event_notifier *event_notifier,
360 const char *stack_data)
361 {
362 /*
363 * This function is called from the probe, we must do dynamic
364 * allocation in this context.
365 */
366 struct lttng_event_notifier_notification notif = {0};
367
368 notification_init(&notif, event_notifier);
369
370 if (caa_unlikely(!cds_list_empty(&event_notifier->capture_bytecode_runtime_head))) {
371 struct lttng_bytecode_runtime *capture_bc_runtime;
372
373 /*
374 * Iterate over all the capture bytecodes. If the interpreter
375 * functions returns successfully, append the value of the
376 * `output` parameter to the capture buffer. If the interpreter
377 * fails, append an empty capture to the buffer.
378 */
379 cds_list_for_each_entry(capture_bc_runtime,
380 &event_notifier->capture_bytecode_runtime_head, node) {
381 struct lttng_interpreter_output output;
382
383 if (capture_bc_runtime->interpreter_funcs.capture(capture_bc_runtime,
384 stack_data, &output) & LTTNG_INTERPRETER_RECORD_FLAG)
385 notification_append_capture(&notif, &output);
386 else
387 notification_append_empty_capture(&notif);
388 }
389 }
390
391 /*
392 * Send the notification (including the capture buffer) to the
393 * sessiond.
394 */
395 notification_send(&notif, event_notifier);
396 }
This page took 0.03695 seconds and 4 git commands to generate.