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