From 4acc866e829881299a13d0aa8e28b93807549975 Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Tue, 23 Jul 2019 02:08:59 -0400 Subject: [PATCH] bt2: rename CreationError to MemoryError, handle it in and out of Python bindings Babeltrace API calls can explicitly return the MEMORY_ERROR status, which is currently converted to a bt2.Error in Python. If this bt2.Error goes back to the native side of the bindings, is is converted back to the ERROR status. This is not ideal, as the status value should stay MEMORY_ERROR when unwinding the stack. Also, when creation functions fail (return NULL/None), we currently raise a CreationError. Those creation functions only return NULL/None if there were memory issues, there is not other way they can legitimately fail (otherwise they would return a status). So it would make sense for this to be reported as a MEMORY_ERROR. To address these two issues, this patch: - renames bt2.CreationError to bt2.MemoryError - makes utils._handle_func_status raise a bt2.MemoryError when receiving the MEMORY_ERROR status - makes the native bindings return MEMORY_ERROR when catching a bt2.MemoryError Since there's no easy way to generate an actual MemoryError, I tested this manually by hacking bt_graph_create to make it fail. Change-Id: I4969e8ccd9618d8361fe45d0973df980bc9b7abd Signed-off-by: Simon Marchi Reviewed-on: https://review.lttng.org/c/babeltrace/+/1751 Tested-by: jenkins Reviewed-by: Philippe Proulx --- src/bindings/python/bt2/bt2/__init__.py.in | 4 ++-- src/bindings/python/bt2/bt2/component.py | 6 +++--- src/bindings/python/bt2/bt2/field_class.py | 2 +- src/bindings/python/bt2/bt2/graph.py | 4 ++-- src/bindings/python/bt2/bt2/integer_range_set.py | 2 +- src/bindings/python/bt2/bt2/message_iterator.py | 16 ++++++++-------- .../python/bt2/bt2/native_bt_component_class.i | 12 +++++++++++- src/bindings/python/bt2/bt2/port.py | 2 +- src/bindings/python/bt2/bt2/query_executor.py | 2 +- src/bindings/python/bt2/bt2/stream.py | 2 +- src/bindings/python/bt2/bt2/trace.py | 2 +- src/bindings/python/bt2/bt2/trace_class.py | 4 ++-- src/bindings/python/bt2/bt2/utils.py | 8 ++++---- src/bindings/python/bt2/bt2/value.py | 2 +- 14 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/bindings/python/bt2/bt2/__init__.py.in b/src/bindings/python/bt2/bt2/__init__.py.in index ba17f1be..e98e4fb0 100644 --- a/src/bindings/python/bt2/bt2/__init__.py.in +++ b/src/bindings/python/bt2/bt2/__init__.py.in @@ -68,8 +68,8 @@ from bt2.value import _IntegerValue from bt2.clock_snapshot import _UnknownClockSnapshot -class CreationError(Error): - '''Raised when object creation fails due to memory issues.''' +class MemoryError(Error): + '''Raised when an operation fails due to memory issues.''' class InvalidObject(Exception): diff --git a/src/bindings/python/bt2/bt2/component.py b/src/bindings/python/bt2/bt2/component.py index 07cccec9..cd1cf2dd 100644 --- a/src/bindings/python/bt2/bt2/component.py +++ b/src/bindings/python/bt2/bt2/component.py @@ -499,7 +499,7 @@ class _UserComponentType(type): ) if cc_ptr is None: - raise bt2.CreationError( + raise bt2.MemoryError( "cannot create component class '{}'".format(class_name) ) @@ -677,7 +677,7 @@ class _UserComponent(metaclass=_UserComponentType): tc_ptr = native_bt.trace_class_create(ptr) if tc_ptr is None: - raise bt2.CreationError('could not create trace class') + raise bt2.MemoryError('could not create trace class') tc = bt2._TraceClass._create_from_ptr(tc_ptr) tc._assigns_automatic_stream_class_id = assigns_automatic_stream_class_id @@ -698,7 +698,7 @@ class _UserComponent(metaclass=_UserComponentType): cc_ptr = native_bt.clock_class_create(ptr) if cc_ptr is None: - raise bt2.CreationError('could not create clock class') + raise bt2.MemoryError('could not create clock class') cc = bt2.clock_class._ClockClass._create_from_ptr(cc_ptr) diff --git a/src/bindings/python/bt2/bt2/field_class.py b/src/bindings/python/bt2/bt2/field_class.py index 06980b39..7f251368 100644 --- a/src/bindings/python/bt2/bt2/field_class.py +++ b/src/bindings/python/bt2/bt2/field_class.py @@ -46,7 +46,7 @@ class _FieldClass(object._SharedObject): def _check_create_status(self, ptr): if ptr is None: - raise bt2.CreationError( + raise bt2.MemoryError( 'cannot create {} field class object'.format(self._NAME.lower()) ) diff --git a/src/bindings/python/bt2/bt2/graph.py b/src/bindings/python/bt2/bt2/graph.py index 870ddb38..23467468 100644 --- a/src/bindings/python/bt2/bt2/graph.py +++ b/src/bindings/python/bt2/bt2/graph.py @@ -73,7 +73,7 @@ class Graph(object._SharedObject): ptr = native_bt.graph_create() if ptr is None: - raise bt2.CreationError('cannot create graph object') + raise bt2.MemoryError('cannot create graph object') super().__init__(ptr) @@ -196,6 +196,6 @@ class Graph(object._SharedObject): ) if msg_iter_ptr is None: - raise bt2.CreationError('cannot create output port message iterator') + raise bt2.MemoryError('cannot create output port message iterator') return bt2.message_iterator._OutputPortMessageIterator(msg_iter_ptr) diff --git a/src/bindings/python/bt2/bt2/integer_range_set.py b/src/bindings/python/bt2/bt2/integer_range_set.py index f7222fef..913422c1 100644 --- a/src/bindings/python/bt2/bt2/integer_range_set.py +++ b/src/bindings/python/bt2/bt2/integer_range_set.py @@ -72,7 +72,7 @@ class _IntegerRangeSet(object._SharedObject, collections.abc.MutableSet): ptr = self._create_range_set() if ptr is None: - raise bt2.CreationError('cannot create range set object') + raise bt2.MemoryError('cannot create range set object') super().__init__(ptr) diff --git a/src/bindings/python/bt2/bt2/message_iterator.py b/src/bindings/python/bt2/bt2/message_iterator.py index 9d3a4d22..4457fc58 100644 --- a/src/bindings/python/bt2/bt2/message_iterator.py +++ b/src/bindings/python/bt2/bt2/message_iterator.py @@ -220,7 +220,7 @@ class _UserMessageIterator(_MessageIterator): ) if ptr is None: - raise bt2.CreationError('cannot create event message object') + raise bt2.MemoryError('cannot create event message object') return bt2.message._EventMessage(ptr) @@ -231,7 +231,7 @@ class _UserMessageIterator(_MessageIterator): ) if ptr is None: - raise bt2.CreationError('cannot create inactivity message object') + raise bt2.MemoryError('cannot create inactivity message object') return bt2.message._MessageIteratorInactivityMessage(ptr) @@ -240,7 +240,7 @@ class _UserMessageIterator(_MessageIterator): ptr = native_bt.message_stream_beginning_create(self._bt_ptr, stream._ptr) if ptr is None: - raise bt2.CreationError('cannot create stream beginning message object') + raise bt2.MemoryError('cannot create stream beginning message object') msg = bt2.message._StreamBeginningMessage(ptr) @@ -254,7 +254,7 @@ class _UserMessageIterator(_MessageIterator): ptr = native_bt.message_stream_end_create(self._bt_ptr, stream._ptr) if ptr is None: - raise bt2.CreationError('cannot create stream end message object') + raise bt2.MemoryError('cannot create stream end message object') msg = bt2.message._StreamEndMessage(ptr) @@ -285,7 +285,7 @@ class _UserMessageIterator(_MessageIterator): ptr = native_bt.message_packet_beginning_create(self._bt_ptr, packet._ptr) if ptr is None: - raise bt2.CreationError('cannot create packet beginning message object') + raise bt2.MemoryError('cannot create packet beginning message object') return bt2.message._PacketBeginningMessage(ptr) @@ -311,7 +311,7 @@ class _UserMessageIterator(_MessageIterator): ptr = native_bt.message_packet_end_create(self._bt_ptr, packet._ptr) if ptr is None: - raise bt2.CreationError('cannot create packet end message object') + raise bt2.MemoryError('cannot create packet end message object') return bt2.message._PacketEndMessage(ptr) @@ -343,7 +343,7 @@ class _UserMessageIterator(_MessageIterator): ptr = native_bt.message_discarded_events_create(self._bt_ptr, stream._ptr) if ptr is None: - raise bt2.CreationError('cannot discarded events message object') + raise bt2.MemoryError('cannot discarded events message object') msg = bt2.message._DiscardedEventsMessage(ptr) @@ -380,7 +380,7 @@ class _UserMessageIterator(_MessageIterator): ptr = native_bt.message_discarded_packets_create(self._bt_ptr, stream._ptr) if ptr is None: - raise bt2.CreationError('cannot discarded packets message object') + raise bt2.MemoryError('cannot discarded packets message object') msg = bt2.message._DiscardedPacketsMessage(ptr) diff --git a/src/bindings/python/bt2/bt2/native_bt_component_class.i b/src/bindings/python/bt2/bt2/native_bt_component_class.i index b9e91a4a..dac194b3 100644 --- a/src/bindings/python/bt2/bt2/native_bt_component_class.i +++ b/src/bindings/python/bt2/bt2/native_bt_component_class.i @@ -94,6 +94,7 @@ PyObject *lookup_cc_ptr_to_py_cls(const bt_component_class *bt_cc) static PyObject *py_mod_bt2 = NULL; static PyObject *py_mod_bt2_exc_error_type = NULL; +static PyObject *py_mod_bt2_exc_memory_error = NULL; static PyObject *py_mod_bt2_exc_try_again_type = NULL; static PyObject *py_mod_bt2_exc_stop_type = NULL; static PyObject *py_mod_bt2_exc_msg_iter_canceled_type = NULL; @@ -117,6 +118,9 @@ void bt_bt2_cc_init_from_bt2(void) py_mod_bt2_exc_error_type = PyObject_GetAttrString(py_mod_bt2, "Error"); BT_ASSERT(py_mod_bt2_exc_error_type); + py_mod_bt2_exc_memory_error = + PyObject_GetAttrString(py_mod_bt2, "MemoryError"); + BT_ASSERT(py_mod_bt2_exc_memory_error); py_mod_bt2_exc_try_again_type = PyObject_GetAttrString(py_mod_bt2, "TryAgain"); BT_ASSERT(py_mod_bt2_exc_try_again_type); @@ -408,7 +412,13 @@ int py_exc_to_status(bt_self_component_class *self_component_class, log_exception_and_maybe_append_error(BT_LOG_WARNING, true, self_component_class, self_component, self_message_iterator, module_name); - status = __BT_FUNC_STATUS_ERROR; + + if (PyErr_GivenExceptionMatches(exc, + py_mod_bt2_exc_memory_error)) { + status = __BT_FUNC_STATUS_MEMORY_ERROR; + } else { + status = __BT_FUNC_STATUS_ERROR; + } } end: diff --git a/src/bindings/python/bt2/bt2/port.py b/src/bindings/python/bt2/bt2/port.py index 1d649b35..ecee18ce 100644 --- a/src/bindings/python/bt2/bt2/port.py +++ b/src/bindings/python/bt2/bt2/port.py @@ -119,7 +119,7 @@ class _UserComponentInputPort(_UserComponentPort, _InputPort): self._ptr ) if msg_iter_ptr is None: - raise bt2.CreationError('cannot create message iterator object') + raise bt2.MemoryError('cannot create message iterator object') return bt2.message_iterator._UserComponentInputPortMessageIterator(msg_iter_ptr) diff --git a/src/bindings/python/bt2/bt2/query_executor.py b/src/bindings/python/bt2/bt2/query_executor.py index 17ddd97e..a59bc793 100644 --- a/src/bindings/python/bt2/bt2/query_executor.py +++ b/src/bindings/python/bt2/bt2/query_executor.py @@ -34,7 +34,7 @@ class QueryExecutor(object._SharedObject): ptr = native_bt.query_executor_create() if ptr is None: - raise bt2.CreationError('cannot create query executor object') + raise bt2.MemoryError('cannot create query executor object') super().__init__(ptr) diff --git a/src/bindings/python/bt2/bt2/stream.py b/src/bindings/python/bt2/bt2/stream.py index 70011758..2e75990d 100644 --- a/src/bindings/python/bt2/bt2/stream.py +++ b/src/bindings/python/bt2/bt2/stream.py @@ -62,6 +62,6 @@ class _Stream(bt2.object._SharedObject): packet_ptr = native_bt.packet_create(self._ptr) if packet_ptr is None: - raise bt2.CreationError('cannot create packet object') + raise bt2.MemoryError('cannot create packet object') return bt2.packet._Packet._create_from_ptr(packet_ptr) diff --git a/src/bindings/python/bt2/bt2/trace.py b/src/bindings/python/bt2/bt2/trace.py index 86bd90d0..5516a986 100644 --- a/src/bindings/python/bt2/bt2/trace.py +++ b/src/bindings/python/bt2/bt2/trace.py @@ -166,7 +166,7 @@ class _Trace(object._SharedObject, collections.abc.Mapping): ) if stream_ptr is None: - raise bt2.CreationError('cannot create stream object') + raise bt2.MemoryError('cannot create stream object') stream = bt2.stream._Stream._create_from_ptr(stream_ptr) diff --git a/src/bindings/python/bt2/bt2/trace_class.py b/src/bindings/python/bt2/bt2/trace_class.py index 8032ed11..798dbee0 100644 --- a/src/bindings/python/bt2/bt2/trace_class.py +++ b/src/bindings/python/bt2/bt2/trace_class.py @@ -69,7 +69,7 @@ class _TraceClass(object._SharedObject, collections.abc.Mapping): trace_ptr = native_bt.trace_create(self._ptr) if trace_ptr is None: - raise bt2.CreationError('cannot create trace class object') + raise bt2.MemoryError('cannot create trace class object') trace = bt2.trace._Trace._create_from_ptr(trace_ptr) @@ -204,7 +204,7 @@ class _TraceClass(object._SharedObject, collections.abc.Mapping): def _check_create_status(self, ptr, type_name): if ptr is None: - raise bt2.CreationError('cannot create {} field class'.format(type_name)) + raise bt2.MemoryError('cannot create {} field class'.format(type_name)) def _create_integer_field_class( self, create_func, py_cls, type_name, field_value_range, preferred_display_base diff --git a/src/bindings/python/bt2/bt2/utils.py b/src/bindings/python/bt2/bt2/utils.py index 8d5c4e2f..023ff0a8 100644 --- a/src/bindings/python/bt2/bt2/utils.py +++ b/src/bindings/python/bt2/bt2/utils.py @@ -135,12 +135,12 @@ def _handle_func_status(status, msg=None): # no error return - if ( - status == native_bt.__BT_FUNC_STATUS_ERROR - or status == native_bt.__BT_FUNC_STATUS_MEMORY_ERROR - ): + if status == native_bt.__BT_FUNC_STATUS_ERROR: assert msg is not None raise bt2.Error(msg) + elif status == native_bt.__BT_FUNC_STATUS_MEMORY_ERROR: + assert msg is not None + raise bt2.MemoryError(msg) elif status == native_bt.__BT_FUNC_STATUS_END: if msg is None: raise bt2.Stop diff --git a/src/bindings/python/bt2/bt2/value.py b/src/bindings/python/bt2/bt2/value.py index 9ba01086..2c947660 100644 --- a/src/bindings/python/bt2/bt2/value.py +++ b/src/bindings/python/bt2/bt2/value.py @@ -92,7 +92,7 @@ class _Value(object._SharedObject, metaclass=abc.ABCMeta): def _check_create_status(self, ptr): if ptr is None: - raise bt2.CreationError( + raise bt2.MemoryError( 'cannot create {} value object'.format(self._NAME.lower()) ) -- 2.34.1