Fix: barectf_packet_set_buf(): keep full packet state
[barectf.git] / barectf / templates / c / barectf.c.j2
1 {#
2 # The MIT License (MIT)
3 #
4 # Copyright (c) 2020 Philippe Proulx <pproulx@efficios.com>
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining
7 # a copy of this software and associated documentation files (the
8 # "Software"), to deal in the Software without restriction, including
9 # without limitation the rights to use, copy, modify, merge, publish,
10 # distribute, sublicense, and/or sell copies of the Software, and to
11 # permit persons to whom the Software is furnished to do so, subject to
12 # the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be
15 # included in all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #}
25 {% import 'common.j2' as common %}
26 {% import 'c/common.j2' as c_common %}
27 {% import 'c/barectf.c-macros.j2' as macros %}
28 {% set prefix = common.prefix %}
29 {% set ucprefix = common.ucprefix %}
30 {% set ctx_struct_name = c_common.ctx_struct_name %}
31 {% set cg_opts = cfg.options.code_generation_options %}
32 {% set const_params = true %}
33 {% include 'license-header.j2' %}
34
35
36 #include <stdint.h>
37 #include <string.h>
38 #include <assert.h>
39
40 #include "{{ header_file_name }}"
41 #include "{{ bitfield_header_file_name }}"
42
43 #define _ALIGN(_at_var, _align) \
44 do { \
45 (_at_var) = ((_at_var) + ((_align) - 1)) & -(_align); \
46 } while (0)
47
48 #ifdef __cplusplus
49 # define _TO_VOID_PTR(_value) static_cast<void *>(_value)
50 # define _FROM_VOID_PTR(_type, _value) static_cast<_type *>(_value)
51 #else
52 # define _TO_VOID_PTR(_value) ((void *) (_value))
53 # define _FROM_VOID_PTR(_type, _value) ((_type *) (_value))
54 #endif
55
56 #define _BITS_TO_BYTES(_x) ((_x) >> 3)
57 #define _BYTES_TO_BITS(_x) ((_x) << 3)
58
59 union _f2u {
60 float f;
61 uint32_t u;
62 };
63
64 union _d2u {
65 double f;
66 uint64_t u;
67 };
68
69 uint32_t {{ prefix }}packet_size(const void * const vctx)
70 {
71 return _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx)->packet_size;
72 }
73
74 int {{ prefix }}packet_is_full(const void * const vctx)
75 {
76 const struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx);
77
78 return ctx->at == ctx->packet_size;
79 }
80
81 int {{ prefix }}packet_is_empty(const void * const vctx)
82 {
83 const struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx);
84
85 return ctx->at <= ctx->off_content;
86 }
87
88 uint32_t {{ prefix }}packet_events_discarded(const void * const vctx)
89 {
90 return _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx)->events_discarded;
91 }
92
93 uint32_t {{ prefix }}discarded_event_records_count(const void * const vctx)
94 {
95 return {{ prefix }}packet_events_discarded(vctx);
96 }
97
98 uint8_t *{{ prefix }}packet_buf(const void * const vctx)
99 {
100 return _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx)->buf;
101 }
102
103 uint8_t *{{ prefix }}packet_buf_addr(const void * const vctx)
104 {
105 return {{ prefix }}packet_buf(vctx);
106 }
107
108 uint32_t {{ prefix }}packet_buf_size(const void * const vctx)
109 {
110 const struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx);
111
112 return _BITS_TO_BYTES(ctx->packet_size);
113 }
114
115 void {{ prefix }}packet_set_buf(void * const vctx, uint8_t * const buf,
116 const uint32_t buf_size)
117 {
118 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
119
120 ctx->buf = buf;
121
122 if (ctx->at == ctx->packet_size) {
123 /* Keep full packet state */
124 ctx->at = _BYTES_TO_BITS(buf_size);
125 }
126
127 ctx->packet_size = _BYTES_TO_BITS(buf_size);
128 }
129
130 int {{ prefix }}packet_is_open(const void * const vctx)
131 {
132 return _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx)->packet_is_open;
133 }
134
135 int {{ prefix }}is_in_tracing_section(const void * const vctx)
136 {
137 return _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx)->in_tracing_section;
138 }
139
140 volatile const int *{{ prefix }}is_in_tracing_section_ptr(const void * const vctx)
141 {
142 return &_FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx)->in_tracing_section;
143 }
144
145 int {{ prefix }}is_tracing_enabled(const void * const vctx)
146 {
147 return _FROM_VOID_PTR(const struct {{ ctx_struct_name }}, vctx)->is_tracing_enabled;
148 }
149
150 void {{ prefix }}enable_tracing(void * const vctx, const int enable)
151 {
152 _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx)->is_tracing_enabled = enable;
153 }
154
155 static
156 void _write_c_str(struct {{ ctx_struct_name }} * const ctx, const char * const src)
157 {
158 const uint32_t sz = strlen(src) + 1;
159
160 memcpy(&ctx->buf[_BITS_TO_BYTES(ctx->at)], src, sz);
161 ctx->at += _BYTES_TO_BITS(sz);
162 }
163
164 static
165 int _reserve_er_space(void * const vctx, const uint32_t er_size)
166 {
167 int ret;
168 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
169
170 /* Event _cannot_ fit? */
171 if (er_size > (ctx->packet_size - ctx->off_content)) {
172 goto no_space;
173 }
174
175 /* Packet is full? */
176 if ({{ prefix }}packet_is_full(ctx)) {
177 /* Yes: is the back end full? */
178 if (ctx->cbs.is_backend_full(ctx->data)) {
179 /* Yes: discard event record */
180 goto no_space;
181 }
182
183 /* Back-end is _not_ full: open new packet */
184 ctx->use_cur_last_event_ts = 1;
185 ctx->cbs.open_packet(ctx->data);
186 ctx->use_cur_last_event_ts = 0;
187 }
188
189 /* Event fits the current packet? */
190 if (er_size > (ctx->packet_size - ctx->at)) {
191 /* No: close packet now */
192 ctx->use_cur_last_event_ts = 1;
193 ctx->cbs.close_packet(ctx->data);
194 ctx->use_cur_last_event_ts = 0;
195
196 /* Is the back end full? */
197 if (ctx->cbs.is_backend_full(ctx->data)) {
198 /* Yes: discard event record */
199 goto no_space;
200 }
201
202 /* Back-end is _not_ full: open new packet */
203 ctx->use_cur_last_event_ts = 1;
204 ctx->cbs.open_packet(ctx->data);
205 ctx->use_cur_last_event_ts = 0;
206 assert(er_size <= (ctx->packet_size - ctx->at));
207 }
208
209 ret = 1;
210 goto end;
211
212 no_space:
213 ctx->events_discarded++;
214 ret = 0;
215
216 end:
217 return ret;
218 }
219
220 static
221 void _commit_er(void * const vctx)
222 {
223 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
224
225 /* Is the packet full? */
226 if ({{ prefix }}packet_is_full(ctx)) {
227 /* Yes: close it now */
228 ctx->cbs.close_packet(ctx->data);
229 }
230 }
231
232 {% include 'c/ctx-init-func-proto.j2' %}
233
234 {
235 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
236 ctx->cbs = cbs;
237 ctx->data = data;
238 ctx->buf = buf;
239 ctx->packet_size = _BYTES_TO_BITS(buf_size);
240 ctx->at = 0;
241 ctx->events_discarded = 0;
242 ctx->packet_is_open = 0;
243 ctx->in_tracing_section = 0;
244 ctx->is_tracing_enabled = 1;
245 ctx->use_cur_last_event_ts = 0;
246 }
247
248 {% for dst in cfg.trace.type.data_stream_types | sort %}
249 {% set def_clk_type = dst.default_clock_type %}
250 {% set sctx_name %}{{ prefix }}{{ dst.name }}{% endset %}
251 {% set this_ds_ops = ds_ops[dst] %}
252 {% include 'c/open-func-proto.j2' %}
253
254 {
255 {{ macros.open_close_func_preamble(dst, dst.features.packet_features.beginning_timestamp_field_type) | indent_tab }}
256
257 /*
258 * This function is either called by a tracing function, or
259 * directly by the platform.
260 *
261 * If it's called by a tracing function, then
262 * `ctx->in_tracing_section` is 1, so it's safe to open
263 * the packet here (alter the packet), even if tracing was
264 * disabled in the meantime because we're already in a tracing
265 * section (which finishes at the end of the tracing function
266 * call).
267 *
268 * If it's called directly by the platform, then if tracing is
269 * disabled, we don't want to alter the packet, and return
270 * immediately.
271 */
272 if (!ctx->is_tracing_enabled && !saved_in_tracing_section) {
273 ctx->in_tracing_section = 0;
274 goto end;
275 }
276
277 /* We can alter the packet */
278 ctx->in_tracing_section = 1;
279
280 /* Do not open a packet that is already open */
281 if (ctx->packet_is_open) {
282 ctx->in_tracing_section = saved_in_tracing_section;
283 goto end;
284 }
285
286 ctx->at = 0;
287 {% set pkt_header_op = this_ds_ops.pkt_header_op %}
288 {% if pkt_header_op %}
289
290 {{ pkt_header_op.serialize_str(dst=dst) | indent_tab }}
291 {% endif %}
292
293 {{ this_ds_ops.pkt_ctx_op.serialize_str(dst=dst) | indent_tab }}
294
295 /* Save content beginning's offset */
296 ctx->off_content = ctx->at;
297
298 /* Mark current packet as open */
299 ctx->packet_is_open = 1;
300
301 /* Not tracing anymore */
302 ctx->in_tracing_section = saved_in_tracing_section;
303
304 end:
305 return;
306 }
307
308 {% include 'c/close-func-proto.j2' %}
309
310 {
311 {{ macros.open_close_func_preamble(dst, dst.features.packet_features.end_timestamp_field_type) | indent_tab }}
312
313 /*
314 * This function is either called by a tracing function, or
315 * directly by the platform.
316 *
317 * If it's called by a tracing function, then
318 * `ctx->in_tracing_section` is 1, so it's safe to close
319 * the packet here (alter the packet), even if tracing was
320 * disabled in the meantime, because we're already in a tracing
321 * section (which finishes at the end of the tracing function
322 * call).
323 *
324 * If it's called directly by the platform, then if tracing is
325 * disabled, we don't want to alter the packet, and return
326 * immediately.
327 */
328 if (!ctx->is_tracing_enabled && !saved_in_tracing_section) {
329 ctx->in_tracing_section = 0;
330 goto end;
331 }
332
333 /* We can alter the packet */
334 ctx->in_tracing_section = 1;
335
336 /* Do not close a packet that is not open */
337 if (!ctx->packet_is_open) {
338 ctx->in_tracing_section = saved_in_tracing_section;
339 goto end;
340 }
341
342 /* Save content size */
343 ctx->content_size = ctx->at;
344 {% set name = 'timestamp_end' %}
345 {% if name in dst._pkt_ctx_ft.members %}
346 {% set op = ds_op_pkt_ctx_op(dst, name) %}
347
348 /* Go back to `timestamp_end` field offset */
349 ctx->at = sctx->off_{{ op | op_src_var_name }};
350
351 {% set src = 'ts' %}
352 {% filter indent_tab(indent_first=true) %}
353 {% include 'c/serialize-write-saved-int-statements.j2' %}
354
355 {% endfilter %}
356 {% endif %}
357 {% set name = 'content_size' %}
358 {% if name in dst._pkt_ctx_ft.members %}
359 {% set op = ds_op_pkt_ctx_op(dst, name) %}
360
361 /* Go back to `content_size` field offset */
362 ctx->at = sctx->off_{{ op | op_src_var_name }};
363
364 {% set src %}ctx->{{ name }}{% endset %}
365 {% filter indent_tab(indent_first=true) %}
366 {% include 'c/serialize-write-saved-int-statements.j2' %}
367
368 {% endfilter %}
369 {% endif %}
370 {% set name = 'events_discarded' %}
371 {% if name in dst._pkt_ctx_ft.members %}
372 {% set op = ds_op_pkt_ctx_op(dst, name) %}
373
374 /* Go back to `events_discarded` field offset */
375 ctx->at = sctx->off_{{ op | op_src_var_name }};
376
377 {% set src %}ctx->{{ name }}{% endset %}
378 {% filter indent_tab(indent_first=true) %}
379 {% include 'c/serialize-write-saved-int-statements.j2' %}
380
381 {% endfilter %}
382 {% endif %}
383
384 /* Go back to end of packet */
385 ctx->at = ctx->packet_size;
386
387 /* Mark packet as closed */
388 ctx->packet_is_open = 0;
389
390 /* Not tracing anymore */
391 ctx->in_tracing_section = saved_in_tracing_section;
392
393 end:
394 return;
395 }
396
397 {% if dst._er_header_ft %}
398 static void _serialize_er_header_{{ dst.name }}(void * const vctx,
399 const uint32_t ert_id)
400 {
401 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
402 {% if def_clk_type and dst.features.event_record_features.timestamp_field_type %}
403 struct {{ sctx_name }}_ctx * const sctx = _FROM_VOID_PTR(struct {{ sctx_name }}_ctx, vctx);
404 const {{ cg_opts.clock_type_c_types[def_clk_type] }} ts = sctx->cur_last_event_ts;
405 {% endif %}
406
407 {{ this_ds_ops.er_header_op.serialize_str(dst=dst) | indent_tab }}
408 }
409
410 {% endif %}
411 {% if dst.event_record_common_context_field_type %}
412 static void _serialize_er_common_ctx_{{ dst.name }}(void * const vctx{{ dst | serialize_er_common_ctx_func_params_str(const_params) }})
413 {
414 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
415
416 {{ this_ds_ops.er_common_ctx_op.serialize_str(dst=dst) | indent_tab }}
417 }
418
419 {% endif %}
420 {# internal serialization functions #}
421 {% for ert in dst.event_record_types | sort %}
422 static void _serialize_er_{{ dst.name }}_{{ ert.name }}(void * const vctx{{ (dst, ert) | trace_func_params_str(const_params) }})
423 {
424 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
425 {% if dst._er_header_ft %}
426
427 /* Serialize header */
428 _serialize_er_header_{{ dst.name }}(ctx, {{ ert.id }});
429 {% endif %}
430 {% if dst.event_record_common_context_field_type %}
431
432 /* Serialize common context */
433 {% set params = macros.ft_call_params(root_ft_prefixes.ERCC, dst.event_record_common_context_field_type) %}
434 _serialize_er_common_ctx_{{ dst.name }}(ctx{{ params }});
435 {% endif %}
436 {% set this_er_ops = this_ds_ops.er_ops[ert] %}
437 {% if this_er_ops.spec_ctx_op %}
438
439 {{ this_er_ops.spec_ctx_op.serialize_str(dst=dst, ert=ert) | indent_tab }}
440 {% endif %}
441 {% if this_er_ops.payload_op %}
442
443 {{ this_er_ops.payload_op.serialize_str(dst=dst, ert=ert) | indent_tab }}
444 {% endif %}
445 }
446
447 {% endfor %}
448 {# internal size functions #}
449 {% for ert in dst.event_record_types | sort %}
450 {% set this_er_ops = this_ds_ops.er_ops[ert] %}
451 static uint32_t _er_size_{{ dst.name }}_{{ ert.name }}(void * const vctx{{ (dst, ert) | trace_func_params_str(const_params, only_dyn=true) }})
452 {
453 struct {{ ctx_struct_name }} * const ctx = _FROM_VOID_PTR(struct {{ ctx_struct_name }}, vctx);
454 uint32_t at = ctx->at;
455 {% if this_ds_ops.er_header_op %}
456
457 {{ this_ds_ops.er_header_op.size_str(dst=dst) | indent_tab }}
458 {% endif %}
459 {% if this_ds_ops.er_common_ctx_op %}
460
461 {{ this_ds_ops.er_common_ctx_op.size_str(dst=dst) | indent_tab }}
462 {% endif %}
463 {% if this_er_ops.spec_ctx_op %}
464
465 {{ this_er_ops.spec_ctx_op.size_str(dst=dst, ert=ert) | indent_tab }}
466 {% endif %}
467 {% if this_er_ops.payload_op %}
468
469 {{ this_er_ops.payload_op.size_str(dst=dst, ert=ert) | indent_tab }}
470 {% endif %}
471
472 return at - ctx->at;
473 }
474
475 {% endfor %}
476 {# public tracing functions #}
477 {% for ert in dst.event_record_types | sort %}
478 {% include 'c/trace-func-proto.j2' %}
479
480 {
481 struct {{ ctx_struct_name }} * const ctx = &sctx->parent;
482 uint32_t er_size;
483
484 {% if def_clk_type %}
485 /* Save timestamp */
486 sctx->cur_last_event_ts = ctx->cbs.{{ def_clk_type.name }}_clock_get_value(ctx->data);
487
488 {% endif %}
489 if (!ctx->is_tracing_enabled) {
490 goto end;
491 }
492
493 /* We can alter the packet */
494 ctx->in_tracing_section = 1;
495
496 /* Compute event record size */
497 {% set er_common_ctx_params = macros.ft_call_params(root_ft_prefixes.ERCC, dst.event_record_common_context_field_type, true) %}
498 {% set spec_ctx_params = macros.ft_call_params(root_ft_prefixes.ERSC, ert.specific_context_field_type, true) %}
499 {% set payload_params = macros.ft_call_params(root_ft_prefixes.ERP, ert.payload_field_type, true) %}
500 {% set params %}{{ er_common_ctx_params }}{{ spec_ctx_params }}{{ payload_params }}{% endset %}
501 er_size = _er_size_{{ dst.name }}_{{ ert.name }}(_TO_VOID_PTR(ctx){{ params }});
502
503 /* Is there enough space to serialize? */
504 if (!_reserve_er_space(_TO_VOID_PTR(ctx), er_size)) {
505 /* no: forget this */
506 ctx->in_tracing_section = 0;
507 goto end;
508 }
509
510 /* Serialize event record */
511 {% set er_common_ctx_params = macros.ft_call_params(root_ft_prefixes.ERCC, dst.event_record_common_context_field_type) %}
512 {% set spec_ctx_params = macros.ft_call_params(root_ft_prefixes.ERSC, ert.specific_context_field_type) %}
513 {% set payload_params = macros.ft_call_params(root_ft_prefixes.ERP, ert.payload_field_type) %}
514 {% set params %}{{ er_common_ctx_params }}{{ spec_ctx_params }}{{ payload_params }}{% endset %}
515 _serialize_er_{{ dst.name }}_{{ ert.name }}(_TO_VOID_PTR(ctx){{ params }});
516
517 /* Commit event record */
518 _commit_er(_TO_VOID_PTR(ctx));
519
520 /* Not tracing anymore */
521 ctx->in_tracing_section = 0;
522
523 end:
524 return;
525 }
526 {% if not loop.last %}{{ '\n' }}{% endif %}
527 {% endfor %}
528 {% endfor %}
This page took 0.044638 seconds and 4 git commands to generate.