Commit | Line | Data |
---|---|---|
21f58fb7 FD |
1 | /* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only) |
2 | * | |
3 | * lttng-event-notifier-notification.c | |
4 | * | |
5 | * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com> | |
6 | */ | |
7 | ||
42f3ef8c FD |
8 | #include <linux/bug.h> |
9 | ||
10 | #include <lttng/lttng-bytecode.h> | |
21f58fb7 | 11 | #include <lttng/events.h> |
42f3ef8c | 12 | #include <lttng/msgpack.h> |
21f58fb7 FD |
13 | #include <lttng/event-notifier-notification.h> |
14 | ||
42f3ef8c FD |
15 | static |
16 | int capture_enum(struct lttng_msgpack_writer *writer, | |
17 | struct lttng_interpreter_output *output) __attribute__ ((unused)); | |
18 | static | |
19 | int capture_enum(struct lttng_msgpack_writer *writer, | |
20 | struct lttng_interpreter_output *output) | |
21 | { | |
22 | int ret; | |
23 | ||
24 | /* | |
25 | * Enums are captured as a map containing 2 key-value pairs. Such as: | |
26 | * - type: enum | |
27 | * value: 177 | |
28 | */ | |
29 | ret = lttng_msgpack_begin_map(writer, 2); | |
30 | if (ret) { | |
31 | WARN_ON_ONCE(1); | |
32 | goto end; | |
33 | } | |
34 | ||
35 | ret = lttng_msgpack_write_str(writer, "type"); | |
36 | if (ret) { | |
37 | WARN_ON_ONCE(1); | |
38 | goto end; | |
39 | } | |
40 | ||
41 | ret = lttng_msgpack_write_str(writer, "enum"); | |
42 | if (ret) { | |
43 | WARN_ON_ONCE(1); | |
44 | goto end; | |
45 | } | |
46 | ||
47 | ret = lttng_msgpack_write_str(writer, "value"); | |
48 | if (ret) { | |
49 | WARN_ON_ONCE(1); | |
50 | goto end; | |
51 | } | |
52 | ||
53 | switch (output->type) { | |
54 | case LTTNG_INTERPRETER_TYPE_SIGNED_ENUM: | |
55 | ret = lttng_msgpack_write_signed_integer(writer, output->u.s); | |
56 | if (ret) { | |
57 | WARN_ON_ONCE(1); | |
58 | goto end; | |
59 | } | |
60 | break; | |
61 | case LTTNG_INTERPRETER_TYPE_UNSIGNED_ENUM: | |
62 | ret = lttng_msgpack_write_signed_integer(writer, output->u.u); | |
63 | if (ret) { | |
64 | WARN_ON_ONCE(1); | |
65 | goto end; | |
66 | } | |
67 | break; | |
68 | default: | |
69 | WARN_ON(1); | |
70 | } | |
71 | ||
72 | ret = lttng_msgpack_end_map(writer); | |
73 | if (ret) | |
74 | WARN_ON_ONCE(1); | |
75 | ||
76 | end: | |
77 | return ret; | |
78 | } | |
79 | ||
80 | static | |
81 | int64_t capture_sequence_element_signed(uint8_t *ptr, | |
82 | const struct lttng_integer_type *type) | |
83 | { | |
84 | int64_t value = 0; | |
85 | unsigned int size = type->size; | |
86 | bool byte_order_reversed = type->reverse_byte_order; | |
87 | ||
88 | switch (size) { | |
89 | case 8: | |
90 | value = *ptr; | |
91 | break; | |
92 | case 16: | |
93 | { | |
94 | int16_t tmp; | |
95 | tmp = *(int16_t *) ptr; | |
96 | if (byte_order_reversed) | |
97 | __swab16s(&tmp); | |
98 | ||
99 | value = tmp; | |
100 | break; | |
101 | } | |
102 | case 32: | |
103 | { | |
104 | int32_t tmp; | |
105 | tmp = *(int32_t *) ptr; | |
106 | if (byte_order_reversed) | |
107 | __swab32s(&tmp); | |
108 | ||
109 | value = tmp; | |
110 | break; | |
111 | } | |
112 | case 64: | |
113 | { | |
114 | int64_t tmp; | |
115 | tmp = *(int64_t *) ptr; | |
116 | if (byte_order_reversed) | |
117 | __swab64s(&tmp); | |
118 | ||
119 | value = tmp; | |
120 | break; | |
121 | } | |
122 | default: | |
123 | WARN_ON(1); | |
124 | } | |
125 | ||
126 | return value; | |
127 | } | |
128 | ||
129 | static | |
130 | uint64_t capture_sequence_element_unsigned(uint8_t *ptr, | |
131 | const struct lttng_integer_type *type) | |
132 | { | |
133 | uint64_t value = 0; | |
134 | unsigned int size = type->size; | |
135 | bool byte_order_reversed = type->reverse_byte_order; | |
136 | ||
137 | switch (size) { | |
138 | case 8: | |
139 | value = *ptr; | |
140 | break; | |
141 | case 16: | |
142 | { | |
143 | uint16_t tmp; | |
144 | tmp = *(uint16_t *) ptr; | |
145 | if (byte_order_reversed) | |
146 | __swab16s(&tmp); | |
147 | ||
148 | value = tmp; | |
149 | break; | |
150 | } | |
151 | case 32: | |
152 | { | |
153 | uint32_t tmp; | |
154 | tmp = *(uint32_t *) ptr; | |
155 | if (byte_order_reversed) | |
156 | __swab32s(&tmp); | |
157 | ||
158 | value = tmp; | |
159 | break; | |
160 | } | |
161 | case 64: | |
162 | { | |
163 | uint64_t tmp; | |
164 | tmp = *(uint64_t *) ptr; | |
165 | if (byte_order_reversed) | |
166 | __swab64s(&tmp); | |
167 | ||
168 | value = tmp; | |
169 | break; | |
170 | } | |
171 | default: | |
172 | WARN_ON(1); | |
173 | } | |
174 | ||
175 | return value; | |
176 | } | |
177 | ||
178 | static | |
179 | int capture_sequence(struct lttng_msgpack_writer *writer, | |
180 | struct lttng_interpreter_output *output) __attribute__ ((unused)); | |
181 | int capture_sequence(struct lttng_msgpack_writer *writer, | |
182 | struct lttng_interpreter_output *output) | |
183 | { | |
184 | const struct lttng_integer_type *integer_type = NULL; | |
185 | const struct lttng_type *nested_type; | |
186 | uint8_t *ptr; | |
187 | bool signedness; | |
188 | int ret, i; | |
189 | ||
190 | ret = lttng_msgpack_begin_array(writer, output->u.sequence.nr_elem); | |
191 | if (ret) { | |
192 | WARN_ON_ONCE(1); | |
193 | goto end; | |
194 | } | |
195 | ||
196 | ptr = (uint8_t *) output->u.sequence.ptr; | |
197 | nested_type = output->u.sequence.nested_type; | |
198 | switch (nested_type->atype) { | |
199 | case atype_integer: | |
200 | integer_type = &nested_type->u.integer; | |
201 | break; | |
202 | case atype_enum_nestable: | |
203 | /* Treat enumeration as an integer. */ | |
204 | integer_type = &nested_type->u.enum_nestable.container_type->u.integer; | |
205 | break; | |
206 | default: | |
207 | /* Capture of array of non-integer are not supported. */ | |
208 | WARN_ON(1); | |
209 | } | |
210 | signedness = integer_type->signedness; | |
211 | for (i = 0; i < output->u.sequence.nr_elem; i++) { | |
212 | if (signedness) { | |
213 | ret = lttng_msgpack_write_signed_integer(writer, | |
214 | capture_sequence_element_signed(ptr, integer_type)); | |
215 | if (ret) { | |
216 | WARN_ON_ONCE(1); | |
217 | goto end; | |
218 | } | |
219 | } else { | |
220 | ret = lttng_msgpack_write_unsigned_integer(writer, | |
221 | capture_sequence_element_unsigned(ptr, integer_type)); | |
222 | if (ret) { | |
223 | WARN_ON_ONCE(1); | |
224 | goto end; | |
225 | } | |
226 | } | |
227 | ||
228 | /* | |
229 | * We assume that alignment is smaller or equal to the size. | |
230 | * This currently holds true but if it changes in the future, | |
231 | * we will want to change the pointer arithmetics below to | |
232 | * take into account that the next element might be further | |
233 | * away. | |
234 | */ | |
235 | WARN_ON(integer_type->alignment > integer_type->size); | |
236 | ||
237 | /* Size is in number of bits. */ | |
238 | ptr += (integer_type->size / CHAR_BIT) ; | |
239 | } | |
240 | ||
241 | ret = lttng_msgpack_end_array(writer); | |
242 | if (ret) | |
243 | WARN_ON_ONCE(1); | |
244 | end: | |
245 | return ret; | |
246 | } | |
247 | ||
21f58fb7 FD |
248 | void lttng_event_notifier_notification_send(struct lttng_event_notifier *event_notifier) |
249 | { | |
250 | struct lttng_event_notifier_group *event_notifier_group = event_notifier->group; | |
251 | struct lib_ring_buffer_ctx ctx; | |
252 | int ret; | |
253 | ||
254 | if (unlikely(!READ_ONCE(event_notifier->enabled))) | |
255 | return; | |
256 | ||
257 | lib_ring_buffer_ctx_init(&ctx, event_notifier_group->chan, NULL, | |
258 | sizeof(event_notifier->user_token), | |
259 | lttng_alignof(event_notifier->user_token), -1); | |
260 | ret = event_notifier_group->ops->event_reserve(&ctx, 0); | |
261 | if (ret < 0) { | |
262 | //TODO: error handling with counter maps | |
263 | //silently drop for now. | |
264 | WARN_ON_ONCE(1); | |
265 | return; | |
266 | } | |
267 | lib_ring_buffer_align_ctx(&ctx, lttng_alignof(event_notifier->user_token)); | |
268 | event_notifier_group->ops->event_write(&ctx, &event_notifier->user_token, | |
269 | sizeof(event_notifier->user_token)); | |
270 | event_notifier_group->ops->event_commit(&ctx); | |
271 | irq_work_queue(&event_notifier_group->wakeup_pending); | |
272 | } |