Commit | Line | Data |
---|---|---|
ab0ee2ca | 1 | /* |
ab5be9fa | 2 | * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com> |
ab0ee2ca | 3 | * |
ab5be9fa | 4 | * SPDX-License-Identifier: GPL-2.0-only |
ab0ee2ca | 5 | * |
ab0ee2ca JG |
6 | */ |
7 | ||
8 | #include <lttng/trigger/trigger.h> | |
9 | #include <lttng/lttng-error.h> | |
c9e313bc SM |
10 | #include "notification-thread.hpp" |
11 | #include "notification-thread-commands.hpp" | |
12 | #include <common/error.hpp> | |
ab0ee2ca JG |
13 | #include <unistd.h> |
14 | #include <stdint.h> | |
15 | #include <inttypes.h> | |
16 | ||
17 | static | |
18 | void init_notification_thread_command(struct notification_thread_command *cmd) | |
19 | { | |
ab0ee2ca | 20 | CDS_INIT_LIST_HEAD(&cmd->cmd_list_node); |
8ada111f | 21 | lttng_waiter_init(&cmd->reply_waiter); |
ab0ee2ca JG |
22 | } |
23 | ||
24 | static | |
25 | int run_command_wait(struct notification_thread_handle *handle, | |
26 | struct notification_thread_command *cmd) | |
27 | { | |
28 | int ret; | |
29 | uint64_t notification_counter = 1; | |
30 | ||
ab0ee2ca JG |
31 | pthread_mutex_lock(&handle->cmd_queue.lock); |
32 | /* Add to queue. */ | |
33 | cds_list_add_tail(&cmd->cmd_list_node, | |
34 | &handle->cmd_queue.list); | |
35 | /* Wake-up thread. */ | |
f370852f | 36 | ret = lttng_write(handle->cmd_queue.event_fd, |
ab0ee2ca | 37 | ¬ification_counter, sizeof(notification_counter)); |
58d3fed5 | 38 | if (ret != sizeof(notification_counter)) { |
ab0ee2ca JG |
39 | PERROR("write to notification thread's queue event fd"); |
40 | /* | |
41 | * Remove the command from the list so the notification | |
42 | * thread does not process it. | |
43 | */ | |
44 | cds_list_del(&cmd->cmd_list_node); | |
45 | goto error_unlock_queue; | |
46 | } | |
47 | pthread_mutex_unlock(&handle->cmd_queue.lock); | |
48 | ||
8ada111f | 49 | lttng_waiter_wait(&cmd->reply_waiter); |
ab0ee2ca JG |
50 | return 0; |
51 | error_unlock_queue: | |
52 | pthread_mutex_unlock(&handle->cmd_queue.lock); | |
53 | return -1; | |
54 | } | |
55 | ||
0ab399e0 JG |
56 | static |
57 | struct notification_thread_command *notification_thread_command_copy( | |
58 | const struct notification_thread_command *original_cmd) | |
59 | { | |
60 | struct notification_thread_command *new_cmd; | |
61 | ||
64803277 | 62 | new_cmd = zmalloc<notification_thread_command>(); |
0ab399e0 JG |
63 | if (!new_cmd) { |
64 | goto end; | |
65 | } | |
66 | ||
67 | *new_cmd = *original_cmd; | |
68 | init_notification_thread_command(new_cmd); | |
69 | end: | |
70 | return new_cmd; | |
71 | } | |
72 | ||
73 | static | |
74 | int run_command_no_wait(struct notification_thread_handle *handle, | |
75 | const struct notification_thread_command *in_cmd) | |
76 | { | |
77 | int ret; | |
78 | uint64_t notification_counter = 1; | |
79 | struct notification_thread_command *new_cmd = | |
80 | notification_thread_command_copy(in_cmd); | |
81 | ||
82 | if (!new_cmd) { | |
83 | goto error; | |
84 | } | |
85 | new_cmd->is_async = true; | |
86 | ||
87 | pthread_mutex_lock(&handle->cmd_queue.lock); | |
88 | /* Add to queue. */ | |
89 | cds_list_add_tail(&new_cmd->cmd_list_node, | |
90 | &handle->cmd_queue.list); | |
91 | /* Wake-up thread. */ | |
f370852f | 92 | ret = lttng_write(handle->cmd_queue.event_fd, |
0ab399e0 JG |
93 | ¬ification_counter, sizeof(notification_counter)); |
94 | if (ret != sizeof(notification_counter)) { | |
95 | PERROR("write to notification thread's queue event fd"); | |
96 | /* | |
97 | * Remove the command from the list so the notification | |
98 | * thread does not process it. | |
99 | */ | |
100 | cds_list_del(&new_cmd->cmd_list_node); | |
101 | goto error_unlock_queue; | |
102 | } | |
103 | pthread_mutex_unlock(&handle->cmd_queue.lock); | |
104 | return 0; | |
105 | error_unlock_queue: | |
106 | free(new_cmd); | |
107 | pthread_mutex_unlock(&handle->cmd_queue.lock); | |
108 | error: | |
109 | return -1; | |
110 | } | |
111 | ||
ab0ee2ca JG |
112 | enum lttng_error_code notification_thread_command_register_trigger( |
113 | struct notification_thread_handle *handle, | |
0efb2ad7 JG |
114 | struct lttng_trigger *trigger, |
115 | bool is_trigger_anonymous) | |
ab0ee2ca JG |
116 | { |
117 | int ret; | |
118 | enum lttng_error_code ret_code; | |
0ab399e0 | 119 | struct notification_thread_command cmd = {}; |
ab0ee2ca | 120 | |
a0377dfe | 121 | LTTNG_ASSERT(trigger); |
ab0ee2ca JG |
122 | init_notification_thread_command(&cmd); |
123 | ||
124 | cmd.type = NOTIFICATION_COMMAND_TYPE_REGISTER_TRIGGER; | |
242388e4 | 125 | lttng_trigger_get(trigger); |
ac16173e | 126 | cmd.parameters.register_trigger.trigger = trigger; |
0efb2ad7 JG |
127 | cmd.parameters.register_trigger.is_trigger_anonymous = |
128 | is_trigger_anonymous; | |
ab0ee2ca JG |
129 | |
130 | ret = run_command_wait(handle, &cmd); | |
131 | if (ret) { | |
132 | ret_code = LTTNG_ERR_UNK; | |
133 | goto end; | |
134 | } | |
135 | ret_code = cmd.reply_code; | |
136 | end: | |
137 | return ret_code; | |
138 | } | |
139 | ||
140 | enum lttng_error_code notification_thread_command_unregister_trigger( | |
141 | struct notification_thread_handle *handle, | |
ac16173e | 142 | const struct lttng_trigger *trigger) |
ab0ee2ca JG |
143 | { |
144 | int ret; | |
145 | enum lttng_error_code ret_code; | |
0ab399e0 | 146 | struct notification_thread_command cmd = {}; |
ab0ee2ca JG |
147 | |
148 | init_notification_thread_command(&cmd); | |
149 | ||
150 | cmd.type = NOTIFICATION_COMMAND_TYPE_UNREGISTER_TRIGGER; | |
ac16173e | 151 | cmd.parameters.unregister_trigger.trigger = trigger; |
ab0ee2ca JG |
152 | |
153 | ret = run_command_wait(handle, &cmd); | |
154 | if (ret) { | |
155 | ret_code = LTTNG_ERR_UNK; | |
156 | goto end; | |
157 | } | |
158 | ret_code = cmd.reply_code; | |
159 | end: | |
160 | return ret_code; | |
161 | } | |
162 | ||
163 | enum lttng_error_code notification_thread_command_add_channel( | |
164 | struct notification_thread_handle *handle, | |
165 | char *session_name, uid_t uid, gid_t gid, | |
166 | char *channel_name, uint64_t key, | |
167 | enum lttng_domain_type domain, uint64_t capacity) | |
168 | { | |
169 | int ret; | |
170 | enum lttng_error_code ret_code; | |
0ab399e0 | 171 | struct notification_thread_command cmd = {}; |
ab0ee2ca JG |
172 | |
173 | init_notification_thread_command(&cmd); | |
174 | ||
175 | cmd.type = NOTIFICATION_COMMAND_TYPE_ADD_CHANNEL; | |
8abe313a JG |
176 | cmd.parameters.add_channel.session.name = session_name; |
177 | cmd.parameters.add_channel.session.uid = uid; | |
178 | cmd.parameters.add_channel.session.gid = gid; | |
179 | cmd.parameters.add_channel.channel.name = channel_name; | |
180 | cmd.parameters.add_channel.channel.key = key; | |
181 | cmd.parameters.add_channel.channel.domain = domain; | |
182 | cmd.parameters.add_channel.channel.capacity = capacity; | |
ab0ee2ca JG |
183 | |
184 | ret = run_command_wait(handle, &cmd); | |
185 | if (ret) { | |
186 | ret_code = LTTNG_ERR_UNK; | |
187 | goto end; | |
188 | } | |
189 | ret_code = cmd.reply_code; | |
190 | end: | |
191 | return ret_code; | |
192 | } | |
193 | ||
194 | enum lttng_error_code notification_thread_command_remove_channel( | |
195 | struct notification_thread_handle *handle, | |
196 | uint64_t key, enum lttng_domain_type domain) | |
197 | { | |
198 | int ret; | |
199 | enum lttng_error_code ret_code; | |
0ab399e0 | 200 | struct notification_thread_command cmd = {}; |
ab0ee2ca JG |
201 | |
202 | init_notification_thread_command(&cmd); | |
203 | ||
204 | cmd.type = NOTIFICATION_COMMAND_TYPE_REMOVE_CHANNEL; | |
205 | cmd.parameters.remove_channel.key = key; | |
206 | cmd.parameters.remove_channel.domain = domain; | |
207 | ||
208 | ret = run_command_wait(handle, &cmd); | |
209 | if (ret) { | |
210 | ret_code = LTTNG_ERR_UNK; | |
211 | goto end; | |
212 | } | |
213 | ret_code = cmd.reply_code; | |
214 | end: | |
215 | return ret_code; | |
216 | } | |
217 | ||
731c1b12 JG |
218 | enum lttng_error_code notification_thread_command_session_rotation_ongoing( |
219 | struct notification_thread_handle *handle, | |
220 | const char *session_name, uid_t uid, gid_t gid, | |
221 | uint64_t trace_archive_chunk_id) | |
222 | { | |
223 | int ret; | |
224 | enum lttng_error_code ret_code; | |
0ab399e0 | 225 | struct notification_thread_command cmd = {}; |
731c1b12 JG |
226 | |
227 | init_notification_thread_command(&cmd); | |
228 | ||
229 | cmd.type = NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_ONGOING; | |
230 | cmd.parameters.session_rotation.session_name = session_name; | |
231 | cmd.parameters.session_rotation.uid = uid; | |
232 | cmd.parameters.session_rotation.gid = gid; | |
233 | cmd.parameters.session_rotation.trace_archive_chunk_id = | |
234 | trace_archive_chunk_id; | |
235 | ||
236 | ret = run_command_wait(handle, &cmd); | |
237 | if (ret) { | |
238 | ret_code = LTTNG_ERR_UNK; | |
239 | goto end; | |
240 | } | |
241 | ret_code = cmd.reply_code; | |
242 | end: | |
243 | return ret_code; | |
244 | } | |
245 | ||
246 | enum lttng_error_code notification_thread_command_session_rotation_completed( | |
247 | struct notification_thread_handle *handle, | |
248 | const char *session_name, uid_t uid, gid_t gid, | |
249 | uint64_t trace_archive_chunk_id, | |
250 | struct lttng_trace_archive_location *location) | |
251 | { | |
252 | int ret; | |
253 | enum lttng_error_code ret_code; | |
0ab399e0 | 254 | struct notification_thread_command cmd = {}; |
731c1b12 JG |
255 | |
256 | init_notification_thread_command(&cmd); | |
257 | ||
258 | cmd.type = NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_COMPLETED; | |
259 | cmd.parameters.session_rotation.session_name = session_name; | |
260 | cmd.parameters.session_rotation.uid = uid; | |
261 | cmd.parameters.session_rotation.gid = gid; | |
262 | cmd.parameters.session_rotation.trace_archive_chunk_id = | |
263 | trace_archive_chunk_id; | |
264 | cmd.parameters.session_rotation.location = location; | |
265 | ||
266 | ret = run_command_wait(handle, &cmd); | |
267 | if (ret) { | |
268 | ret_code = LTTNG_ERR_UNK; | |
269 | goto end; | |
270 | } | |
271 | ret_code = cmd.reply_code; | |
272 | end: | |
273 | return ret_code; | |
274 | } | |
275 | ||
d02d7404 JR |
276 | enum lttng_error_code notification_thread_command_add_tracer_event_source( |
277 | struct notification_thread_handle *handle, | |
278 | int tracer_event_source_fd, | |
279 | enum lttng_domain_type domain) | |
280 | { | |
281 | int ret; | |
282 | enum lttng_error_code ret_code; | |
283 | struct notification_thread_command cmd = {}; | |
284 | ||
a0377dfe | 285 | LTTNG_ASSERT(tracer_event_source_fd >= 0); |
d02d7404 JR |
286 | |
287 | init_notification_thread_command(&cmd); | |
288 | ||
289 | cmd.type = NOTIFICATION_COMMAND_TYPE_ADD_TRACER_EVENT_SOURCE; | |
290 | cmd.parameters.tracer_event_source.tracer_event_source_fd = | |
291 | tracer_event_source_fd; | |
292 | cmd.parameters.tracer_event_source.domain = domain; | |
293 | ||
294 | ret = run_command_wait(handle, &cmd); | |
295 | if (ret) { | |
296 | ret_code = LTTNG_ERR_UNK; | |
297 | goto end; | |
298 | } | |
299 | ||
300 | ret_code = cmd.reply_code; | |
301 | end: | |
302 | return ret_code; | |
303 | } | |
304 | ||
305 | enum lttng_error_code notification_thread_command_remove_tracer_event_source( | |
306 | struct notification_thread_handle *handle, | |
307 | int tracer_event_source_fd) | |
308 | { | |
309 | int ret; | |
310 | enum lttng_error_code ret_code; | |
311 | struct notification_thread_command cmd = {}; | |
312 | ||
313 | init_notification_thread_command(&cmd); | |
314 | ||
315 | cmd.type = NOTIFICATION_COMMAND_TYPE_REMOVE_TRACER_EVENT_SOURCE; | |
316 | cmd.parameters.tracer_event_source.tracer_event_source_fd = | |
317 | tracer_event_source_fd; | |
318 | ||
319 | ret = run_command_wait(handle, &cmd); | |
320 | if (ret) { | |
321 | ret_code = LTTNG_ERR_UNK; | |
322 | goto end; | |
323 | } | |
324 | ||
325 | ret_code = cmd.reply_code; | |
326 | end: | |
327 | return ret_code; | |
328 | } | |
329 | ||
fbc9f37d JR |
330 | enum lttng_error_code notification_thread_command_list_triggers( |
331 | struct notification_thread_handle *handle, | |
332 | uid_t uid, | |
333 | struct lttng_triggers **triggers) | |
334 | { | |
335 | int ret; | |
336 | enum lttng_error_code ret_code; | |
337 | struct notification_thread_command cmd = {}; | |
338 | ||
a0377dfe FD |
339 | LTTNG_ASSERT(handle); |
340 | LTTNG_ASSERT(triggers); | |
fbc9f37d JR |
341 | |
342 | init_notification_thread_command(&cmd); | |
343 | ||
344 | cmd.type = NOTIFICATION_COMMAND_TYPE_LIST_TRIGGERS; | |
345 | cmd.parameters.list_triggers.uid = uid; | |
346 | ||
347 | ret = run_command_wait(handle, &cmd); | |
348 | if (ret) { | |
349 | ret_code = LTTNG_ERR_UNK; | |
350 | goto end; | |
351 | } | |
352 | ||
353 | ret_code = cmd.reply_code; | |
354 | *triggers = cmd.reply.list_triggers.triggers; | |
355 | ||
356 | end: | |
357 | return ret_code; | |
358 | } | |
359 | ||
ab0ee2ca JG |
360 | void notification_thread_command_quit( |
361 | struct notification_thread_handle *handle) | |
362 | { | |
363 | int ret; | |
0ab399e0 | 364 | struct notification_thread_command cmd = {}; |
ab0ee2ca JG |
365 | |
366 | init_notification_thread_command(&cmd); | |
367 | ||
368 | cmd.type = NOTIFICATION_COMMAND_TYPE_QUIT; | |
369 | ret = run_command_wait(handle, &cmd); | |
a0377dfe | 370 | LTTNG_ASSERT(!ret && cmd.reply_code == LTTNG_OK); |
ab0ee2ca | 371 | } |
f2b3ef9f JG |
372 | |
373 | int notification_thread_client_communication_update( | |
374 | struct notification_thread_handle *handle, | |
375 | notification_client_id id, | |
376 | enum client_transmission_status transmission_status) | |
377 | { | |
378 | struct notification_thread_command cmd = {}; | |
379 | ||
380 | init_notification_thread_command(&cmd); | |
381 | ||
382 | cmd.type = NOTIFICATION_COMMAND_TYPE_CLIENT_COMMUNICATION_UPDATE; | |
383 | cmd.parameters.client_communication_update.id = id; | |
384 | cmd.parameters.client_communication_update.status = transmission_status; | |
385 | return run_command_no_wait(handle, &cmd); | |
386 | } | |
b9a8d78f | 387 | |
8790759c FD |
388 | enum lttng_error_code notification_thread_command_get_trigger( |
389 | struct notification_thread_handle *handle, | |
390 | const struct lttng_trigger *trigger, | |
391 | struct lttng_trigger **real_trigger) | |
392 | { | |
393 | int ret; | |
394 | enum lttng_error_code ret_code; | |
395 | struct notification_thread_command cmd = {}; | |
396 | ||
397 | init_notification_thread_command(&cmd); | |
398 | ||
399 | cmd.type = NOTIFICATION_COMMAND_TYPE_GET_TRIGGER; | |
400 | cmd.parameters.get_trigger.trigger = trigger; | |
401 | ret = run_command_wait(handle, &cmd); | |
402 | if (ret) { | |
403 | ret_code = LTTNG_ERR_UNK; | |
404 | goto end; | |
405 | } | |
406 | ||
407 | ret_code = cmd.reply_code; | |
408 | *real_trigger = cmd.reply.get_trigger.trigger; | |
409 | ||
410 | end: | |
411 | return ret_code; | |
412 | } | |
413 | ||
82b3cbf4 JR |
414 | /* |
415 | * Takes ownership of the payload if present. | |
416 | */ | |
82b3cbf4 JR |
417 | struct lttng_event_notifier_notification *lttng_event_notifier_notification_create( |
418 | uint64_t tracer_token, | |
419 | enum lttng_domain_type domain, | |
420 | char *payload, | |
421 | size_t payload_size) | |
b9a8d78f FD |
422 | { |
423 | struct lttng_event_notifier_notification *notification = NULL; | |
424 | ||
a0377dfe FD |
425 | LTTNG_ASSERT(domain != LTTNG_DOMAIN_NONE); |
426 | LTTNG_ASSERT((payload && payload_size) || (!payload && !payload_size)); | |
b9a8d78f | 427 | |
64803277 | 428 | notification = zmalloc<lttng_event_notifier_notification>(); |
b9a8d78f | 429 | if (notification == NULL) { |
bd0514a5 | 430 | ERR("Error allocating notification"); |
b9a8d78f FD |
431 | goto end; |
432 | } | |
433 | ||
434 | notification->tracer_token = tracer_token; | |
435 | notification->type = domain; | |
82b3cbf4 JR |
436 | notification->capture_buffer = payload; |
437 | notification->capture_buf_size = payload_size; | |
b9a8d78f FD |
438 | |
439 | end: | |
440 | return notification; | |
441 | } | |
442 | ||
b9a8d78f FD |
443 | void lttng_event_notifier_notification_destroy( |
444 | struct lttng_event_notifier_notification *notification) | |
445 | { | |
446 | if (!notification) { | |
447 | return; | |
448 | } | |
449 | ||
82b3cbf4 | 450 | free(notification->capture_buffer); |
b9a8d78f FD |
451 | free(notification); |
452 | } |