lib: update copyrights
[babeltrace.git] / lib / trace-ir / stream-class.c
... / ...
CommitLineData
1/*
2 * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
3 * Copyright 2013, 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#define BT_LOG_TAG "STREAM-CLASS"
25#include <babeltrace/lib-logging-internal.h>
26
27#include <babeltrace/assert-pre-internal.h>
28#include <babeltrace/trace-ir/clock-class-internal.h>
29#include <babeltrace/trace-ir/event-class-internal.h>
30#include <babeltrace/trace-ir/field-class-internal.h>
31#include <babeltrace/trace-ir/field-internal.h>
32#include <babeltrace/trace-ir/stream-class-internal.h>
33#include <babeltrace/trace-ir/trace-const.h>
34#include <babeltrace/trace-ir/trace-internal.h>
35#include <babeltrace/trace-ir/utils-internal.h>
36#include <babeltrace/trace-ir/field-wrapper-internal.h>
37#include <babeltrace/trace-ir/resolve-field-path-internal.h>
38#include <babeltrace/object.h>
39#include <babeltrace/compiler-internal.h>
40#include <babeltrace/align-internal.h>
41#include <babeltrace/endian-internal.h>
42#include <babeltrace/assert-internal.h>
43#include <babeltrace/property-internal.h>
44#include <inttypes.h>
45#include <stdint.h>
46#include <stdbool.h>
47
48#define BT_ASSERT_PRE_STREAM_CLASS_HOT(_sc) \
49 BT_ASSERT_PRE_HOT((_sc), "Stream class", ": %!+S", (_sc))
50
51static
52void destroy_stream_class(struct bt_object *obj)
53{
54 struct bt_stream_class *stream_class = (void *) obj;
55
56 BT_LIB_LOGD("Destroying stream class: %!+S", stream_class);
57 BT_LOGD_STR("Putting default clock class.");
58 BT_OBJECT_PUT_REF_AND_RESET(stream_class->default_clock_class);
59
60 if (stream_class->event_classes) {
61 BT_LOGD_STR("Destroying event classes.");
62 g_ptr_array_free(stream_class->event_classes, TRUE);
63 stream_class->event_classes = NULL;
64 }
65
66 if (stream_class->name.str) {
67 g_string_free(stream_class->name.str, TRUE);
68 stream_class->name.str = NULL;
69 stream_class->name.value = NULL;
70 }
71
72 BT_LOGD_STR("Putting event header field class.");
73 BT_OBJECT_PUT_REF_AND_RESET(stream_class->event_header_fc);
74 BT_LOGD_STR("Putting packet context field class.");
75 BT_OBJECT_PUT_REF_AND_RESET(stream_class->packet_context_fc);
76 BT_LOGD_STR("Putting event common context field class.");
77 BT_OBJECT_PUT_REF_AND_RESET(stream_class->event_common_context_fc);
78 bt_object_pool_finalize(&stream_class->event_header_field_pool);
79 bt_object_pool_finalize(&stream_class->packet_context_field_pool);
80 g_free(stream_class);
81}
82
83static
84void free_field_wrapper(struct bt_field_wrapper *field_wrapper,
85 struct bt_stream_class *stream_class)
86{
87 bt_field_wrapper_destroy((void *) field_wrapper);
88}
89
90BT_ASSERT_PRE_FUNC
91static
92bool stream_class_id_is_unique(const struct bt_trace_class *tc, uint64_t id)
93{
94 uint64_t i;
95 bool is_unique = true;
96
97 for (i = 0; i < tc->stream_classes->len; i++) {
98 const struct bt_stream_class *sc =
99 tc->stream_classes->pdata[i];
100
101 if (sc->id == id) {
102 is_unique = false;
103 goto end;
104 }
105 }
106
107end:
108 return is_unique;
109}
110
111static
112struct bt_stream_class *create_stream_class_with_id(
113 struct bt_trace_class *tc, uint64_t id)
114{
115 struct bt_stream_class *stream_class = NULL;
116 int ret;
117
118 BT_ASSERT(tc);
119 BT_ASSERT_PRE(stream_class_id_is_unique(tc, id),
120 "Duplicate stream class ID: %![tc-]+T, id=%" PRIu64, tc, id);
121 BT_LIB_LOGD("Creating stream class object: %![tc-]+T, id=%" PRIu64,
122 tc, id);
123 stream_class = g_new0(struct bt_stream_class, 1);
124 if (!stream_class) {
125 BT_LOGE_STR("Failed to allocate one stream class.");
126 goto error;
127 }
128
129 bt_object_init_shared_with_parent(&stream_class->base,
130 destroy_stream_class);
131
132 stream_class->name.str = g_string_new(NULL);
133 if (!stream_class->name.str) {
134 BT_LOGE_STR("Failed to allocate a GString.");
135 ret = -1;
136 goto end;
137 }
138
139 stream_class->id = id;
140 stream_class->assigns_automatic_event_class_id = true;
141 stream_class->assigns_automatic_stream_id = true;
142 stream_class->event_classes = g_ptr_array_new_with_free_func(
143 (GDestroyNotify) bt_object_try_spec_release);
144 if (!stream_class->event_classes) {
145 BT_LOGE_STR("Failed to allocate a GPtrArray.");
146 goto error;
147 }
148
149 ret = bt_object_pool_initialize(&stream_class->event_header_field_pool,
150 (bt_object_pool_new_object_func) bt_field_wrapper_new,
151 (bt_object_pool_destroy_object_func) free_field_wrapper,
152 stream_class);
153 if (ret) {
154 BT_LOGE("Failed to initialize event header field pool: ret=%d",
155 ret);
156 goto error;
157 }
158
159 ret = bt_object_pool_initialize(&stream_class->packet_context_field_pool,
160 (bt_object_pool_new_object_func) bt_field_wrapper_new,
161 (bt_object_pool_destroy_object_func) free_field_wrapper,
162 stream_class);
163 if (ret) {
164 BT_LOGE("Failed to initialize packet context field pool: ret=%d",
165 ret);
166 goto error;
167 }
168
169 bt_object_set_parent(&stream_class->base, &tc->base);
170 g_ptr_array_add(tc->stream_classes, stream_class);
171 bt_trace_class_freeze(tc);
172 BT_LIB_LOGD("Created stream class object: %!+S", stream_class);
173 goto end;
174
175error:
176 BT_OBJECT_PUT_REF_AND_RESET(stream_class);
177
178end:
179 return stream_class;
180}
181
182struct bt_stream_class *bt_stream_class_create(struct bt_trace_class *tc)
183{
184 BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
185 BT_ASSERT_PRE(tc->assigns_automatic_stream_class_id,
186 "Trace class does not automatically assigns stream class IDs: "
187 "%![sc-]+T", tc);
188 return create_stream_class_with_id(tc,
189 (uint64_t) tc->stream_classes->len);
190}
191
192struct bt_stream_class *bt_stream_class_create_with_id(
193 struct bt_trace_class *tc, uint64_t id)
194{
195 BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
196 BT_ASSERT_PRE(!tc->assigns_automatic_stream_class_id,
197 "Trace class automatically assigns stream class IDs: "
198 "%![sc-]+T", tc);
199 return create_stream_class_with_id(tc, id);
200}
201
202struct bt_trace_class *bt_stream_class_borrow_trace_class(
203 struct bt_stream_class *stream_class)
204{
205 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
206 return bt_stream_class_borrow_trace_class_inline(stream_class);
207}
208
209const struct bt_trace_class *bt_stream_class_borrow_trace_class_const(
210 const struct bt_stream_class *stream_class)
211{
212 return bt_stream_class_borrow_trace_class((void *) stream_class);
213}
214
215const char *bt_stream_class_get_name(const struct bt_stream_class *stream_class)
216{
217 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
218 return stream_class->name.value;
219}
220
221int bt_stream_class_set_name(
222 struct bt_stream_class *stream_class,
223 const char *name)
224{
225 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
226 BT_ASSERT_PRE_NON_NULL(name, "Name");
227 BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
228 g_string_assign(stream_class->name.str, name);
229 stream_class->name.value = stream_class->name.str->str;
230 BT_LIB_LOGV("Set stream class's name: %!+S", stream_class);
231 return 0;
232}
233
234uint64_t bt_stream_class_get_id(const struct bt_stream_class *stream_class)
235{
236 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
237 return stream_class->id;
238}
239
240uint64_t bt_stream_class_get_event_class_count(
241 const struct bt_stream_class *stream_class)
242{
243 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
244 return (uint64_t) stream_class->event_classes->len;
245}
246
247struct bt_event_class *bt_stream_class_borrow_event_class_by_index(
248 struct bt_stream_class *stream_class, uint64_t index)
249{
250 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
251 BT_ASSERT_PRE_VALID_INDEX(index, stream_class->event_classes->len);
252 return g_ptr_array_index(stream_class->event_classes, index);
253}
254
255const struct bt_event_class *
256bt_stream_class_borrow_event_class_by_index_const(
257 const struct bt_stream_class *stream_class, uint64_t index)
258{
259 return bt_stream_class_borrow_event_class_by_index(
260 (void *) stream_class, index);
261}
262
263struct bt_event_class *bt_stream_class_borrow_event_class_by_id(
264 struct bt_stream_class *stream_class, uint64_t id)
265{
266 struct bt_event_class *event_class = NULL;
267 uint64_t i;
268
269 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
270
271 for (i = 0; i < stream_class->event_classes->len; i++) {
272 struct bt_event_class *event_class_candidate =
273 g_ptr_array_index(stream_class->event_classes, i);
274
275 if (event_class_candidate->id == id) {
276 event_class = event_class_candidate;
277 goto end;
278 }
279 }
280
281end:
282 return event_class;
283}
284
285const struct bt_event_class *
286bt_stream_class_borrow_event_class_by_id_const(
287 const struct bt_stream_class *stream_class, uint64_t id)
288{
289 return bt_stream_class_borrow_event_class_by_id(
290 (void *) stream_class, id);
291}
292
293const struct bt_field_class *
294bt_stream_class_borrow_packet_context_field_class_const(
295 const struct bt_stream_class *stream_class)
296{
297 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
298 return stream_class->packet_context_fc;
299}
300
301int bt_stream_class_set_packet_context_field_class(
302 struct bt_stream_class *stream_class,
303 struct bt_field_class *field_class)
304{
305 int ret;
306 struct bt_resolve_field_path_context resolve_ctx = {
307 .packet_header = NULL,
308 .packet_context = field_class,
309 .event_header = NULL,
310 .event_common_context = NULL,
311 .event_specific_context = NULL,
312 .event_payload = NULL,
313 };
314
315 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
316 BT_ASSERT_PRE_NON_NULL(field_class, "Field class");
317 BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
318 BT_ASSERT_PRE(bt_field_class_get_type(field_class) ==
319 BT_FIELD_CLASS_TYPE_STRUCTURE,
320 "Packet context field class is not a structure field class: %!+F",
321 field_class);
322 resolve_ctx.packet_header =
323 bt_stream_class_borrow_trace_class_inline(stream_class)->packet_header_fc;
324 ret = bt_resolve_field_paths(field_class, &resolve_ctx);
325 if (ret) {
326 goto end;
327 }
328
329 bt_field_class_make_part_of_trace_class(field_class);
330 bt_object_put_ref(stream_class->packet_context_fc);
331 stream_class->packet_context_fc = field_class;
332 bt_object_get_no_null_check(stream_class->packet_context_fc);
333 bt_field_class_freeze(field_class);
334 BT_LIB_LOGV("Set stream class's packet context field class: %!+S",
335 stream_class);
336
337end:
338 return ret;
339}
340
341const struct bt_field_class *bt_stream_class_borrow_event_header_field_class_const(
342 const struct bt_stream_class *stream_class)
343{
344 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
345 return stream_class->event_header_fc;
346}
347
348int bt_stream_class_set_event_header_field_class(
349 struct bt_stream_class *stream_class,
350 struct bt_field_class *field_class)
351{
352 int ret;
353 struct bt_resolve_field_path_context resolve_ctx = {
354 .packet_header = NULL,
355 .packet_context = NULL,
356 .event_header = field_class,
357 .event_common_context = NULL,
358 .event_specific_context = NULL,
359 .event_payload = NULL,
360 };
361
362 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
363 BT_ASSERT_PRE_NON_NULL(field_class, "Field class");
364 BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
365 BT_ASSERT_PRE(bt_field_class_get_type(field_class) ==
366 BT_FIELD_CLASS_TYPE_STRUCTURE,
367 "Event header field class is not a structure field class: %!+F",
368 field_class);
369 resolve_ctx.packet_header =
370 bt_stream_class_borrow_trace_class_inline(stream_class)->packet_header_fc;
371 resolve_ctx.packet_context = stream_class->packet_context_fc;
372 ret = bt_resolve_field_paths(field_class, &resolve_ctx);
373 if (ret) {
374 goto end;
375 }
376
377 bt_field_class_make_part_of_trace_class(field_class);
378 bt_object_put_ref(stream_class->event_header_fc);
379 stream_class->event_header_fc = field_class;
380 bt_object_get_no_null_check(stream_class->event_header_fc);
381 bt_field_class_freeze(field_class);
382 BT_LIB_LOGV("Set stream class's event header field class: %!+S",
383 stream_class);
384
385end:
386 return ret;
387}
388
389const struct bt_field_class *
390bt_stream_class_borrow_event_common_context_field_class_const(
391 const struct bt_stream_class *stream_class)
392{
393 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
394 return stream_class->event_common_context_fc;
395}
396
397int bt_stream_class_set_event_common_context_field_class(
398 struct bt_stream_class *stream_class,
399 struct bt_field_class *field_class)
400{
401 int ret;
402 struct bt_resolve_field_path_context resolve_ctx = {
403 .packet_header = NULL,
404 .packet_context = NULL,
405 .event_header = NULL,
406 .event_common_context = field_class,
407 .event_specific_context = NULL,
408 .event_payload = NULL,
409 };
410
411 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
412 BT_ASSERT_PRE_NON_NULL(field_class, "Field class");
413 BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
414 BT_ASSERT_PRE(bt_field_class_get_type(field_class) ==
415 BT_FIELD_CLASS_TYPE_STRUCTURE,
416 "Event common context field class is not a structure field class: %!+F",
417 field_class);
418 resolve_ctx.packet_header =
419 bt_stream_class_borrow_trace_class_inline(stream_class)->packet_header_fc;
420 resolve_ctx.packet_context = stream_class->packet_context_fc;
421 resolve_ctx.event_header = stream_class->event_header_fc;
422 ret = bt_resolve_field_paths(field_class, &resolve_ctx);
423 if (ret) {
424 goto end;
425 }
426
427 bt_field_class_make_part_of_trace_class(field_class);
428 bt_object_put_ref(stream_class->event_common_context_fc);
429 stream_class->event_common_context_fc = field_class;
430 bt_object_get_no_null_check(stream_class->event_common_context_fc);
431 bt_field_class_freeze(field_class);
432 BT_LIB_LOGV("Set stream class's event common context field class: %!+S",
433 stream_class);
434
435end:
436 return ret;
437}
438
439BT_HIDDEN
440void _bt_stream_class_freeze(const struct bt_stream_class *stream_class)
441{
442 /* The field classes and default clock class are already frozen */
443 BT_ASSERT(stream_class);
444 BT_LIB_LOGD("Freezing stream class: %!+S", stream_class);
445 ((struct bt_stream_class *) stream_class)->frozen = true;
446}
447
448int bt_stream_class_set_default_clock_class(
449 struct bt_stream_class *stream_class,
450 struct bt_clock_class *clock_class)
451{
452 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
453 BT_ASSERT_PRE_NON_NULL(clock_class, "Clock class");
454 BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
455 bt_object_put_ref(stream_class->default_clock_class);
456 stream_class->default_clock_class = clock_class;
457 bt_object_get_no_null_check(stream_class->default_clock_class);
458 bt_clock_class_freeze(clock_class);
459 BT_LIB_LOGV("Set stream class's default clock class: %!+S",
460 stream_class);
461 return 0;
462}
463
464struct bt_clock_class *bt_stream_class_borrow_default_clock_class(
465 struct bt_stream_class *stream_class)
466{
467 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
468 return stream_class->default_clock_class;
469}
470
471const struct bt_clock_class *bt_stream_class_borrow_default_clock_class_const(
472 const struct bt_stream_class *stream_class)
473{
474 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
475 return stream_class->default_clock_class;
476}
477
478bt_bool bt_stream_class_assigns_automatic_event_class_id(
479 const struct bt_stream_class *stream_class)
480{
481 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
482 return (bt_bool) stream_class->assigns_automatic_event_class_id;
483}
484
485void bt_stream_class_set_assigns_automatic_event_class_id(
486 struct bt_stream_class *stream_class,
487 bt_bool value)
488{
489 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
490 BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
491 stream_class->assigns_automatic_event_class_id = (bool) value;
492 BT_LIB_LOGV("Set stream class's automatic event class ID "
493 "assignment property: %!+S", stream_class);
494}
495
496bt_bool bt_stream_class_assigns_automatic_stream_id(
497 const struct bt_stream_class *stream_class)
498{
499 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
500 return (bt_bool) stream_class->assigns_automatic_stream_id;
501}
502
503void bt_stream_class_set_assigns_automatic_stream_id(
504 struct bt_stream_class *stream_class,
505 bt_bool value)
506{
507 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
508 BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
509 stream_class->assigns_automatic_stream_id = (bool) value;
510 BT_LIB_LOGV("Set stream class's automatic stream ID "
511 "assignment property: %!+S", stream_class);
512}
513
514bt_bool bt_stream_class_packets_have_discarded_event_counter_snapshot(
515 const struct bt_stream_class *stream_class)
516{
517 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
518 return (bt_bool) stream_class->packets_have_discarded_event_counter_snapshot;
519}
520
521void bt_stream_class_set_packets_have_discarded_event_counter_snapshot(
522 struct bt_stream_class *stream_class,
523 bt_bool value)
524{
525 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
526 BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
527 stream_class->packets_have_discarded_event_counter_snapshot =
528 (bool) value;
529 BT_LIB_LOGV("Set stream class's "
530 "\"packets have discarded event counter snapshot\" property: "
531 "%!+S", stream_class);
532}
533
534bt_bool bt_stream_class_packets_have_packet_counter_snapshot(
535 const struct bt_stream_class *stream_class)
536{
537 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
538 return (bt_bool) stream_class->packets_have_packet_counter_snapshot;
539}
540
541void bt_stream_class_set_packets_have_packet_counter_snapshot(
542 struct bt_stream_class *stream_class,
543 bt_bool value)
544{
545 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
546 BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
547 stream_class->packets_have_packet_counter_snapshot =
548 (bool) value;
549 BT_LIB_LOGV("Set stream class's "
550 "\"packets have packet counter snapshot\" property: "
551 "%!+S", stream_class);
552}
553
554bt_bool bt_stream_class_packets_have_default_beginning_clock_value(
555 const struct bt_stream_class *stream_class)
556{
557 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
558 return (bt_bool) stream_class->packets_have_default_beginning_cv;
559}
560
561void bt_stream_class_set_packets_have_default_beginning_clock_value(
562 struct bt_stream_class *stream_class,
563 bt_bool value)
564{
565 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
566 BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
567 BT_ASSERT_PRE(!value || stream_class->default_clock_class,
568 "Stream class does not have a default clock class: %!+S",
569 stream_class);
570 stream_class->packets_have_default_beginning_cv = (bool) value;
571 BT_LIB_LOGV("Set stream class's "
572 "\"packets have default beginning clock value\" property: "
573 "%!+S", stream_class);
574}
575
576bt_bool bt_stream_class_packets_have_default_end_clock_value(
577 const struct bt_stream_class *stream_class)
578{
579 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
580 return (bt_bool) stream_class->packets_have_default_end_cv;
581}
582
583void bt_stream_class_set_packets_have_default_end_clock_value(
584 struct bt_stream_class *stream_class,
585 bt_bool value)
586{
587 BT_ASSERT_PRE_NON_NULL(stream_class, "Stream class");
588 BT_ASSERT_PRE_STREAM_CLASS_HOT(stream_class);
589 BT_ASSERT_PRE(!value || stream_class->default_clock_class,
590 "Stream class does not have a default clock class: %!+S",
591 stream_class);
592 stream_class->packets_have_default_end_cv = (bool) value;
593 BT_LIB_LOGV("Set stream class's "
594 "\"packets have default end clock value\" property: "
595 "%!+S", stream_class);
596}
597
598bt_bool bt_stream_class_default_clock_is_always_known(
599 const struct bt_stream_class *stream_class)
600{
601 /* BT_CLOCK_VALUE_STATUS_UNKNOWN is not supported as of 2.0 */
602 return BT_TRUE;
603}
This page took 0.023951 seconds and 4 git commands to generate.