Commit | Line | Data |
---|---|---|
e5540b2a MD |
1 | // SPDX-License-Identifier: MIT |
2 | /* | |
3 | * Copyright 2022 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
4 | */ | |
5 | ||
6 | #include <stdint.h> | |
7 | #include <inttypes.h> | |
8 | #include <stdlib.h> | |
9 | #include <stdio.h> | |
10 | ||
11 | /* SIDE stands for "Static Instrumentation Dynamically Enabled" */ | |
12 | ||
13 | /* Helper macros */ | |
14 | ||
15 | #define SIDE_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | |
16 | ||
17 | /* | |
18 | * Compound literals with static storage are needed by SIDE | |
19 | * instrumentation. | |
20 | * Compound literals are part of the C99 and C11 standards, but not | |
21 | * part of the C++ standards. They are supported by most C++ compilers | |
22 | * though. | |
23 | * | |
24 | * Example use: | |
25 | * static struct mystruct *var = LTTNG_UST_COMPOUND_LITERAL(struct mystruct, { 1, 2, 3 }); | |
26 | */ | |
27 | #define SIDE_COMPOUND_LITERAL(type, ...) (type[]) { __VA_ARGS__ } | |
28 | ||
29 | #define side_likely(x) __builtin_expect(!!(x), 1) | |
30 | #define side_unlikely(x) __builtin_expect(!!(x), 0) | |
31 | ||
32 | struct side_arg_vec; | |
33 | struct side_type_description; | |
34 | struct side_event_field; | |
35 | ||
36 | enum side_type { | |
37 | SIDE_TYPE_U8, | |
38 | SIDE_TYPE_U16, | |
39 | SIDE_TYPE_U32, | |
40 | SIDE_TYPE_U64, | |
41 | SIDE_TYPE_S8, | |
42 | SIDE_TYPE_S16, | |
43 | SIDE_TYPE_S32, | |
44 | SIDE_TYPE_S64, | |
45 | SIDE_TYPE_STRING, | |
46 | SIDE_TYPE_DYNAMIC, | |
47 | SIDE_TYPE_STRUCT, | |
48 | SIDE_TYPE_ARRAY, | |
49 | SIDE_TYPE_VLA, | |
50 | SIDE_TYPE_VLA_VISITOR, | |
51 | //TODO: | |
52 | //specialized array and vla for fixed-size integers (optimization) | |
53 | //variants (discriminated unions) | |
54 | }; | |
55 | ||
56 | enum side_loglevel { | |
57 | SIDE_LOGLEVEL_EMERG = 0, | |
58 | SIDE_LOGLEVEL_ALERT = 1, | |
59 | SIDE_LOGLEVEL_CRIT = 2, | |
60 | SIDE_LOGLEVEL_ERR = 3, | |
61 | SIDE_LOGLEVEL_WARNING = 4, | |
62 | SIDE_LOGLEVEL_NOTICE = 5, | |
63 | SIDE_LOGLEVEL_INFO = 6, | |
64 | SIDE_LOGLEVEL_DEBUG = 7, | |
65 | }; | |
66 | ||
67 | enum side_visitor_status { | |
68 | SIDE_VISITOR_STATUS_ERROR = -1, | |
69 | SIDE_VISITOR_STATUS_OK = 0, | |
70 | SIDE_VISITOR_STATUS_END = 1, | |
71 | }; | |
72 | ||
73 | typedef enum side_visitor_status (*side_visitor_begin)(void *ctx); | |
74 | typedef enum side_visitor_status (*side_visitor_end)(void *ctx); | |
75 | typedef enum side_visitor_status (*side_visitor_get_next)(void *ctx, struct side_arg_vec *sav_elem); | |
76 | ||
77 | struct side_type_description { | |
78 | enum side_type type; | |
79 | union { | |
80 | struct { | |
81 | uint32_t nr_fields; | |
82 | const struct side_event_field *fields; | |
83 | } side_struct; | |
84 | struct { | |
85 | uint32_t length; | |
86 | const struct side_type_description *elem_type; | |
87 | } side_array; | |
88 | struct { | |
89 | const struct side_type_description *elem_type; | |
90 | } side_vla; | |
91 | struct { | |
92 | const struct side_type_description *elem_type; | |
93 | side_visitor_begin begin; | |
94 | side_visitor_end end; | |
95 | side_visitor_get_next get_next; | |
96 | } side_vla_visitor; | |
97 | } u; | |
98 | }; | |
99 | ||
100 | struct side_event_field { | |
101 | const char *field_name; | |
102 | struct side_type_description side_type; | |
103 | }; | |
104 | ||
105 | struct side_event_description { | |
106 | uint32_t version; | |
107 | uint32_t enabled; | |
108 | uint32_t loglevel; /* enum side_loglevel */ | |
109 | uint32_t nr_fields; | |
110 | const char *provider_name; | |
111 | const char *event_name; | |
112 | const struct side_event_field *fields; | |
113 | }; | |
114 | ||
115 | struct side_arg_vec { | |
116 | uint32_t type; /* enum side_type */ | |
117 | union { | |
118 | uint8_t side_u8; | |
119 | uint16_t side_u16; | |
120 | uint32_t side_u32; | |
121 | uint64_t side_u64; | |
122 | int8_t side_s8; | |
123 | int16_t side_s16; | |
124 | int32_t side_s32; | |
125 | int64_t side_s64; | |
126 | const char *string; | |
127 | const struct side_arg_vec_description *side_struct; | |
128 | const struct side_arg_vec_description *side_array; | |
129 | const struct side_arg_vec_description *side_vla; | |
130 | void *side_vla_visitor_ctx; | |
131 | } u; | |
132 | }; | |
133 | ||
134 | struct side_arg_vec_description { | |
135 | const struct side_arg_vec *sav; | |
136 | uint32_t len; | |
137 | }; | |
138 | ||
139 | /* Tracer example */ | |
140 | ||
141 | static | |
142 | void tracer_print_struct(const struct side_type_description *type_desc, const struct side_arg_vec_description *sav_desc); | |
143 | static | |
144 | void tracer_print_array(const struct side_type_description *type_desc, const struct side_arg_vec_description *sav_desc); | |
145 | static | |
146 | void tracer_print_vla(const struct side_type_description *type_desc, const struct side_arg_vec_description *sav_desc); | |
147 | static | |
148 | void tracer_print_vla_visitor(const struct side_type_description *type_desc, void *ctx); | |
149 | ||
150 | static | |
151 | void tracer_print_type(const struct side_type_description *type_desc, const struct side_arg_vec *item) | |
152 | { | |
153 | if (type_desc->type != SIDE_TYPE_DYNAMIC && type_desc->type != item->type) { | |
154 | printf("ERROR: type mismatch between description and arguments\n"); | |
155 | abort(); | |
156 | } | |
157 | ||
158 | switch (item->type) { | |
159 | case SIDE_TYPE_U8: | |
160 | printf("%" PRIu8, item->u.side_u8); | |
161 | break; | |
162 | case SIDE_TYPE_U16: | |
163 | printf("%" PRIu16, item->u.side_u16); | |
164 | break; | |
165 | case SIDE_TYPE_U32: | |
166 | printf("%" PRIu32, item->u.side_u32); | |
167 | break; | |
168 | case SIDE_TYPE_U64: | |
169 | printf("%" PRIu64, item->u.side_u64); | |
170 | break; | |
171 | case SIDE_TYPE_S8: | |
172 | printf("%" PRId8, item->u.side_s8); | |
173 | break; | |
174 | case SIDE_TYPE_S16: | |
175 | printf("%" PRId16, item->u.side_s16); | |
176 | break; | |
177 | case SIDE_TYPE_S32: | |
178 | printf("%" PRId32, item->u.side_s32); | |
179 | break; | |
180 | case SIDE_TYPE_S64: | |
181 | printf("%" PRId64, item->u.side_s64); | |
182 | break; | |
183 | case SIDE_TYPE_STRING: | |
184 | printf("%s", item->u.string); | |
185 | break; | |
186 | case SIDE_TYPE_STRUCT: | |
187 | tracer_print_struct(type_desc, item->u.side_struct); | |
188 | break; | |
189 | case SIDE_TYPE_ARRAY: | |
190 | tracer_print_array(type_desc, item->u.side_array); | |
191 | break; | |
192 | case SIDE_TYPE_VLA: | |
193 | tracer_print_vla(type_desc, item->u.side_vla); | |
194 | break; | |
195 | case SIDE_TYPE_VLA_VISITOR: | |
196 | tracer_print_vla_visitor(type_desc, item->u.side_vla_visitor_ctx); | |
197 | break; | |
198 | default: | |
199 | printf("<UNKNOWN TYPE>"); | |
200 | abort(); | |
201 | } | |
202 | } | |
203 | ||
204 | static | |
205 | void tracer_print_field(const struct side_event_field *item_desc, const struct side_arg_vec *item) | |
206 | { | |
207 | printf("(\"%s\", ", item_desc->field_name); | |
208 | tracer_print_type(&item_desc->side_type, item); | |
209 | printf(")"); | |
210 | } | |
211 | ||
212 | static | |
213 | void tracer_print_struct(const struct side_type_description *type_desc, const struct side_arg_vec_description *sav_desc) | |
214 | { | |
215 | const struct side_arg_vec *sav = sav_desc->sav; | |
216 | uint32_t side_sav_len = sav_desc->len; | |
217 | int i; | |
218 | ||
219 | if (type_desc->u.side_struct.nr_fields != side_sav_len) { | |
220 | printf("ERROR: number of fields mismatch between description and arguments of structure\n"); | |
221 | abort(); | |
222 | } | |
223 | printf("{ "); | |
224 | for (i = 0; i < side_sav_len; i++) { | |
225 | printf("%s", i ? ", " : ""); | |
226 | tracer_print_field(&type_desc->u.side_struct.fields[i], &sav[i]); | |
227 | } | |
228 | printf(" }"); | |
229 | } | |
230 | ||
231 | static | |
232 | void tracer_print_array(const struct side_type_description *type_desc, const struct side_arg_vec_description *sav_desc) | |
233 | { | |
234 | const struct side_arg_vec *sav = sav_desc->sav; | |
235 | uint32_t side_sav_len = sav_desc->len; | |
236 | int i; | |
237 | ||
238 | if (type_desc->u.side_array.length != side_sav_len) { | |
239 | printf("ERROR: length mismatch between description and arguments of array\n"); | |
240 | abort(); | |
241 | } | |
242 | printf("[ "); | |
243 | for (i = 0; i < side_sav_len; i++) { | |
244 | printf("%s", i ? ", " : ""); | |
245 | tracer_print_type(type_desc->u.side_array.elem_type, &sav[i]); | |
246 | } | |
247 | printf(" ]"); | |
248 | } | |
249 | ||
250 | static | |
251 | void tracer_print_vla(const struct side_type_description *type_desc, const struct side_arg_vec_description *sav_desc) | |
252 | { | |
253 | const struct side_arg_vec *sav = sav_desc->sav; | |
254 | uint32_t side_sav_len = sav_desc->len; | |
255 | int i; | |
256 | ||
257 | printf("[ "); | |
258 | for (i = 0; i < side_sav_len; i++) { | |
259 | printf("%s", i ? ", " : ""); | |
260 | tracer_print_type(type_desc->u.side_vla.elem_type, &sav[i]); | |
261 | } | |
262 | printf(" ]"); | |
263 | } | |
264 | ||
265 | static | |
266 | void tracer_print_vla_visitor(const struct side_type_description *type_desc, void *ctx) | |
267 | { | |
268 | enum side_visitor_status status; | |
269 | int i; | |
270 | ||
271 | status = type_desc->u.side_vla_visitor.begin(ctx); | |
272 | if (status != SIDE_VISITOR_STATUS_OK) { | |
273 | printf("ERROR: Visitor error\n"); | |
274 | abort(); | |
275 | } | |
276 | ||
277 | printf("[ "); | |
278 | status = SIDE_VISITOR_STATUS_OK; | |
279 | for (i = 0; status == SIDE_VISITOR_STATUS_OK; i++) { | |
280 | struct side_arg_vec sav_elem; | |
281 | ||
282 | status = type_desc->u.side_vla_visitor.get_next(ctx, &sav_elem); | |
283 | switch (status) { | |
284 | case SIDE_VISITOR_STATUS_OK: | |
285 | break; | |
286 | case SIDE_VISITOR_STATUS_ERROR: | |
287 | printf("ERROR: Visitor error\n"); | |
288 | abort(); | |
289 | case SIDE_VISITOR_STATUS_END: | |
290 | continue; | |
291 | } | |
292 | printf("%s", i ? ", " : ""); | |
293 | tracer_print_type(type_desc->u.side_vla_visitor.elem_type, &sav_elem); | |
294 | } | |
295 | printf(" ]"); | |
296 | if (type_desc->u.side_vla_visitor.end) { | |
297 | status = type_desc->u.side_vla_visitor.end(ctx); | |
298 | if (status != SIDE_VISITOR_STATUS_OK) { | |
299 | printf("ERROR: Visitor error\n"); | |
300 | abort(); | |
301 | } | |
302 | } | |
303 | } | |
304 | ||
305 | __attribute__((noinline)) | |
306 | void tracer_call(const struct side_event_description *desc, const struct side_arg_vec_description *sav_desc) | |
307 | { | |
308 | const struct side_arg_vec *sav = sav_desc->sav; | |
309 | uint32_t side_sav_len = sav_desc->len; | |
310 | int i; | |
311 | ||
312 | printf("provider: %s, event: %s, ", desc->provider_name, desc->event_name); | |
313 | if (desc->nr_fields != side_sav_len) { | |
314 | printf("ERROR: number of fields mismatch between description and arguments\n"); | |
315 | abort(); | |
316 | } | |
317 | for (i = 0; i < side_sav_len; i++) { | |
318 | printf("%s", i ? ", " : ""); | |
319 | tracer_print_field(&desc->fields[i], &sav[i]); | |
320 | } | |
321 | printf("\n"); | |
322 | } | |
323 | ||
324 | #define SIDE_PARAM(...) __VA_ARGS__ | |
325 | ||
326 | #define side_type_decl(_type) { .type = _type } | |
327 | #define side_field(_type, _name) { .field_name = _name, .side_type = side_type_decl(_type) } | |
328 | ||
329 | #define side_type_struct_decl(_fields) \ | |
330 | { \ | |
331 | .type = SIDE_TYPE_STRUCT, \ | |
332 | .u = { \ | |
333 | .side_struct = { \ | |
334 | .nr_fields = SIDE_ARRAY_SIZE(SIDE_PARAM(_fields)), \ | |
335 | .fields = _fields, \ | |
336 | }, \ | |
337 | }, \ | |
338 | } | |
339 | #define side_field_struct(_name, _fields) \ | |
340 | { \ | |
341 | .field_name = _name, \ | |
342 | .side_type = side_type_struct_decl(SIDE_PARAM(_fields)), \ | |
343 | } | |
344 | ||
345 | #define side_type_array_decl(_elem_type, _length) \ | |
346 | { \ | |
347 | .type = SIDE_TYPE_ARRAY, \ | |
348 | .u = { \ | |
349 | .side_array = { \ | |
350 | .length = _length, \ | |
351 | .elem_type = _elem_type, \ | |
352 | }, \ | |
353 | }, \ | |
354 | } | |
355 | #define side_field_array(_name, _elem_type, _length) \ | |
356 | { \ | |
357 | .field_name = _name, \ | |
358 | .side_type = side_type_array_decl(_elem_type, _length), \ | |
359 | } | |
360 | ||
361 | #define side_type_vla_decl(_elem_type) \ | |
362 | { \ | |
363 | .type = SIDE_TYPE_VLA, \ | |
364 | .u = { \ | |
365 | .side_vla = { \ | |
366 | .elem_type = _elem_type, \ | |
367 | }, \ | |
368 | }, \ | |
369 | } | |
370 | #define side_field_vla(_name, _elem_type) \ | |
371 | { \ | |
372 | .field_name = _name, \ | |
373 | .side_type = side_type_vla_decl(_elem_type), \ | |
374 | } | |
375 | ||
376 | #define side_type_vla_visitor_decl(_elem_type, _begin, _end, _get_next) \ | |
377 | { \ | |
378 | .type = SIDE_TYPE_VLA_VISITOR, \ | |
379 | .u = { \ | |
380 | .side_vla_visitor = { \ | |
381 | .elem_type = _elem_type, \ | |
382 | .begin = _begin, \ | |
383 | .end = _end, \ | |
384 | .get_next = _get_next, \ | |
385 | }, \ | |
386 | }, \ | |
387 | } | |
388 | #define side_field_vla_visitor(_name, _elem_type, _begin, _end, _get_next) \ | |
389 | { \ | |
390 | .field_name = _name, \ | |
391 | .side_type = side_type_vla_visitor_decl(_elem_type, _begin, _end, _get_next), \ | |
392 | } | |
393 | ||
394 | #define side_vla_elem(...) \ | |
395 | SIDE_COMPOUND_LITERAL(const struct side_type_description, side_type_decl(__VA_ARGS__)) | |
396 | ||
397 | #define side_vla_visitor_elem(...) \ | |
398 | SIDE_COMPOUND_LITERAL(const struct side_type_description, side_type_decl(__VA_ARGS__)) | |
399 | ||
400 | #define side_array_elem(...) \ | |
401 | SIDE_COMPOUND_LITERAL(const struct side_type_description, side_type_decl(__VA_ARGS__)) | |
402 | ||
403 | #define side_field_list(...) \ | |
404 | SIDE_COMPOUND_LITERAL(const struct side_event_field, __VA_ARGS__) | |
405 | ||
406 | #define side_arg_u8(val) { .type = SIDE_TYPE_U8, .u = { .side_u8 = (val) } } | |
407 | #define side_arg_u16(val) { .type = SIDE_TYPE_U16, .u = { .side_u16 = (val) } } | |
408 | #define side_arg_u32(val) { .type = SIDE_TYPE_U32, .u = { .side_u32 = (val) } } | |
409 | #define side_arg_u64(val) { .type = SIDE_TYPE_U64, .u = { .side_u64 = (val) } } | |
410 | #define side_arg_s8(val) { .type = SIDE_TYPE_S8, .u = { .side_s8 = (val) } } | |
411 | #define side_arg_s16(val) { .type = SIDE_TYPE_S16, .u = { .side_s16 = (val) } } | |
412 | #define side_arg_s32(val) { .type = SIDE_TYPE_S32, .u = { .side_s32 = (val) } } | |
413 | #define side_arg_s64(val) { .type = SIDE_TYPE_S64, .u = { .side_s64 = (val) } } | |
414 | #define side_arg_string(val) { .type = SIDE_TYPE_STRING, .u = { .string = (val) } } | |
415 | #define side_arg_struct(_side_type) { .type = SIDE_TYPE_STRUCT, .u = { .side_struct = (_side_type) } } | |
416 | #define side_arg_array(_side_type) { .type = SIDE_TYPE_ARRAY, .u = { .side_array = (_side_type) } } | |
417 | #define side_arg_vla(_side_type) { .type = SIDE_TYPE_VLA, .u = { .side_vla = (_side_type) } } | |
418 | #define side_arg_vla_visitor(_ctx) { .type = SIDE_TYPE_VLA_VISITOR, .u = { .side_vla_visitor_ctx = (_ctx) } } | |
419 | ||
420 | #define side_arg_define_vec(_identifier, _sav) \ | |
421 | const struct side_arg_vec _identifier##_vec[] = { _sav }; \ | |
422 | const struct side_arg_vec_description _identifier = { \ | |
423 | .sav = _identifier##_vec, \ | |
424 | .len = SIDE_ARRAY_SIZE(_identifier##_vec), \ | |
425 | } | |
426 | ||
427 | #define side_arg_list(...) __VA_ARGS__ | |
428 | ||
429 | #define side_event_cond(desc) if (side_unlikely((desc)->enabled)) | |
430 | #define side_event_call(desc, _sav) \ | |
431 | { \ | |
432 | const struct side_arg_vec side_sav[] = { _sav }; \ | |
433 | const struct side_arg_vec_description sav_desc = { \ | |
434 | .sav = side_sav, \ | |
435 | .len = SIDE_ARRAY_SIZE(side_sav), \ | |
436 | }; \ | |
437 | tracer_call(desc, &sav_desc); \ | |
438 | } | |
439 | ||
440 | #define side_event(desc, sav) \ | |
441 | side_event_cond(desc) \ | |
442 | side_event_call(desc, SIDE_PARAM(sav)); \ | |
443 | ||
444 | #define side_define_event(_identifier, _provider, _event, _loglevel, _fields) \ | |
445 | struct side_event_description _identifier = { \ | |
446 | .version = 0, \ | |
447 | .enabled = 0, \ | |
448 | .loglevel = _loglevel, \ | |
449 | .nr_fields = SIDE_ARRAY_SIZE(SIDE_PARAM(_fields)), \ | |
450 | .provider_name = _provider, \ | |
451 | .event_name = _event, \ | |
452 | .fields = _fields, \ | |
453 | } | |
454 | ||
455 | #define side_declare_event(_identifier) \ | |
456 | struct side_event_description _identifier | |
457 | ||
458 | /* User code example */ | |
459 | ||
460 | static side_define_event(my_provider_event, "myprovider", "myevent", SIDE_LOGLEVEL_DEBUG, | |
461 | side_field_list( | |
462 | side_field(SIDE_TYPE_U32, "abc"), | |
463 | side_field(SIDE_TYPE_S64, "def"), | |
464 | side_field(SIDE_TYPE_DYNAMIC, "dynamic"), | |
465 | ) | |
466 | ); | |
467 | ||
468 | static | |
469 | void test_fields(void) | |
470 | { | |
471 | uint32_t uw = 42; | |
472 | int64_t sdw = -500; | |
473 | ||
474 | my_provider_event.enabled = 1; | |
475 | side_event(&my_provider_event, side_arg_list(side_arg_u32(uw), side_arg_s64(sdw), side_arg_string("zzz"))); | |
476 | } | |
477 | ||
478 | static side_define_event(my_provider_event2, "myprovider", "myevent2", SIDE_LOGLEVEL_DEBUG, | |
479 | side_field_list( | |
480 | side_field_struct("structfield", | |
481 | side_field_list( | |
482 | side_field(SIDE_TYPE_U32, "x"), | |
483 | side_field(SIDE_TYPE_S64, "y"), | |
484 | ) | |
485 | ), | |
486 | side_field(SIDE_TYPE_U8, "z"), | |
487 | ) | |
488 | ); | |
489 | ||
490 | static | |
491 | void test_struct(void) | |
492 | { | |
493 | my_provider_event2.enabled = 1; | |
494 | side_event_cond(&my_provider_event2) { | |
495 | side_arg_define_vec(mystruct, side_arg_list(side_arg_u32(21), side_arg_s64(22))); | |
496 | side_event_call(&my_provider_event2, side_arg_list(side_arg_struct(&mystruct), side_arg_u8(55))); | |
497 | } | |
498 | } | |
499 | ||
500 | static side_define_event(my_provider_event_array, "myprovider", "myarray", SIDE_LOGLEVEL_DEBUG, | |
501 | side_field_list( | |
502 | side_field_array("arr", side_array_elem(SIDE_TYPE_U32), 3), | |
503 | side_field(SIDE_TYPE_S64, "v"), | |
504 | ) | |
505 | ); | |
506 | ||
507 | static | |
508 | void test_array(void) | |
509 | { | |
510 | my_provider_event_array.enabled = 1; | |
511 | side_event_cond(&my_provider_event_array) { | |
512 | side_arg_define_vec(myarray, side_arg_list(side_arg_u32(1), side_arg_u32(2), side_arg_u32(3))); | |
513 | side_event_call(&my_provider_event_array, side_arg_list(side_arg_array(&myarray), side_arg_s64(42))); | |
514 | } | |
515 | } | |
516 | ||
517 | static side_define_event(my_provider_event_vla, "myprovider", "myvla", SIDE_LOGLEVEL_DEBUG, | |
518 | side_field_list( | |
519 | side_field_vla("vla", side_vla_elem(SIDE_TYPE_U32)), | |
520 | side_field(SIDE_TYPE_S64, "v"), | |
521 | ) | |
522 | ); | |
523 | ||
524 | static | |
525 | void test_vla(void) | |
526 | { | |
527 | my_provider_event_vla.enabled = 1; | |
528 | side_event_cond(&my_provider_event_vla) { | |
529 | side_arg_define_vec(myvla, side_arg_list(side_arg_u32(1), side_arg_u32(2), side_arg_u32(3))); | |
530 | side_event_call(&my_provider_event_vla, side_arg_list(side_arg_vla(&myvla), side_arg_s64(42))); | |
531 | } | |
532 | } | |
533 | ||
534 | struct app_visitor_ctx { | |
535 | const uint32_t *ptr; | |
536 | int init_pos; | |
537 | int current_pos; | |
538 | int end_pos; | |
539 | }; | |
540 | ||
541 | enum side_visitor_status test_visitor_begin(void *_ctx) | |
542 | { | |
543 | struct app_visitor_ctx *ctx = (struct app_visitor_ctx *) _ctx; | |
544 | ctx->current_pos = ctx->init_pos; | |
545 | return SIDE_VISITOR_STATUS_OK; | |
546 | } | |
547 | ||
548 | enum side_visitor_status test_visitor_end(void *_ctx) | |
549 | { | |
550 | return SIDE_VISITOR_STATUS_OK; | |
551 | } | |
552 | ||
553 | enum side_visitor_status test_visitor_get_next(void *_ctx, struct side_arg_vec *sav_elem) | |
554 | { | |
555 | struct app_visitor_ctx *ctx = (struct app_visitor_ctx *) _ctx; | |
556 | ||
557 | if (ctx->current_pos >= ctx->end_pos) | |
558 | return SIDE_VISITOR_STATUS_END; | |
559 | sav_elem->type = SIDE_TYPE_U32; | |
560 | sav_elem->u.side_u32 = ctx->ptr[ctx->current_pos++]; | |
561 | return SIDE_VISITOR_STATUS_OK; | |
562 | } | |
563 | ||
564 | static uint32_t testarray[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; | |
565 | ||
566 | static side_define_event(my_provider_event_vla_visitor, "myprovider", "myvlavisit", SIDE_LOGLEVEL_DEBUG, | |
567 | side_field_list( | |
568 | side_field_vla_visitor("vlavisit", side_vla_visitor_elem(SIDE_TYPE_U32), | |
569 | test_visitor_begin, test_visitor_end, test_visitor_get_next), | |
570 | side_field(SIDE_TYPE_S64, "v"), | |
571 | ) | |
572 | ); | |
573 | ||
574 | static | |
575 | void test_vla_visitor(void) | |
576 | { | |
577 | my_provider_event_vla_visitor.enabled = 1; | |
578 | side_event_cond(&my_provider_event_vla_visitor) { | |
579 | struct app_visitor_ctx ctx = { | |
580 | .ptr = testarray, | |
581 | .init_pos = 0, | |
582 | .current_pos = 0, | |
583 | .end_pos = SIDE_ARRAY_SIZE(testarray), | |
584 | }; | |
585 | side_event_call(&my_provider_event_vla_visitor, side_arg_list(side_arg_vla_visitor(&ctx), side_arg_s64(42))); | |
586 | } | |
587 | } | |
588 | ||
589 | int main() | |
590 | { | |
591 | test_fields(); | |
592 | test_struct(); | |
593 | test_array(); | |
594 | test_vla(); | |
595 | test_vla_visitor(); | |
596 | return 0; | |
597 | } |