SoW-2019-0002: Dynamic Snapshot
[lttng-tools.git] / tests / regression / tools / notification / base_client.c
1 /*
2 * base_client.c
3 *
4 * Base client application for testing of LTTng notification API
5 *
6 * Copyright 2017 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
7 *
8 * SPDX-License-Identifier: MIT
9 *
10 */
11
12 #include <stdio.h>
13 #include <stdbool.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <inttypes.h>
17 #include <assert.h>
18
19 #include <lttng/action/action.h>
20 #include <lttng/action/notify.h>
21 #include <lttng/condition/buffer-usage.h>
22 #include <lttng/condition/condition.h>
23 #include <lttng/condition/evaluation.h>
24 #include <lttng/domain.h>
25 #include <lttng/endpoint.h>
26 #include <lttng/notification/channel.h>
27 #include <lttng/notification/notification.h>
28 #include <lttng/trigger/trigger.h>
29 #include <lttng/lttng-error.h>
30
31 static unsigned int nr_notifications = 0;
32 static unsigned int nr_expected_notifications = 0;
33 static const char *session_name = NULL;
34 static const char *channel_name = NULL;
35 static double threshold_ratio = 0.0;
36 static uint64_t threshold_bytes = 0;
37 static bool is_threshold_ratio = false;
38 static enum lttng_condition_type buffer_usage_type = LTTNG_CONDITION_TYPE_UNKNOWN;
39 static enum lttng_domain_type domain_type = LTTNG_DOMAIN_NONE;
40
41 int handle_condition(
42 const struct lttng_condition *condition,
43 const struct lttng_evaluation *condition_evaluation);
44
45 static int parse_arguments(char **argv)
46 {
47 const char *domain_type_string = NULL;
48 const char *buffer_usage_type_string = NULL;
49 const char *buffer_usage_threshold_type = NULL;
50 const char *buffer_usage_threshold_value = NULL;
51 const char *nr_expected_notifications_string = NULL;
52
53 session_name = argv[1];
54 channel_name = argv[2];
55 domain_type_string = argv[3];
56 buffer_usage_type_string = argv[4];
57 buffer_usage_threshold_type = argv[5];
58 buffer_usage_threshold_value = argv[6];
59 nr_expected_notifications_string = argv[7];
60
61 /* Parse arguments */
62 /* Domain type */
63 if (!strcasecmp("LTTNG_DOMAIN_UST", domain_type_string)) {
64 domain_type = LTTNG_DOMAIN_UST;
65 }
66 if (!strcasecmp("LTTNG_DOMAIN_KERNEL", domain_type_string)) {
67 domain_type = LTTNG_DOMAIN_KERNEL;
68 }
69 if (domain_type == LTTNG_DOMAIN_NONE) {
70 printf("error: Unknown domain type\n");
71 goto error;
72 }
73
74 /* Buffer usage condition type */
75 if (!strcasecmp("low", buffer_usage_type_string)) {
76 buffer_usage_type = LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW;
77 }
78 if (!strcasecmp("high", buffer_usage_type_string)) {
79 buffer_usage_type = LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH;
80 }
81 if (buffer_usage_type == LTTNG_CONDITION_TYPE_UNKNOWN) {
82 printf("error: Unknown condition type\n");
83 goto error;
84 }
85
86 /* Ratio or bytes ? */
87 if (!strcasecmp("bytes", buffer_usage_threshold_type)) {
88 is_threshold_ratio = false;
89 sscanf(buffer_usage_threshold_value, "%" SCNu64, &threshold_bytes);
90 }
91
92 if (!strcasecmp("ratio", buffer_usage_threshold_type)) {
93 is_threshold_ratio = true;
94 sscanf(buffer_usage_threshold_value, "%lf", &threshold_ratio);
95 }
96
97 /* Number of notification to expect */
98 sscanf(nr_expected_notifications_string, "%d", &nr_expected_notifications);
99
100 return 0;
101 error:
102 return 1;
103 }
104
105 int main(int argc, char **argv)
106 {
107 int ret = 0;
108 enum lttng_condition_status condition_status;
109 enum lttng_notification_channel_status nc_status;
110 struct lttng_notification_channel *notification_channel = NULL;
111 struct lttng_condition *condition = NULL;
112 struct lttng_action *action = NULL;
113 struct lttng_trigger *trigger = NULL;
114
115 /*
116 * Disable buffering on stdout.
117 * Safety measure to prevent hang on the validation side since
118 * stdout is used for outside synchronization.
119 */
120 setbuf(stdout, NULL);
121
122 if (argc < 8) {
123 printf("error: Missing arguments for tests\n");
124 ret = 1;
125 goto end;
126 }
127
128 ret = parse_arguments(argv);
129 if (ret) {
130 printf("error: Could not parse arguments\n");
131 goto end;
132 }
133
134 /* Setup */
135 notification_channel = lttng_notification_channel_create(
136 lttng_session_daemon_notification_endpoint);
137 if (!notification_channel) {
138 printf("error: Could not create notification channel\n");
139 ret = 1;
140 goto end;
141 }
142
143 switch (buffer_usage_type) {
144 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
145 condition = lttng_condition_buffer_usage_low_create();
146 break;
147 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
148 condition = lttng_condition_buffer_usage_high_create();
149 break;
150 default:
151 printf("error: Invalid buffer_usage_type\n");
152 ret = 1;
153 goto end;
154 }
155
156 if (!condition) {
157 printf("error: Could not create condition object\n");
158 ret = 1;
159 goto end;
160 }
161
162 if (is_threshold_ratio) {
163 condition_status = lttng_condition_buffer_usage_set_threshold_ratio(
164 condition, threshold_ratio);
165 } else {
166 condition_status = lttng_condition_buffer_usage_set_threshold(
167 condition, threshold_bytes);
168 }
169
170 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
171 printf("error: Could not set threshold\n");
172 ret = 1;
173 goto end;
174 }
175
176 condition_status = lttng_condition_buffer_usage_set_session_name(
177 condition, session_name);
178 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
179 printf("error: Could not set session name\n");
180 ret = 1;
181 goto end;
182 }
183 condition_status = lttng_condition_buffer_usage_set_channel_name(
184 condition, channel_name);
185 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
186 printf("error: Could not set channel name\n");
187 ret = 1;
188 goto end;
189 }
190 condition_status = lttng_condition_buffer_usage_set_domain_type(
191 condition, domain_type);
192 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
193 printf("error: Could not set domain type\n");
194 ret = 1;
195 goto end;
196 }
197
198 action = lttng_action_notify_create();
199 if (!action) {
200 printf("error: Could not create action notify\n");
201 ret = 1;
202 goto end;
203 }
204
205 trigger = lttng_trigger_create(condition, action);
206 if (!trigger) {
207 printf("error: Could not create trigger\n");
208 ret = 1;
209 goto end;
210 }
211
212 ret = lttng_register_trigger(trigger);
213
214 /*
215 * An equivalent trigger might already be registered if an other app
216 * registered an equivalent trigger.
217 */
218 if (ret < 0 && ret != -LTTNG_ERR_TRIGGER_EXISTS) {
219 printf("error: %s\n", lttng_strerror(ret));
220 ret = 1;
221 goto end;
222 }
223
224 nc_status = lttng_notification_channel_subscribe(notification_channel, condition);
225 if (nc_status != LTTNG_NOTIFICATION_CHANNEL_STATUS_OK) {
226 printf("error: Could not subscribe\n");
227 ret = 1;
228 goto end;
229 }
230
231 /* Tell outside process that the client is ready */
232 printf("sync: ready\n");
233
234 for (;;) {
235 struct lttng_notification *notification;
236 enum lttng_notification_channel_status status;
237 const struct lttng_evaluation *notification_evaluation;
238 const struct lttng_condition *notification_condition;
239
240 if (nr_notifications == nr_expected_notifications) {
241 ret = 0;
242 goto end;
243 }
244 /* Receive the next notification. */
245 status = lttng_notification_channel_get_next_notification(
246 notification_channel,
247 &notification);
248
249 switch (status) {
250 case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK:
251 break;
252 case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED:
253 ret = 1;
254 printf("error: No drop should be observed during this test app\n");
255 goto end;
256 case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED:
257 /*
258 * The notification channel has been closed by the
259 * session daemon. This is typically caused by a session
260 * daemon shutting down (cleanly or because of a crash).
261 */
262 printf("error: Notification channel was closed\n");
263 ret = 1;
264 goto end;
265 default:
266 /* Unhandled conditions / errors. */
267 printf("error: Unknown notification channel status\n");
268 ret = 1;
269 goto end;
270 }
271
272 notification_condition = lttng_notification_get_condition(notification);
273 notification_evaluation = lttng_notification_get_evaluation(notification);
274
275 ret = handle_condition(notification_condition, notification_evaluation);
276 nr_notifications++;
277
278 lttng_notification_destroy(notification);
279 if (ret != 0) {
280 goto end;
281 }
282 }
283 end:
284 if (trigger) {
285 lttng_unregister_trigger(trigger);
286 }
287 if (lttng_notification_channel_unsubscribe(notification_channel, condition)) {
288 printf("error: channel unsubscribe error\n");
289 }
290 lttng_trigger_destroy(trigger);
291 lttng_condition_destroy(condition);
292 lttng_action_destroy(action);
293 lttng_notification_channel_destroy(notification_channel);
294 printf("exit: %d\n", ret);
295 return ret;
296 }
297
298 int handle_condition(
299 const struct lttng_condition *condition,
300 const struct lttng_evaluation *evaluation)
301 {
302 int ret = 0;
303 const char *string_low = "low";
304 const char *string_high = "high";
305 const char *string_condition_type = NULL;
306 const char *condition_session_name = NULL;
307 const char *condition_channel_name = NULL;
308 enum lttng_condition_type condition_type;
309 enum lttng_domain_type condition_domain_type;
310 double buffer_usage_ratio;
311 uint64_t buffer_usage_bytes;
312
313 condition_type = lttng_condition_get_type(condition);
314
315 if (condition_type != buffer_usage_type) {
316 ret = 1;
317 printf("error: condition type and buffer usage type are not the same\n");
318 goto end;
319 }
320
321 /* Fetch info to test */
322 ret = lttng_condition_buffer_usage_get_session_name(condition,
323 &condition_session_name);
324 if (ret) {
325 printf("error: session name could not be fetched\n");
326 ret = 1;
327 goto end;
328 }
329 ret = lttng_condition_buffer_usage_get_channel_name(condition,
330 &condition_channel_name);
331 if (ret) {
332 printf("error: channel name could not be fetched\n");
333 ret = 1;
334 goto end;
335 }
336 ret = lttng_condition_buffer_usage_get_domain_type(condition,
337 &condition_domain_type);
338 if (ret) {
339 printf("error: domain type could not be fetched\n");
340 ret = 1;
341 goto end;
342 }
343
344 if (strcmp(condition_session_name, session_name) != 0) {
345 printf("error: session name differs\n");
346 ret = 1;
347 goto end;
348 }
349
350 if (strcmp(condition_channel_name, channel_name) != 0) {
351 printf("error: channel name differs\n");
352 ret = 1;
353 goto end;
354 }
355
356 if (condition_domain_type != domain_type) {
357 printf("error: domain type differs\n");
358 ret = 1;
359 goto end;
360 }
361
362 if (is_threshold_ratio) {
363 lttng_evaluation_buffer_usage_get_usage_ratio(
364 evaluation, &buffer_usage_ratio);
365 switch (condition_type) {
366 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
367 if (buffer_usage_ratio > threshold_ratio) {
368 printf("error: buffer usage ratio is bigger than set threshold ratio\n");
369 ret = 1;
370 goto end;
371 }
372 break;
373 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
374 if (buffer_usage_ratio < threshold_ratio) {
375 printf("error: buffer usage ratio is lower than set threshold ratio\n");
376 ret = 1;
377 goto end;
378 }
379 break;
380 default:
381 printf("error: Unknown condition type\n");
382 ret = 1;
383 goto end;
384 }
385 } else {
386 lttng_evaluation_buffer_usage_get_usage(
387 evaluation, &buffer_usage_bytes);
388 switch (condition_type) {
389 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
390 if (buffer_usage_bytes > threshold_bytes) {
391 printf("error: buffer usage ratio is bigger than set threshold bytes\n");
392 ret = 1;
393 goto end;
394 }
395 break;
396 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
397 if (buffer_usage_bytes < threshold_bytes) {
398 printf("error: buffer usage ratio is lower than set threshold bytes\n");
399 ret = 1;
400 goto end;
401 }
402 break;
403 default:
404 printf("error: Unknown condition type\n");
405 ret = 1;
406 goto end;
407 }
408 }
409
410 switch (condition_type) {
411 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
412 string_condition_type = string_low;
413 break;
414 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
415 string_condition_type = string_high;
416 break;
417 default:
418 printf("error: Unknown condition type\n");
419 ret = 1;
420 goto end;
421 }
422
423 printf("notification: %s %d\n", string_condition_type, nr_notifications);
424 end:
425 return ret;
426 }
This page took 0.038321 seconds and 5 git commands to generate.