from bt2.component import _UserSourceComponent
from bt2.connection import *
from bt2.connection import _Connection
-from bt2.connection import _PrivateConnection
from bt2.ctf_writer import *
from bt2.ctf_writer import _CtfWriterStream
from bt2.event import _Event
return (self.seconds, self.cycles) == (other.seconds, other.cycles)
-class ClockClass(object._Object):
+class ClockClass(object._SharedObject):
def __init__(self, name, frequency, description=None, precision=None,
offset=None, is_absolute=None, uuid=None):
utils._check_str(name)
return clock_snapshot
-class _ClockSnapshot(object._Object):
+class _ClockSnapshot(object._UniqueObject):
def __init__(self, clock_class_ptr, cycles):
utils._check_uint64(cycles)
ptr = native_bt.clock_snapshot_create(clock_class_ptr, cycles)
# have been created by Python code, but since we only have the pointer,
# we can only wrap it in a generic way and lose the original Python
# class.
-class _GenericComponentClass(object._Object):
+class _GenericComponentClass(object._SharedObject):
@property
def name(self):
name = native_bt.component_class_get_name(self._ptr)
# This is analogous to _GenericSourceComponentClass, but for source
# component objects.
-class _GenericSourceComponent(object._Object, _SourceComponent):
+class _GenericSourceComponent(object._SharedObject, _SourceComponent):
@property
def output_ports(self):
return _ComponentPorts(False, self,
# This is analogous to _GenericFilterComponentClass, but for filter
# component objects.
-class _GenericFilterComponent(object._Object, _FilterComponent):
+class _GenericFilterComponent(object._SharedObject, _FilterComponent):
@property
def output_ports(self):
return _ComponentPorts(False, self,
# This is analogous to _GenericSinkComponentClass, but for sink
# component objects.
-class _GenericSinkComponent(object._Object, _SinkComponent):
+class _GenericSinkComponent(object._SharedObject, _SinkComponent):
@property
def input_ports(self):
return _ComponentPorts(False, self,
return obj
-class _Connection(object._Object):
+class _Connection(object._SharedObject):
@staticmethod
def _downstream_port(ptr):
port_ptr = native_bt.connection_get_downstream_port(ptr)
return False
return self.addr == other.addr
-
-
-class _PrivateConnection(object._PrivateObject, _Connection):
- def create_message_iterator(self, message_types=None):
- msg_types = bt2.message._msg_types_from_msg_classes(message_types)
- status, msg_iter_ptr = native_bt.py3_create_priv_conn_msg_iter(int(self._ptr),
- msg_types)
- _handle_status(status, 'cannot create message iterator object')
- assert(msg_iter_ptr)
- return bt2.message_iterator._PrivateConnectionMessageIterator._create_from_ptr(msg_iter_ptr)
-
- @property
- def is_ended(self):
- return self._is_ended(self._pub_ptr)
-
- @property
- def downstream_port(self):
- return self._downstream_port(self._pub_ptr)
-
- @property
- def upstream_port(self):
- return self._upstream_port(self._pub_ptr)
import bt2
-class CtfWriterClock(object._Object):
+class CtfWriterClock(bt2.object._SharedObject):
def __init__(self, name, description=None, frequency=None, precision=None,
offset=None, is_absolute=None, uuid=None):
utils._check_str(name)
return cpy
-class CtfWriter(object._Object):
+class CtfWriter(bt2.object._SharedObject):
def __init__(self, path):
utils._check_str(path)
ptr = native_bt.ctf_writer_create(path)
return _EventClockSnapshotsIterator(self)
-class _Event(object._Object):
+class _Event(object._UniqueObject):
@property
def event_class(self):
return self._event_class
DEBUG = native_bt.EVENT_CLASS_LOG_LEVEL_DEBUG
-class EventClass(object._Object):
+class EventClass(object._SharedObject):
def __init__(self, name, id=None, log_level=None, emf_uri=None,
context_field_class=None, payload_field_class=None):
utils._check_str(name)
return field
-class _Field(object._Object, metaclass=abc.ABCMeta):
+class _Field(object._UniqueObject, metaclass=abc.ABCMeta):
def __copy__(self):
ptr = native_bt.field_copy(self._ptr)
utils._handle_ptr(ptr, 'cannot copy {} field object'.format(self._NAME.lower()))
return _TYPE_ID_TO_OBJ[typeid]._create_from_ptr(ptr)
-class _FieldClass(object._Object, metaclass=abc.ABCMeta):
+class _FieldClass(object._SharedObject, metaclass=abc.ABCMeta):
def __init__(self, ptr):
super().__init__(ptr)
return (self.name, self.lower, self.upper) == (other.name, other.lower, other.upper)
-class _EnumerationFieldClassMappingIterator(object._Object,
- collections.abc.Iterator):
+class _EnumerationFieldClassMappingIterator(object._SharedObject,
+ collections.abc.Iterator):
def __init__(self, iter_ptr, is_signed):
super().__init__(iter_ptr)
self._is_signed = is_signed
pass
-class Graph(object._Object):
+class Graph(object._SharedObject):
def __init__(self):
ptr = native_bt.graph_create()
return msg_types
-class _Message(object._Object):
+class _Message(object._SharedObject):
pass
raise NotImplementedError
-class _GenericMessageIterator(object._Object, _MessageIterator):
+class _GenericMessageIterator(object._SharedObject, _MessageIterator):
def _get_msg(self):
msg_ptr = native_bt.message_iterator_get_message(self._ptr)
utils._handle_ptr(msg_ptr, "cannot get message iterator object's current message object")
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-from bt2 import native_bt
-import abc
+class _BaseObject:
+ # Ensure that the object always has _ptr set, even if it throws during
+ # construction.
+
+ def __new__(cls, *args, **kwargs):
+ obj = super().__new__(cls)
+ obj._ptr = None
+ return obj
-class _Object:
def __init__(self, ptr):
self._ptr = ptr
def addr(self):
return int(self._ptr)
+ def __repr__(self):
+ return '<{}.{} object @ {}>'.format(self.__class__.__module__,
+ self.__class__.__name__,
+ hex(self.addr))
+
+ def __copy__(self):
+ raise NotImplementedError
+
+ def __deepcopy__(self, memo):
+ raise NotImplementedError
+
+
+# A Python object that is itself not refcounted, but is wholly owned by an
+# object that is itself refcounted (a _SharedObject). A Babeltrace unique
+# object gets destroyed once its owner gets destroyed (its refcount drops to
+# 0).
+#
+# In the Python bindings, to avoid having to deal with issues with the lifetime
+# of unique objects, we make it so acquiring a reference on a unique object
+# acquires a reference on its owner.
+
+class _UniqueObject(_BaseObject):
+
+ # Create a _UniqueObject.
+ #
+ # - ptr: SWIG Object, pointer to the unique object.
+ # - owner_ptr: SWIG Object, pointer to the owner of the unique
+ # object. A new reference is acquired.
+ # - owner_get_ref: Callback to get a reference on the owner
+ # - owner_put_ref: Callback to put a reference on the owner.
+
@classmethod
- def _create_from_ptr(cls, ptr):
+ def _create_from_ptr_and_get_ref(cls, ptr, owner_ptr,
+ owner_get_ref, owner_put_ref):
obj = cls.__new__(cls)
obj._ptr = ptr
+ obj._owner_ptr = owner_ptr
+ obj._owner_put_ref = owner_put_ref
+ owner_get_ref(obj._owner_ptr)
return obj
- def _get(self):
- native_bt.get(self._ptr)
-
def __del__(self):
- ptr = getattr(self, '_ptr', None)
- native_bt.put(ptr)
- self._ptr = None
+ self._owner_put_ref(self._owner_ptr)
- def __repr__(self):
- return '<{}.{} object @ {}>'.format(self.__class__.__module__,
- self.__class__.__name__,
- hex(self.addr))
+# Python object that owns a reference to a Babeltrace object.
+class _SharedObject(_BaseObject):
-class _PrivateObject:
- def __del__(self):
- pub_ptr = getattr(self, '_pub_ptr', None)
- native_bt.put(pub_ptr)
- self._pub_ptr = None
- super().__del__()
+ # Get a new reference on ptr.
+ #
+ # This must be implemented by subclasses to work correctly with a pointer
+ # of the native type they wrap.
+ @staticmethod
+ def _get_ref(ptr):
+ raise NotImplementedError
-class _Freezable(metaclass=abc.ABCMeta):
- @property
- def is_frozen(self):
- return self._is_frozen()
+ # Put a reference on ptr.
+ #
+ # This must be implemented by subclasses to work correctly with a pointer
+ # of the native type they wrap.
- @property
- def frozen(self):
- return self.is_frozen
+ @staticmethod
+ def _put_ref(ptr):
+ raise NotImplementedError
- def freeze(self):
- self._freeze()
+ # Create a _SharedObject from an existing reference.
+ #
+ # This assumes that the caller owns a reference to the Babeltrace object
+ # and transfers this ownership to the newly created Python object.
- @abc.abstractmethod
- def _is_frozen(self):
- pass
+ @classmethod
+ def _create_from_ptr(cls, ptr_owned):
+ obj = cls.__new__(cls)
+ obj._ptr = ptr_owned
+ return obj
- @abc.abstractmethod
- def _freeze(self):
- pass
+ # Like _create_from_ptr, but acquire a new reference rather than
+ # stealing the caller's reference.
+
+ @classmethod
+ def _create_from_ptr_and_get_ref(cls, ptr):
+ obj = cls._create_from_ptr(ptr)
+ cls._get_ref(obj._ptr)
+ return obj
+
+ def __del__(self):
+ self._put_ref(self._ptr)
import bt2
-class _Packet(object._Object):
+class _Packet(object._SharedObject):
@property
def stream(self):
stream_ptr = native_bt.packet_get_stream(self._ptr)
return _Plugin._create_from_ptr(ptr)
-class _PluginSet(object._Object, collections.abc.Sequence):
+class _PluginSet(object._SharedObject, collections.abc.Sequence):
def __len__(self):
count = native_bt.plugin_set_get_plugin_count(self._ptr)
assert(count >= 0)
return _PluginComponentClassesIterator(self)
-class _Plugin(object._Object):
+class _Plugin(object._SharedObject):
@property
def name(self):
name = native_bt.plugin_get_name(self._ptr)
return obj
-class _Port(object._Object):
+class _Port(object._SharedObject):
@staticmethod
def _name(ptr):
name = native_bt.port_get_name(ptr)
return bt2.message_iterator._OutputPortMessageIterator._create_from_ptr(msg_iter_ptr)
-class _PrivatePort(object._PrivateObject, _Port):
+class _PrivatePort(_Port):
@property
def name(self):
return self._name(self._pub_ptr)
import bt2
-class QueryExecutor(object._Object):
+class QueryExecutor(object._SharedObject):
def _handle_status(self, status, gen_error_msg):
if status == native_bt.QUERY_STATUS_AGAIN:
raise bt2.TryAgain
return cls._create_from_ptr(stream_ptr)
-class _StreamBase(object._Object):
+class _StreamBase(object._SharedObject):
@property
def stream_class(self):
stream_class_ptr = native_bt.stream_get_class(self._ptr)
return ev_id
-class StreamClass(object._Object, collections.abc.Mapping):
+class StreamClass(object._SharedObject, collections.abc.Mapping):
def __init__(self, name=None, id=None, packet_context_field_class=None,
event_header_field_class=None, event_context_field_class=None,
event_classes=None):
return _TraceEnvIterator(self)
-class Trace(object._Object, collections.abc.Mapping):
+class Trace(object._SharedObject, collections.abc.Mapping):
def __init__(self, name=None, native_byte_order=None, env=None,
packet_header_field_class=None, clock_classes=None,
stream_classes=None):
raise TypeError("cannot create value object from '{}' object".format(value.__class__.__name__))
-class _Value(object._Object, object._Freezable, metaclass=abc.ABCMeta):
+class _Value(object._SharedObject, metaclass=abc.ABCMeta):
def __eq__(self, other):
if other is None:
# self is never the null value object