1 # The MIT License (MIT)
3 # Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
4 # Copyright (c) 2018 Francis Deslauriers <francis.deslauriers@efficios.com>
5 # Copyright (c) 2019 Simon Marchi <simon.marchi@efficios.com>
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to deal
9 # in the Software without restriction, including without limitation the rights
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 # copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 from bt2
import native_bt
, utils
, object
26 from bt2
import stream_class
as bt2_stream_class
27 from bt2
import field_class
as bt2_field_class
28 from bt2
import integer_range_set
as bt2_integer_range_set
29 from bt2
import trace
as bt2_trace
30 from bt2
import value
as bt2_value
31 import collections
.abc
36 def _trace_class_destruction_listener_from_native(
37 user_listener
, handle
, trace_class_ptr
39 trace_class
= _TraceClass
._create
_from
_ptr
_and
_get
_ref
(trace_class_ptr
)
40 user_listener(trace_class
)
44 class _TraceClassConst(object._SharedObject
, collections
.abc
.Mapping
):
45 _get_ref
= staticmethod(native_bt
.trace_class_get_ref
)
46 _put_ref
= staticmethod(native_bt
.trace_class_put_ref
)
47 _borrow_stream_class_ptr_by_index
= staticmethod(
48 native_bt
.trace_class_borrow_stream_class_by_index_const
50 _borrow_stream_class_ptr_by_id
= staticmethod(
51 native_bt
.trace_class_borrow_stream_class_by_id_const
53 _borrow_user_attributes_ptr
= staticmethod(
54 native_bt
.trace_class_borrow_user_attributes_const
56 _stream_class_pycls
= bt2_stream_class
._StreamClassConst
57 _create_value_from_ptr_and_get_ref
= staticmethod(
58 bt2_value
._create
_from
_const
_ptr
_and
_get
_ref
62 def user_attributes(self
):
63 ptr
= self
._borrow
_user
_attributes
_ptr
(self
._ptr
)
64 assert ptr
is not None
65 return self
._create
_value
_from
_ptr
_and
_get
_ref
(ptr
)
67 # Number of stream classes in this trace class.
70 count
= native_bt
.trace_class_get_stream_class_count(self
._ptr
)
74 # Get a stream class by stream id.
76 def __getitem__(self
, key
):
77 utils
._check
_uint
64(key
)
79 sc_ptr
= self
._borrow
_stream
_class
_ptr
_by
_id
(self
._ptr
, key
)
83 return self
._stream
_class
_pycls
._create
_from
_ptr
_and
_get
_ref
(sc_ptr
)
86 for idx
in range(len(self
)):
87 sc_ptr
= self
._borrow
_stream
_class
_ptr
_by
_index
(self
._ptr
, idx
)
88 assert sc_ptr
is not None
90 id = native_bt
.stream_class_get_id(sc_ptr
)
96 def assigns_automatic_stream_class_id(self
):
97 return native_bt
.trace_class_assigns_automatic_stream_class_id(self
._ptr
)
99 # Add a listener to be called when the trace class is destroyed.
101 def add_destruction_listener(self
, listener
):
103 if not callable(listener
):
104 raise TypeError("'listener' parameter is not callable")
106 handle
= utils
._ListenerHandle
(self
.addr
)
108 listener_from_native
= functools
.partial(
109 _trace_class_destruction_listener_from_native
, listener
, handle
112 fn
= native_bt
.bt2_trace_class_add_destruction_listener
113 status
, listener_id
= fn(self
._ptr
, listener_from_native
)
114 utils
._handle
_func
_status
(
115 status
, 'cannot add destruction listener to trace class object'
118 handle
._set
_listener
_id
(listener_id
)
122 def remove_destruction_listener(self
, listener_handle
):
123 utils
._check
_type
(listener_handle
, utils
._ListenerHandle
)
125 if listener_handle
._addr
!= self
.addr
:
127 'This trace class destruction listener does not match the trace class object.'
130 if listener_handle
._listener
_id
is None:
132 'This trace class destruction listener was already removed.'
135 status
= native_bt
.trace_class_remove_destruction_listener(
136 self
._ptr
, listener_handle
._listener
_id
138 utils
._handle
_func
_status
(status
)
139 listener_handle
._invalidate
()
142 class _TraceClass(_TraceClassConst
):
143 _borrow_stream_class_ptr_by_index
= staticmethod(
144 native_bt
.trace_class_borrow_stream_class_by_index
146 _borrow_stream_class_ptr_by_id
= staticmethod(
147 native_bt
.trace_class_borrow_stream_class_by_id
149 _borrow_user_attributes_ptr
= staticmethod(
150 native_bt
.trace_class_borrow_user_attributes
152 _stream_class_pycls
= bt2_stream_class
._StreamClass
153 _create_value_from_ptr_and_get_ref
= staticmethod(
154 bt2_value
._create
_from
_ptr
_and
_get
_ref
157 # Instantiate a trace of this class.
159 def __call__(self
, name
=None, user_attributes
=None, uuid
=None, environment
=None):
160 trace_ptr
= native_bt
.trace_create(self
._ptr
)
162 if trace_ptr
is None:
163 raise bt2
._MemoryError('cannot create trace class object')
165 trace
= bt2_trace
._Trace
._create
_from
_ptr
(trace_ptr
)
170 if user_attributes
is not None:
171 trace
._user
_attributes
= user_attributes
176 if environment
is not None:
177 for key
, value
in environment
.items():
178 trace
.environment
[key
] = value
182 def create_stream_class(
186 user_attributes
=None,
187 packet_context_field_class
=None,
188 event_common_context_field_class
=None,
189 default_clock_class
=None,
190 assigns_automatic_event_class_id
=True,
191 assigns_automatic_stream_id
=True,
192 supports_packets
=False,
193 packets_have_beginning_default_clock_snapshot
=False,
194 packets_have_end_default_clock_snapshot
=False,
195 supports_discarded_events
=False,
196 discarded_events_have_default_clock_snapshots
=False,
197 supports_discarded_packets
=False,
198 discarded_packets_have_default_clock_snapshots
=False,
200 # Validate parameters before we create the object.
201 bt2_stream_class
._StreamClass
._validate
_create
_params
(
204 packet_context_field_class
,
205 event_common_context_field_class
,
207 assigns_automatic_event_class_id
,
208 assigns_automatic_stream_id
,
210 packets_have_beginning_default_clock_snapshot
,
211 packets_have_end_default_clock_snapshot
,
212 supports_discarded_events
,
213 discarded_events_have_default_clock_snapshots
,
214 supports_discarded_packets
,
215 discarded_packets_have_default_clock_snapshots
,
218 if self
.assigns_automatic_stream_class_id
:
221 'id provided, but trace class assigns automatic stream class ids'
224 sc_ptr
= native_bt
.stream_class_create(self
._ptr
)
228 'id not provided, but trace class does not assign automatic stream class ids'
231 utils
._check
_uint
64(id)
232 sc_ptr
= native_bt
.stream_class_create_with_id(self
._ptr
, id)
234 sc
= bt2_stream_class
._StreamClass
._create
_from
_ptr
(sc_ptr
)
239 if user_attributes
is not None:
240 sc
._user
_attributes
= user_attributes
242 if event_common_context_field_class
is not None:
243 sc
._event
_common
_context
_field
_class
= event_common_context_field_class
245 if default_clock_class
is not None:
246 sc
._default
_clock
_class
= default_clock_class
248 # call after `sc._default_clock_class` because, if
249 # `packets_have_beginning_default_clock_snapshot` or
250 # `packets_have_end_default_clock_snapshot` is true, then this
251 # stream class needs a default clock class already.
252 sc
._set
_supports
_packets
(
254 packets_have_beginning_default_clock_snapshot
,
255 packets_have_end_default_clock_snapshot
,
258 # call after sc._set_supports_packets() because, if
259 # `packet_context_field_class` is not `None`, then this stream
260 # class needs to support packets already.
261 if packet_context_field_class
is not None:
262 sc
._packet
_context
_field
_class
= packet_context_field_class
264 sc
._assigns
_automatic
_event
_class
_id
= assigns_automatic_event_class_id
265 sc
._assigns
_automatic
_stream
_id
= assigns_automatic_stream_id
266 sc
._set
_supports
_discarded
_events
(
267 supports_discarded_events
, discarded_events_have_default_clock_snapshots
269 sc
._set
_supports
_discarded
_packets
(
270 supports_discarded_packets
, discarded_packets_have_default_clock_snapshots
274 def _user_attributes(self
, user_attributes
):
275 value
= bt2_value
.create_value(user_attributes
)
276 utils
._check
_type
(value
, bt2_value
.MapValue
)
277 native_bt
.trace_class_set_user_attributes(self
._ptr
, value
._ptr
)
279 _user_attributes
= property(fset
=_user_attributes
)
281 def _assigns_automatic_stream_class_id(self
, auto_id
):
282 utils
._check
_bool
(auto_id
)
283 return native_bt
.trace_class_set_assigns_automatic_stream_class_id(
287 _assigns_automatic_stream_class_id
= property(
288 fset
=_assigns_automatic_stream_class_id
291 # Field class creation methods.
293 def _check_field_class_create_status(self
, ptr
, type_name
):
295 raise bt2
._MemoryError('cannot create {} field class'.format(type_name
))
298 def _set_field_class_user_attrs(fc
, user_attributes
):
299 if user_attributes
is not None:
300 fc
._user
_attributes
= user_attributes
302 def create_bool_field_class(self
, user_attributes
=None):
303 field_class_ptr
= native_bt
.field_class_bool_create(self
._ptr
)
304 self
._check
_field
_class
_create
_status
(field_class_ptr
, 'boolean')
305 fc
= bt2_field_class
._BoolFieldClass
._create
_from
_ptr
(field_class_ptr
)
306 self
._set
_field
_class
_user
_attrs
(fc
, user_attributes
)
309 def create_bit_array_field_class(self
, length
, user_attributes
=None):
310 utils
._check
_uint
64(length
)
312 if length
< 1 or length
> 64:
314 'invalid length {}: expecting a value in the [1, 64] range'.format(
319 field_class_ptr
= native_bt
.field_class_bit_array_create(self
._ptr
, length
)
320 self
._check
_field
_class
_create
_status
(field_class_ptr
, 'bit array')
321 fc
= bt2_field_class
._BitArrayFieldClass
._create
_from
_ptr
(field_class_ptr
)
322 self
._set
_field
_class
_user
_attrs
(fc
, user_attributes
)
325 def _create_integer_field_class(
331 preferred_display_base
,
334 field_class_ptr
= create_func(self
._ptr
)
335 self
._check
_field
_class
_create
_status
(field_class_ptr
, type_name
)
337 field_class
= py_cls
._create
_from
_ptr
(field_class_ptr
)
339 if field_value_range
is not None:
340 field_class
._field
_value
_range
= field_value_range
342 if preferred_display_base
is not None:
343 field_class
._preferred
_display
_base
= preferred_display_base
345 self
._set
_field
_class
_user
_attrs
(field_class
, user_attributes
)
348 def create_signed_integer_field_class(
349 self
, field_value_range
=None, preferred_display_base
=None, user_attributes
=None
351 return self
._create
_integer
_field
_class
(
352 native_bt
.field_class_integer_signed_create
,
353 bt2_field_class
._SignedIntegerFieldClass
,
356 preferred_display_base
,
360 def create_unsigned_integer_field_class(
361 self
, field_value_range
=None, preferred_display_base
=None, user_attributes
=None
363 return self
._create
_integer
_field
_class
(
364 native_bt
.field_class_integer_unsigned_create
,
365 bt2_field_class
._UnsignedIntegerFieldClass
,
368 preferred_display_base
,
372 def create_signed_enumeration_field_class(
373 self
, field_value_range
=None, preferred_display_base
=None, user_attributes
=None
375 return self
._create
_integer
_field
_class
(
376 native_bt
.field_class_enumeration_signed_create
,
377 bt2_field_class
._SignedEnumerationFieldClass
,
378 'signed enumeration',
380 preferred_display_base
,
384 def create_unsigned_enumeration_field_class(
385 self
, field_value_range
=None, preferred_display_base
=None, user_attributes
=None
387 return self
._create
_integer
_field
_class
(
388 native_bt
.field_class_enumeration_unsigned_create
,
389 bt2_field_class
._UnsignedEnumerationFieldClass
,
390 'unsigned enumeration',
392 preferred_display_base
,
396 def create_single_precision_real_field_class(self
, user_attributes
=None):
397 field_class_ptr
= native_bt
.field_class_real_single_precision_create(self
._ptr
)
398 self
._check
_field
_class
_create
_status
(field_class_ptr
, 'single-precision real')
400 field_class
= bt2_field_class
._SinglePrecisionRealFieldClass
._create
_from
_ptr
(
404 self
._set
_field
_class
_user
_attrs
(field_class
, user_attributes
)
408 def create_double_precision_real_field_class(self
, user_attributes
=None):
409 field_class_ptr
= native_bt
.field_class_real_double_precision_create(self
._ptr
)
410 self
._check
_field
_class
_create
_status
(field_class_ptr
, 'double-precision real')
412 field_class
= bt2_field_class
._DoublePrecisionRealFieldClass
._create
_from
_ptr
(
416 self
._set
_field
_class
_user
_attrs
(field_class
, user_attributes
)
420 def create_structure_field_class(self
, user_attributes
=None):
421 field_class_ptr
= native_bt
.field_class_structure_create(self
._ptr
)
422 self
._check
_field
_class
_create
_status
(field_class_ptr
, 'structure')
423 fc
= bt2_field_class
._StructureFieldClass
._create
_from
_ptr
(field_class_ptr
)
424 self
._set
_field
_class
_user
_attrs
(fc
, user_attributes
)
427 def create_string_field_class(self
, user_attributes
=None):
428 field_class_ptr
= native_bt
.field_class_string_create(self
._ptr
)
429 self
._check
_field
_class
_create
_status
(field_class_ptr
, 'string')
430 fc
= bt2_field_class
._StringFieldClass
._create
_from
_ptr
(field_class_ptr
)
431 self
._set
_field
_class
_user
_attrs
(fc
, user_attributes
)
434 def create_static_array_field_class(self
, elem_fc
, length
, user_attributes
=None):
435 utils
._check
_type
(elem_fc
, bt2_field_class
._FieldClass
)
436 utils
._check
_uint
64(length
)
437 ptr
= native_bt
.field_class_array_static_create(self
._ptr
, elem_fc
._ptr
, length
)
438 self
._check
_field
_class
_create
_status
(ptr
, 'static array')
439 fc
= bt2_field_class
._StaticArrayFieldClass
._create
_from
_ptr
_and
_get
_ref
(ptr
)
440 self
._set
_field
_class
_user
_attrs
(fc
, user_attributes
)
443 def create_dynamic_array_field_class(
444 self
, elem_fc
, length_fc
=None, user_attributes
=None
446 utils
._check
_type
(elem_fc
, bt2_field_class
._FieldClass
)
449 if length_fc
is not None:
450 utils
._check
_type
(length_fc
, bt2_field_class
._UnsignedIntegerFieldClass
)
451 length_fc_ptr
= length_fc
._ptr
453 ptr
= native_bt
.field_class_array_dynamic_create(
454 self
._ptr
, elem_fc
._ptr
, length_fc_ptr
456 self
._check
_field
_class
_create
_status
(ptr
, 'dynamic array')
457 fc
= bt2_field_class
._create
_field
_class
_from
_ptr
_and
_get
_ref
(ptr
)
458 self
._set
_field
_class
_user
_attrs
(fc
, user_attributes
)
461 def create_option_without_selector_field_class(
462 self
, content_fc
, user_attributes
=None
464 utils
._check
_type
(content_fc
, bt2_field_class
._FieldClass
)
465 ptr
= native_bt
.field_class_option_without_selector_create(
466 self
._ptr
, content_fc
._ptr
468 self
._check
_field
_class
_create
_status
(ptr
, 'option')
469 fc
= bt2_field_class
._create
_field
_class
_from
_ptr
_and
_get
_ref
(ptr
)
470 self
._set
_field
_class
_user
_attrs
(fc
, user_attributes
)
473 def create_option_with_bool_selector_field_class(
474 self
, content_fc
, selector_fc
, selector_is_reversed
=False, user_attributes
=None
476 utils
._check
_type
(content_fc
, bt2_field_class
._FieldClass
)
477 utils
._check
_bool
(selector_is_reversed
)
478 utils
._check
_type
(selector_fc
, bt2_field_class
._BoolFieldClass
)
479 ptr
= native_bt
.field_class_option_with_selector_field_bool_create(
480 self
._ptr
, content_fc
._ptr
, selector_fc
._ptr
482 self
._check
_field
_class
_create
_status
(ptr
, 'option')
483 fc
= bt2_field_class
._create
_field
_class
_from
_ptr
_and
_get
_ref
(ptr
)
484 self
._set
_field
_class
_user
_attrs
(fc
, user_attributes
)
485 fc
._selector
_is
_reversed
= selector_is_reversed
488 def create_option_with_integer_selector_field_class(
489 self
, content_fc
, selector_fc
, ranges
, user_attributes
=None
491 utils
._check
_type
(content_fc
, bt2_field_class
._FieldClass
)
492 utils
._check
_type
(selector_fc
, bt2_field_class
._IntegerFieldClass
)
495 raise ValueError('integer range set is empty')
497 if isinstance(selector_fc
, bt2_field_class
._UnsignedIntegerFieldClass
):
498 utils
._check
_type
(ranges
, bt2_integer_range_set
.UnsignedIntegerRangeSet
)
499 ptr
= native_bt
.field_class_option_with_selector_field_integer_unsigned_create(
500 self
._ptr
, content_fc
._ptr
, selector_fc
._ptr
, ranges
._ptr
503 utils
._check
_type
(ranges
, bt2_integer_range_set
.SignedIntegerRangeSet
)
505 native_bt
.field_class_option_with_selector_field_integer_signed_create(
506 self
._ptr
, content_fc
._ptr
, selector_fc
._ptr
, ranges
._ptr
510 self
._check
_field
_class
_create
_status
(ptr
, 'option')
511 fc
= bt2_field_class
._create
_field
_class
_from
_ptr
_and
_get
_ref
(ptr
)
512 self
._set
_field
_class
_user
_attrs
(fc
, user_attributes
)
515 def create_variant_field_class(self
, selector_fc
=None, user_attributes
=None):
516 selector_fc_ptr
= None
518 if selector_fc
is not None:
519 utils
._check
_type
(selector_fc
, bt2_field_class
._IntegerFieldClass
)
520 selector_fc_ptr
= selector_fc
._ptr
522 ptr
= native_bt
.field_class_variant_create(self
._ptr
, selector_fc_ptr
)
523 self
._check
_field
_class
_create
_status
(ptr
, 'variant')
524 fc
= bt2_field_class
._create
_field
_class
_from
_ptr
_and
_get
_ref
(ptr
)
525 self
._set
_field
_class
_user
_attrs
(fc
, user_attributes
)