SoW-2020-0002: Trace Hit Counters: Implement key-addressed counters in shared memory...
[deliverable/lttng-ust.git] / liblttng-ust / trigger-notification.c
1 /*
2 * trigger-notification.c
3 *
4 * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; only
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #define _GNU_SOURCE
22 #define _LGPL_SOURCE
23
24 #include <assert.h>
25 #include <byteswap.h>
26 #include <errno.h>
27 #include <lttng/ust-events.h>
28 #include <usterr-signal-safe.h>
29
30 #include "../libmsgpack/msgpack.h"
31 #include "lttng-bytecode.h"
32 #include "share.h"
33
34 /*
35 * We want this write to be atomic AND non-blocking, meaning that we
36 * want to write either everything OR nothing.
37 * According to `pipe(7)`, writes that are less than `PIPE_BUF` bytes must be
38 * atomic, so we bound the capture buffer size to the `PIPE_BUF` minus the size
39 * of the notification struct we are sending alongside the capture buffer.
40 */
41 #define CAPTURE_BUFFER_SIZE \
42 (PIPE_BUF - sizeof(struct lttng_ust_trigger_notification) - 1)
43
44 struct lttng_trigger_notification {
45 int notification_fd;
46 uint64_t trigger_id;
47 uint8_t capture_buf[CAPTURE_BUFFER_SIZE];
48 struct lttng_msgpack_writer writer;
49 bool has_captures;
50 };
51
52 static
53 void capture_enum(struct lttng_msgpack_writer *writer,
54 struct lttng_interpreter_output *output)
55 {
56 lttng_msgpack_begin_map(writer, 2);
57 lttng_msgpack_write_str(writer, "type");
58 lttng_msgpack_write_str(writer, "enum");
59
60 lttng_msgpack_write_str(writer, "value");
61
62 switch (output->type) {
63 case LTTNG_INTERPRETER_TYPE_SIGNED_ENUM:
64 lttng_msgpack_write_signed_integer(writer, output->u.s);
65 break;
66 case LTTNG_INTERPRETER_TYPE_UNSIGNED_ENUM:
67 lttng_msgpack_write_signed_integer(writer, output->u.u);
68 break;
69 default:
70 abort();
71 }
72
73 lttng_msgpack_end_map(writer);
74 }
75
76 static
77 int64_t capture_sequence_element_signed(uint8_t *ptr,
78 const struct lttng_integer_type *type)
79 {
80 int64_t value;
81 unsigned int size = type->size;
82 bool byte_order_reversed = type->reverse_byte_order;
83
84 switch (size) {
85 case 8:
86 value = *ptr;
87 break;
88 case 16:
89 {
90 int16_t tmp;
91 tmp = *(int16_t *) ptr;
92 if (byte_order_reversed)
93 tmp = bswap_16(tmp);
94
95 value = tmp;
96 break;
97 }
98 case 32:
99 {
100 int32_t tmp;
101 tmp = *(int32_t *) ptr;
102 if (byte_order_reversed)
103 tmp = bswap_32(tmp);
104
105 value = tmp;
106 break;
107 }
108 case 64:
109 {
110 int64_t tmp;
111 tmp = *(int64_t *) ptr;
112 if (byte_order_reversed)
113 tmp = bswap_64(tmp);
114
115 value = tmp;
116 break;
117 }
118 default:
119 abort();
120 }
121
122 return value;
123 }
124
125 static
126 uint64_t capture_sequence_element_unsigned(uint8_t *ptr,
127 const struct lttng_integer_type *type)
128 {
129 uint64_t value;
130 unsigned int size = type->size;
131 bool byte_order_reversed = type->reverse_byte_order;
132
133 switch (size) {
134 case 8:
135 value = *ptr;
136 break;
137 case 16:
138 {
139 uint16_t tmp;
140 tmp = *(uint16_t *) ptr;
141 if (byte_order_reversed)
142 tmp = bswap_16(tmp);
143
144 value = tmp;
145 break;
146 }
147 case 32:
148 {
149 uint32_t tmp;
150 tmp = *(uint32_t *) ptr;
151 if (byte_order_reversed)
152 tmp = bswap_32(tmp);
153
154 value = tmp;
155 break;
156 }
157 case 64:
158 {
159 uint64_t tmp;
160 tmp = *(uint64_t *) ptr;
161 if (byte_order_reversed)
162 tmp = bswap_64(tmp);
163
164 value = tmp;
165 break;
166 }
167 default:
168 abort();
169 }
170
171 return value;
172 }
173
174 static
175 void capture_sequence(struct lttng_msgpack_writer *writer,
176 struct lttng_interpreter_output *output)
177 {
178 const struct lttng_integer_type *integer_type;
179 const struct lttng_type *nested_type;
180 uint8_t *ptr;
181 bool signedness;
182 int i;
183
184 lttng_msgpack_begin_array(writer, output->u.sequence.nr_elem);
185
186 ptr = (uint8_t *) output->u.sequence.ptr;
187 nested_type = output->u.sequence.nested_type;
188 switch (nested_type->atype) {
189 case atype_integer:
190 integer_type = &nested_type->u.integer;
191 break;
192 case atype_enum:
193 /* Treat enumeration as an integer. */
194 integer_type = &nested_type->u.enum_nestable.container_type->u.integer;
195 break;
196 default:
197 /* Capture of array of non-integer are not supported. */
198 abort();
199 }
200 signedness = integer_type->signedness;
201 for (i = 0; i < output->u.sequence.nr_elem; i++) {
202 if (signedness) {
203 lttng_msgpack_write_signed_integer(writer,
204 capture_sequence_element_signed(ptr, integer_type));
205 } else {
206 lttng_msgpack_write_unsigned_integer(writer,
207 capture_sequence_element_unsigned(ptr, integer_type));
208 }
209
210 /*
211 * We assume that alignment is smaller or equal to the size.
212 * This currently holds true but if it changes in the future,
213 * we will want to change the pointer arithmetics below to
214 * take into account that the next element might be further
215 * away.
216 */
217 assert(integer_type->alignment <= integer_type->size);
218
219 /* Size is in number of bits. */
220 ptr += (integer_type->size / CHAR_BIT) ;
221 }
222
223 lttng_msgpack_end_array(writer);
224 }
225
226 static
227 void notification_init(struct lttng_trigger_notification *notif,
228 struct lttng_trigger *trigger)
229 {
230 struct lttng_msgpack_writer *writer = &notif->writer;
231
232 notif->trigger_id = trigger->id;
233 notif->notification_fd = trigger->group->notification_fd;
234 notif->has_captures = false;
235
236 if (trigger->num_captures > 0) {
237 lttng_msgpack_writer_init(writer, notif->capture_buf,
238 CAPTURE_BUFFER_SIZE);
239
240 lttng_msgpack_begin_array(writer, trigger->num_captures);
241 notif->has_captures = true;
242 }
243 }
244
245 static
246 void notification_append_capture(
247 struct lttng_trigger_notification *notif,
248 struct lttng_interpreter_output *output)
249 {
250 struct lttng_msgpack_writer *writer = &notif->writer;
251
252 switch (output->type) {
253 case LTTNG_INTERPRETER_TYPE_S64:
254 lttng_msgpack_write_signed_integer(writer, output->u.s);
255 break;
256 case LTTNG_INTERPRETER_TYPE_U64:
257 lttng_msgpack_write_unsigned_integer(writer, output->u.u);
258 break;
259 case LTTNG_INTERPRETER_TYPE_DOUBLE:
260 lttng_msgpack_write_double(writer, output->u.d);
261 break;
262 case LTTNG_INTERPRETER_TYPE_STRING:
263 lttng_msgpack_write_str(writer, output->u.str.str);
264 break;
265 case LTTNG_INTERPRETER_TYPE_SEQUENCE:
266 capture_sequence(writer, output);
267 break;
268 case LTTNG_INTERPRETER_TYPE_SIGNED_ENUM:
269 case LTTNG_INTERPRETER_TYPE_UNSIGNED_ENUM:
270 capture_enum(writer, output);
271 break;
272 default:
273 abort();
274 }
275 }
276
277 static
278 void notification_append_empty_capture(
279 struct lttng_trigger_notification *notif)
280 {
281 lttng_msgpack_write_nil(&notif->writer);
282 }
283
284 static void record_error(struct lttng_trigger *trigger)
285 {
286 struct lttng_trigger_group *trigger_group = trigger->group;
287 size_t dimension_index[1];
288 int ret;
289
290 dimension_index[0] = trigger->error_counter_index;
291 ret = trigger_group->error_counter->ops->counter_add(
292 trigger_group->error_counter->counter,
293 dimension_index, 1);
294 if (ret)
295 WARN_ON_ONCE(1);
296 }
297
298 static
299 void notification_send(struct lttng_trigger_notification *notif,
300 struct lttng_trigger *trigger)
301 {
302 ssize_t ret;
303 size_t content_len;
304 int iovec_count = 1;
305 struct lttng_ust_trigger_notification ust_notif;
306 struct iovec iov[2];
307
308 assert(notif);
309
310 ust_notif.id = trigger->id;
311
312 /*
313 * Prepare sending the notification from multiple buffers using an
314 * array of `struct iovec`. The first buffer of the vector is
315 * notification structure itself and is always present.
316 */
317 iov[0].iov_base = &ust_notif;
318 iov[0].iov_len = sizeof(ust_notif);
319
320 if (notif->has_captures) {
321 /*
322 * If captures were requested, the second buffer of the array
323 * is the capture buffer.
324 */
325 assert(notif->writer.buffer);
326 content_len = notif->writer.write_pos - notif->writer.buffer;
327
328 assert(content_len > 0 && content_len <= CAPTURE_BUFFER_SIZE);
329
330 iov[1].iov_base = notif->capture_buf;
331 iov[1].iov_len = content_len;
332
333 iovec_count++;
334 } else {
335 content_len = 0;
336 }
337
338 /*
339 * Update the capture buffer size so that receiver of the buffer will
340 * know how much to expect.
341 */
342 ust_notif.capture_buf_size = content_len;
343
344 /* Send all the buffers. */
345 ret = patient_writev(notif->notification_fd, iov, iovec_count);
346 if (ret == -1) {
347 if (errno == EAGAIN) {
348 record_error(trigger);
349 DBG("Cannot send trigger notification without blocking: %s",
350 strerror(errno));
351 } else {
352 DBG("Error to sending trigger notification: %s",
353 strerror(errno));
354 abort();
355 }
356 }
357 }
358
359 void lttng_trigger_notification_send(struct lttng_trigger *trigger,
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_trigger_notification notif = {0};
367
368 notification_init(&notif, trigger);
369
370 if (caa_unlikely(!cds_list_empty(&trigger->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 &trigger->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, trigger);
396 }
This page took 0.050176 seconds and 5 git commands to generate.