From 4212232cdba456554343e71b2449066e597d0f5b Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Fri, 2 Aug 2019 13:25:42 -0400 Subject: [PATCH] bt2: put SWIG interface file C code in separate files This patch moves any code in `%{ %}` blocks within SWIG interface files (`.i`) to their own files. For a SWIG interface file named `file.i`, the code is moved to `file.i.h`. In `file.i`, there is: %{ #include "file.i.h" %} This helps with text editors which do not always know how to highlight the code of a `.i` file. In `Makefile.am`, the `.i.h` files are added to the `SWIG_INTERFACE_FILES` variable as they can be considered part of the SWIG interface files. Signed-off-by: Philippe Proulx Change-Id: I28975c9b3c827e65ba77af9134521ce1b920d740 Reviewed-on: https://review.lttng.org/c/babeltrace/+/1812 Reviewed-by: Simon Marchi Tested-by: jenkins --- src/bindings/python/bt2/Makefile.am | 7 + .../bt2/bt2/native_bt_component_class.i | 1388 +--------------- .../bt2/bt2/native_bt_component_class.i.h | 1411 +++++++++++++++++ src/bindings/python/bt2/bt2/native_bt_graph.i | 492 +----- .../python/bt2/bt2/native_bt_graph.i.h | 515 ++++++ .../bt2/bt2/native_bt_message_iterator.i | 85 +- .../bt2/bt2/native_bt_message_iterator.i.h | 108 ++ .../python/bt2/bt2/native_bt_plugin.i | 93 +- .../python/bt2/bt2/native_bt_plugin.i.h | 110 ++ src/bindings/python/bt2/bt2/native_bt_trace.i | 41 +- .../python/bt2/bt2/native_bt_trace.i.h | 65 + .../python/bt2/bt2/native_bt_trace_class.i | 42 +- .../python/bt2/bt2/native_bt_trace_class.i.h | 66 + src/bindings/python/bt2/bt2/native_bt_value.i | 44 +- .../python/bt2/bt2/native_bt_value.i.h | 67 + 15 files changed, 2359 insertions(+), 2175 deletions(-) create mode 100644 src/bindings/python/bt2/bt2/native_bt_component_class.i.h create mode 100644 src/bindings/python/bt2/bt2/native_bt_graph.i.h create mode 100644 src/bindings/python/bt2/bt2/native_bt_message_iterator.i.h create mode 100644 src/bindings/python/bt2/bt2/native_bt_plugin.i.h create mode 100644 src/bindings/python/bt2/bt2/native_bt_trace.i.h create mode 100644 src/bindings/python/bt2/bt2/native_bt_trace_class.i.h create mode 100644 src/bindings/python/bt2/bt2/native_bt_value.i.h diff --git a/src/bindings/python/bt2/Makefile.am b/src/bindings/python/bt2/Makefile.am index 54df1e5f..7c59af32 100644 --- a/src/bindings/python/bt2/Makefile.am +++ b/src/bindings/python/bt2/Makefile.am @@ -11,6 +11,7 @@ SWIG_INTERFACE_FILES = \ bt2/native_bt_clock_snapshot.i \ bt2/native_bt_component.i \ bt2/native_bt_component_class.i \ + bt2/native_bt_component_class.i.h \ bt2/native_bt_connection.i \ bt2/native_bt_error.i \ bt2/native_bt_event.i \ @@ -19,20 +20,26 @@ SWIG_INTERFACE_FILES = \ bt2/native_bt_field_class.i \ bt2/native_bt_field_path.i \ bt2/native_bt_graph.i \ + bt2/native_bt_graph.i.h \ bt2/native_bt_integer_range_set.i \ bt2/native_bt_interrupter.i \ bt2/native_bt_logging.i \ bt2/native_bt_message.i \ bt2/native_bt_message_iterator.i \ + bt2/native_bt_message_iterator.i.h \ bt2/native_bt_packet.i \ bt2/native_bt_plugin.i \ + bt2/native_bt_plugin.i.h \ bt2/native_bt_port.i \ bt2/native_bt_query_exec.i \ bt2/native_bt_stream.i \ bt2/native_bt_stream_class.i \ bt2/native_bt_trace.i \ + bt2/native_bt_trace.i.h \ bt2/native_bt_trace_class.i \ + bt2/native_bt_trace_class.i.h \ bt2/native_bt_value.i \ + bt2/native_bt_value.i.h \ bt2/native_bt_version.i # Non-generated files built into the native library. 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 784b0f40..ea8e9589 100644 --- a/src/bindings/python/bt2/bt2/native_bt_component_class.i +++ b/src/bindings/python/bt2/bt2/native_bt_component_class.i @@ -35,1393 +35,7 @@ %include %{ -#include "logging/comp-logging.h" - -/* - * This hash table associates a BT component class object address to a - * user-defined Python class (PyObject *). The keys and values are NOT - * owned by this hash table. The Python class objects are owned by the - * Python module, which should not be unloaded until it is not possible - * to create a user Python component anyway. - * - * This hash table is written to when a user-defined Python component - * class is created by one of the bt_bt2_component_class_*_create() - * functions. - * - * This function is read from when a user calls bt_component_create() - * with a component class pointer created by one of the functions above. - * In this case, the original Python class needs to be found to - * instantiate it and associate the created Python component object with - * a BT component object instance. - */ - -static GHashTable *bt_cc_ptr_to_py_cls; - -static -void register_cc_ptr_to_py_cls(struct bt_component_class *bt_cc, - PyObject *py_cls) -{ - if (!bt_cc_ptr_to_py_cls) { - /* - * Lazy-initializing this GHashTable because GLib - * might not be initialized yet and it needs to be - * before we call g_hash_table_new() - */ - BT_LOGD_STR("Creating native component class to Python component class hash table."); - bt_cc_ptr_to_py_cls = g_hash_table_new(g_direct_hash, g_direct_equal); - BT_ASSERT(bt_cc_ptr_to_py_cls); - } - - g_hash_table_insert(bt_cc_ptr_to_py_cls, (gpointer) bt_cc, - (gpointer) py_cls); -} - -static -PyObject *lookup_cc_ptr_to_py_cls(const bt_component_class *bt_cc) -{ - if (!bt_cc_ptr_to_py_cls) { - BT_LOGW("Cannot look up Python component class because hash table is NULL: " - "comp-cls-addr=%p", bt_cc); - return NULL; - } - - return (PyObject *) g_hash_table_lookup(bt_cc_ptr_to_py_cls, - (gconstpointer) bt_cc); -} - - -/* - * Useful Python objects. - */ - -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_unknown_object_type = NULL; - -static -void bt_bt2_cc_init_from_bt2(void) -{ - /* - * This is called once the bt2 package is loaded. - * - * Those modules and functions are needed while the package is - * used. Loading them here is safe because we know the bt2 - * package is imported, and we know that the user cannot use the - * code here without importing bt2 first. - */ - py_mod_bt2 = PyImport_ImportModule("bt2"); - BT_ASSERT(py_mod_bt2); - 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); - py_mod_bt2_exc_stop_type = - PyObject_GetAttrString(py_mod_bt2, "Stop"); - BT_ASSERT(py_mod_bt2_exc_stop_type); - py_mod_bt2_exc_unknown_object_type = - PyObject_GetAttrString(py_mod_bt2, "UnknownObject"); - BT_ASSERT(py_mod_bt2_exc_unknown_object_type); -} - -static -void bt_bt2_cc_exit_handler(void) -{ - /* - * This is an exit handler (set by the bt2 package). - * - * We only give back the references that we took in - * bt_bt2_cc_init_from_bt2() here. The global variables continue - * to exist for the code of this file, but they are now borrowed - * references. If this code is executed, it means that somehow - * the modules are still loaded, so it should be safe to use - * them even without a strong reference. - * - * We cannot do this in the library's destructor because it - * gets executed once Python is already finalized. - */ - Py_XDECREF(py_mod_bt2); - Py_XDECREF(py_mod_bt2_exc_error_type); - Py_XDECREF(py_mod_bt2_exc_try_again_type); - Py_XDECREF(py_mod_bt2_exc_stop_type); - Py_XDECREF(py_mod_bt2_exc_unknown_object_type); -} - - -/* Library destructor */ - -__attribute__((destructor)) -static -void native_comp_class_dtor(void) { - /* Destroy component class association hash table */ - if (bt_cc_ptr_to_py_cls) { - BT_LOGD_STR("Destroying native component class to Python component class hash table."); - g_hash_table_destroy(bt_cc_ptr_to_py_cls); - } -} - -static -void restore_current_thread_error_and_append_exception_chain_recursive( - int active_log_level, PyObject *py_exc_value, - bt_self_component_class *self_component_class, - bt_self_component *self_component, - bt_self_message_iterator *self_message_iterator, - const char *module_name) -{ - PyObject *py_exc_cause_value; - PyObject *py_exc_type = NULL; - PyObject *py_exc_tb = NULL; - GString *gstr = NULL; - - /* If this exception has a cause, handle that one first. */ - py_exc_cause_value = PyException_GetCause(py_exc_value); - if (py_exc_cause_value) { - restore_current_thread_error_and_append_exception_chain_recursive( - active_log_level, py_exc_cause_value, - self_component_class, self_component, - self_message_iterator, module_name); - } - - /* - * If the raised exception is a bt2._Error, restore the wrapped error. - */ - if (PyErr_GivenExceptionMatches(py_exc_value, py_mod_bt2_exc_error_type)) { - PyObject *py_error_swig_ptr; - const bt_error *error; - int ret; - - /* - * We never raise a bt2._Error with a cause: it should be the - * end of the chain. - */ - BT_ASSERT(!py_exc_cause_value); - - /* - * We steal the error object from the exception, to move - * it back as the current thread's error. - */ - py_error_swig_ptr = PyObject_GetAttrString(py_exc_value, "_ptr"); - BT_ASSERT(py_error_swig_ptr); - - ret = PyObject_SetAttrString(py_exc_value, "_ptr", Py_None); - BT_ASSERT(ret == 0); - - ret = SWIG_ConvertPtr(py_error_swig_ptr, (void **) &error, - SWIGTYPE_p_bt_error, 0); - BT_ASSERT(ret == 0); - - BT_CURRENT_THREAD_MOVE_ERROR_AND_RESET(error); - - Py_DECREF(py_error_swig_ptr); - } - - py_exc_type = PyObject_Type(py_exc_value); - py_exc_tb = PyException_GetTraceback(py_exc_value); - - gstr = bt_py_common_format_exception(py_exc_type, py_exc_value, - py_exc_tb, active_log_level, false); - if (!gstr) { - /* bt_py_common_format_exception has already warned. */ - goto end; - } - - if (self_component_class) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT_CLASS( - self_component_class, "%s", gstr->str); - } else if (self_component) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT( - self_component, "%s", gstr->str); - } else if (self_message_iterator) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR( - self_message_iterator, "%s", gstr->str); - } else { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN( - module_name, "%s", gstr->str); - } - -end: - if (gstr) { - g_string_free(gstr, TRUE); - } - - Py_XDECREF(py_exc_cause_value); - Py_XDECREF(py_exc_type); - Py_XDECREF(py_exc_tb); -} - -/* - * If you have the following code: - * - * try: - * try: - * something_that_raises_bt2_error() - * except bt2._Error as e1: - * raise ValueError from e1 - * except ValueError as e2: - * raise TypeError from e2 - * - * We will have the following exception chain: - * - * TypeError -> ValueError -> bt2._Error - * - * Where the TypeError is the current exception (obtained from PyErr_Fetch). - * - * The bt2._Error contains a `struct bt_error *` that used to be the current - * thread's error, at the moment the exception was raised. - * - * This function gets to the bt2._Error and restores the wrapped - * `struct bt_error *` as the current thread's error. - * - * Then, for each exception in the chain, starting with the oldest one, it adds - * an error cause to the current thread's error. - */ -static -void restore_bt_error_and_append_current_exception_chain( - int active_log_level, - bt_self_component_class *self_component_class, - bt_self_component *self_component, - bt_self_message_iterator *self_message_iterator, - const char *module_name) -{ - BT_ASSERT(PyErr_Occurred()); - - /* Used to access and restore the current exception. */ - PyObject *py_exc_type; - PyObject *py_exc_value; - PyObject *py_exc_tb; - - /* Fetch and normalize the Python exception. */ - PyErr_Fetch(&py_exc_type, &py_exc_value, &py_exc_tb); - PyErr_NormalizeException(&py_exc_type, &py_exc_value, &py_exc_tb); - BT_ASSERT(py_exc_type); - BT_ASSERT(py_exc_value); - BT_ASSERT(py_exc_tb); - - /* - * Set the exception's traceback so it's possible to get it using - * PyException_GetTraceback in - * restore_current_thread_error_and_append_exception_chain_recursive. - */ - PyException_SetTraceback(py_exc_value, py_exc_tb); - - restore_current_thread_error_and_append_exception_chain_recursive( - active_log_level, py_exc_value, self_component_class, - self_component, self_message_iterator, module_name); - - PyErr_Restore(py_exc_type, py_exc_value, py_exc_tb); -} - -static inline -void log_exception_and_maybe_append_error(int func_log_level, - int active_log_level, bool append_error, - bt_self_component_class *self_component_class, - bt_self_component *self_component, - bt_self_message_iterator *self_message_iterator, - const char *module_name) -{ - GString *gstr; - - BT_ASSERT(PyErr_Occurred()); - gstr = bt_py_common_format_current_exception(active_log_level); - if (!gstr) { - /* bt_py_common_format_current_exception() logs errors */ - goto end; - } - - BT_COMP_LOG_CUR_LVL(func_log_level, active_log_level, self_component, - "%s", gstr->str); - - if (append_error) { - restore_bt_error_and_append_current_exception_chain( - active_log_level, self_component_class, self_component, - self_message_iterator, module_name); - - } - -end: - if (gstr) { - g_string_free(gstr, TRUE); - } -} - -static -bt_logging_level get_self_component_log_level(bt_self_component *self_comp) -{ - return bt_component_get_logging_level( - bt_self_component_as_component(self_comp)); -} - -static -bt_logging_level get_self_message_iterator_log_level( - bt_self_message_iterator *self_msg_iter) -{ - bt_self_component *self_comp = - bt_self_message_iterator_borrow_component(self_msg_iter); - - return get_self_component_log_level(self_comp); -} - -static inline -void loge_exception(const char *module_name, int active_log_level) -{ - log_exception_and_maybe_append_error(BT_LOG_ERROR, active_log_level, - true, NULL, NULL, NULL, module_name); -} - -static -void loge_exception_message_iterator( - bt_self_message_iterator *self_message_iterator) -{ - bt_logging_level log_level = get_self_message_iterator_log_level( - self_message_iterator); - - log_exception_and_maybe_append_error(BT_LOG_ERROR, log_level, - true, NULL, NULL, self_message_iterator, NULL); -} - -static inline -void logw_exception(int active_log_level) -{ - log_exception_and_maybe_append_error(BT_LOG_WARNING, active_log_level, - false, NULL, NULL, NULL, NULL); -} - -static inline -int py_exc_to_status(bt_self_component_class *self_component_class, - bt_self_component *self_component, - bt_self_message_iterator *self_message_iterator, - const char *module_name, int active_log_level) -{ - int status = __BT_FUNC_STATUS_OK; - PyObject *exc = PyErr_Occurred(); - - if (!exc) { - goto end; - } - - if (PyErr_GivenExceptionMatches(exc, - py_mod_bt2_exc_try_again_type)) { - status = __BT_FUNC_STATUS_AGAIN; - } else if (PyErr_GivenExceptionMatches(exc, - py_mod_bt2_exc_stop_type)) { - status = __BT_FUNC_STATUS_END; - } else if (PyErr_GivenExceptionMatches(exc, - py_mod_bt2_exc_unknown_object_type)) { - status = __BT_FUNC_STATUS_UNKNOWN_OBJECT; - } else { - /* - * Unknown exception: convert to general error. - * - * Because we only want to fetch the log level when - * we actually get an exception, and not systematically - * when we call py_exc_to_status() (as py_exc_to_status() - * can return `__BT_FUNC_STATUS_OK`), we get it here - * depending on the actor's type. - */ - if (self_component) { - active_log_level = get_self_component_log_level( - self_component); - } else if (self_message_iterator) { - active_log_level = get_self_message_iterator_log_level( - self_message_iterator); - } - - BT_ASSERT(active_log_level != -1); - log_exception_and_maybe_append_error(BT_LOG_WARNING, - active_log_level, true, - self_component_class, self_component, - self_message_iterator, module_name); - - if (PyErr_GivenExceptionMatches(exc, - py_mod_bt2_exc_memory_error)) { - status = __BT_FUNC_STATUS_MEMORY_ERROR; - } else { - status = __BT_FUNC_STATUS_ERROR; - } - } - -end: - PyErr_Clear(); - return status; -} - -static -int py_exc_to_status_component_class( - bt_self_component_class *self_component_class, - int active_log_level) -{ - return py_exc_to_status(self_component_class, NULL, NULL, NULL, - active_log_level); -} - -static -int py_exc_to_status_component(bt_self_component *self_component) -{ - return py_exc_to_status(NULL, self_component, NULL, NULL, -1); -} - -static -int py_exc_to_status_message_iterator( - bt_self_message_iterator *self_message_iterator) -{ - return py_exc_to_status(NULL, NULL, self_message_iterator, NULL, -1); -} - -/* Component class proxy methods (delegate to the attached Python object) */ - -static -bt_component_class_init_method_status component_class_init( - bt_self_component *self_component, - void *self_component_v, - swig_type_info *self_comp_cls_type_swig_type, - const bt_value *params, - void *init_method_data) -{ - const bt_component *component = bt_self_component_as_component(self_component); - const bt_component_class *component_class = bt_component_borrow_class_const(component); - bt_component_class_init_method_status status = __BT_FUNC_STATUS_OK; - PyObject *py_cls = NULL; - PyObject *py_comp = NULL; - PyObject *py_params_ptr = NULL; - PyObject *py_comp_ptr = NULL; - bt_logging_level log_level = get_self_component_log_level( - self_component); - - (void) init_method_data; - - BT_ASSERT(self_component); - BT_ASSERT(self_component_v); - BT_ASSERT(self_comp_cls_type_swig_type); - - /* - * Get the user-defined Python class which created this - * component's class in the first place (borrowed - * reference). - */ - py_cls = lookup_cc_ptr_to_py_cls(component_class); - if (!py_cls) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, - "Cannot find Python class associated to native component class: " - "comp-cls-addr=%p", component_class); - goto error; - } - - /* Parameters pointer -> SWIG pointer Python object */ - py_params_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(params), - SWIGTYPE_p_bt_value, 0); - if (!py_params_ptr) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, - "Failed to create a SWIG pointer object."); - goto error; - } - - py_comp_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_component_v), - self_comp_cls_type_swig_type, 0); - if (!py_comp_ptr) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, - "Failed to create a SWIG pointer object."); - goto error; - } - - /* - * Do the equivalent of this: - * - * py_comp = py_cls._bt_init_from_native(py_comp_ptr, py_params_ptr) - * - * _UserComponentType._bt_init_from_native() calls the Python - * component object's __init__() function. - */ - py_comp = PyObject_CallMethod(py_cls, - "_bt_init_from_native", "(OO)", py_comp_ptr, py_params_ptr); - if (!py_comp) { - BT_COMP_LOG_CUR_LVL(BT_LOG_WARNING, log_level, self_component, - "Failed to call Python class's _bt_init_from_native() method: " - "py-cls-addr=%p", py_cls); - status = py_exc_to_status_component(self_component); - goto end; - } - - /* - * Our user Python component object is now fully created and - * initialized by the user. Since we just created it, this - * native component is its only (persistent) owner. - */ - bt_self_component_set_data(self_component, py_comp); - py_comp = NULL; - goto end; - -error: - status = __BT_FUNC_STATUS_ERROR; - - /* - * Clear any exception: we're returning a bad status anyway. If - * this call originated from Python (creation from a plugin's - * component class, for example), then the user gets an - * appropriate creation error. - */ - PyErr_Clear(); - -end: - Py_XDECREF(py_comp); - Py_XDECREF(py_params_ptr); - Py_XDECREF(py_comp_ptr); - return status; -} - -/* - * Method of bt_component_class_source to initialize a bt_self_component_source - * of that class. - */ - -static -bt_component_class_init_method_status component_class_source_init( - bt_self_component_source *self_component_source, - const bt_value *params, void *init_method_data) -{ - bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source); - return component_class_init( - self_component, - self_component_source, - SWIGTYPE_p_bt_self_component_source, - params, init_method_data); -} - -static -bt_component_class_init_method_status component_class_filter_init( - bt_self_component_filter *self_component_filter, - const bt_value *params, void *init_method_data) -{ - bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter); - return component_class_init( - self_component, - self_component_filter, - SWIGTYPE_p_bt_self_component_filter, - params, init_method_data); -} - -static -bt_component_class_init_method_status component_class_sink_init( - bt_self_component_sink *self_component_sink, - const bt_value *params, void *init_method_data) -{ - bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink); - return component_class_init( - self_component, - self_component_sink, - SWIGTYPE_p_bt_self_component_sink, - params, init_method_data); -} - -static -void component_class_finalize(bt_self_component *self_component) -{ - PyObject *py_comp = bt_self_component_get_data(self_component); - BT_ASSERT(py_comp); - - /* Call user's _user_finalize() method */ - PyObject *py_method_result = PyObject_CallMethod(py_comp, - "_user_finalize", NULL); - - if (PyErr_Occurred()) { - bt_logging_level log_level = get_self_component_log_level( - self_component); - - BT_COMP_LOG_CUR_LVL(BT_LOG_WARNING, log_level, self_component, - "User component's _user_finalize() method raised an exception: ignoring:"); - logw_exception(log_level); - } - - /* - * Ignore any exception raised by the _user_finalize() method - * because it won't change anything at this point: the component - * is being destroyed anyway. - */ - PyErr_Clear(); - Py_XDECREF(py_method_result); - Py_DECREF(py_comp); -} - -static -void component_class_source_finalize(bt_self_component_source *self_component_source) -{ - bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source); - component_class_finalize(self_component); -} - -static -void component_class_filter_finalize(bt_self_component_filter *self_component_filter) -{ - bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter); - component_class_finalize(self_component); -} - -static -void component_class_sink_finalize(bt_self_component_sink *self_component_sink) -{ - bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink); - component_class_finalize(self_component); -} - -static -bt_bool component_class_can_seek_beginning( - bt_self_message_iterator *self_message_iterator) -{ - PyObject *py_iter; - PyObject *py_result = NULL; - bt_bool can_seek_beginning = false; - - py_iter = bt_self_message_iterator_get_data(self_message_iterator); - BT_ASSERT(py_iter); - - py_result = PyObject_GetAttrString(py_iter, "_bt_can_seek_beginning_from_native"); - - BT_ASSERT(!py_result || PyBool_Check(py_result)); - - if (py_result) { - can_seek_beginning = PyObject_IsTrue(py_result); - } else { - /* - * Once can_seek_beginning can report errors, convert the - * exception to a status. For now, log and return false; - */ - loge_exception_message_iterator(self_message_iterator); - PyErr_Clear(); - } - - Py_XDECREF(py_result); - - return can_seek_beginning; -} - -static -bt_component_class_message_iterator_seek_beginning_method_status -component_class_seek_beginning(bt_self_message_iterator *self_message_iterator) -{ - PyObject *py_iter; - PyObject *py_result; - bt_component_class_message_iterator_seek_beginning_method_status status; - - py_iter = bt_self_message_iterator_get_data(self_message_iterator); - BT_ASSERT(py_iter); - py_result = PyObject_CallMethod(py_iter, "_bt_seek_beginning_from_native", - NULL); - BT_ASSERT(!py_result || py_result == Py_None); - status = py_exc_to_status_message_iterator(self_message_iterator); - Py_XDECREF(py_result); - return status; -} - -static -bt_component_class_port_connected_method_status component_class_port_connected( - bt_self_component *self_component, - void *self_component_port, - swig_type_info *self_component_port_swig_type, - bt_port_type self_component_port_type, - const void *other_port, - swig_type_info *other_port_swig_type) -{ - bt_component_class_port_connected_method_status status; - PyObject *py_comp = NULL; - PyObject *py_self_port_ptr = NULL; - PyObject *py_other_port_ptr = NULL; - PyObject *py_method_result = NULL; - bt_logging_level log_level = get_self_component_log_level( - self_component); - - py_comp = bt_self_component_get_data(self_component); - BT_ASSERT(py_comp); - py_self_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_component_port), - self_component_port_swig_type, 0); - if (!py_self_port_ptr) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, - "Failed to create a SWIG pointer object."); - status = __BT_FUNC_STATUS_MEMORY_ERROR; - goto end; - } - - py_other_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(other_port), - other_port_swig_type, 0); - if (!py_other_port_ptr) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, - "Failed to create a SWIG pointer object."); - status = __BT_FUNC_STATUS_MEMORY_ERROR; - goto end; } - - py_method_result = PyObject_CallMethod(py_comp, - "_bt_port_connected_from_native", "(OiO)", py_self_port_ptr, - self_component_port_type, py_other_port_ptr); - BT_ASSERT(!py_method_result || py_method_result == Py_None); - status = py_exc_to_status_component(self_component); - -end: - Py_XDECREF(py_self_port_ptr); - Py_XDECREF(py_other_port_ptr); - Py_XDECREF(py_method_result); - return status; -} - -static -bt_component_class_port_connected_method_status -component_class_source_output_port_connected( - bt_self_component_source *self_component_source, - bt_self_component_port_output *self_component_port_output, - const bt_port_input *other_port_input) -{ - bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source); - - return component_class_port_connected( - self_component, - self_component_port_output, - SWIGTYPE_p_bt_self_component_port_output, - BT_PORT_TYPE_OUTPUT, - other_port_input, - SWIGTYPE_p_bt_port_input); -} - -static -bt_component_class_port_connected_method_status -component_class_filter_input_port_connected( - bt_self_component_filter *self_component_filter, - bt_self_component_port_input *self_component_port_input, - const bt_port_output *other_port_output) -{ - bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter); - - return component_class_port_connected( - self_component, - self_component_port_input, - SWIGTYPE_p_bt_self_component_port_input, - BT_PORT_TYPE_INPUT, - other_port_output, - SWIGTYPE_p_bt_port_output); -} - -static -bt_component_class_port_connected_method_status -component_class_filter_output_port_connected( - bt_self_component_filter *self_component_filter, - bt_self_component_port_output *self_component_port_output, - const bt_port_input *other_port_input) -{ - bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter); - - return component_class_port_connected( - self_component, - self_component_port_output, - SWIGTYPE_p_bt_self_component_port_output, - BT_PORT_TYPE_OUTPUT, - other_port_input, - SWIGTYPE_p_bt_port_input); -} - -static -bt_component_class_port_connected_method_status -component_class_sink_input_port_connected( - bt_self_component_sink *self_component_sink, - bt_self_component_port_input *self_component_port_input, - const bt_port_output *other_port_output) -{ - bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink); - - return component_class_port_connected( - self_component, - self_component_port_input, - SWIGTYPE_p_bt_self_component_port_input, - BT_PORT_TYPE_INPUT, - other_port_output, - SWIGTYPE_p_bt_port_output); -} - -static -bt_component_class_sink_graph_is_configured_method_status -component_class_sink_graph_is_configured( - bt_self_component_sink *self_component_sink) -{ - PyObject *py_comp = NULL; - PyObject *py_method_result = NULL; - bt_component_class_sink_graph_is_configured_method_status status = __BT_FUNC_STATUS_OK; - bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink); - - py_comp = bt_self_component_get_data(self_component); - py_method_result = PyObject_CallMethod(py_comp, - "_bt_graph_is_configured_from_native", NULL); - BT_ASSERT(!py_method_result || py_method_result == Py_None); - status = py_exc_to_status_component(self_component); - Py_XDECREF(py_method_result); - return status; -} - -static -bt_component_class_query_method_status component_class_query( - const bt_component_class *component_class, - bt_self_component_class *self_component_class, - bt_private_query_executor *priv_query_executor, - const char *object, const bt_value *params, - const bt_value **result) -{ - PyObject *py_cls = NULL; - PyObject *py_params_ptr = NULL; - PyObject *py_priv_query_exec_ptr = NULL; - PyObject *py_query_func = NULL; - PyObject *py_object = NULL; - PyObject *py_results_addr = NULL; - bt_component_class_query_method_status status = __BT_FUNC_STATUS_OK; - const bt_query_executor *query_exec = - bt_private_query_executor_as_query_executor_const( - priv_query_executor); - bt_logging_level log_level = - bt_query_executor_get_logging_level(query_exec); - - py_cls = lookup_cc_ptr_to_py_cls(component_class); - if (!py_cls) { - BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR, log_level, BT_LOG_TAG, - "Cannot find Python class associated to native component class: " - "comp-cls-addr=%p", component_class); - goto error; - } - - py_params_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(params), - SWIGTYPE_p_bt_value, 0); - if (!py_params_ptr) { - BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR, log_level, BT_LOG_TAG, - "Failed to create a SWIG pointer object."); - goto error; - } - - py_priv_query_exec_ptr = SWIG_NewPointerObj( - SWIG_as_voidptr(priv_query_executor), - SWIGTYPE_p_bt_private_query_executor, 0); - if (!py_priv_query_exec_ptr) { - BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR, log_level, BT_LOG_TAG, - "Failed to create a SWIG pointer object."); - goto error; - } - - py_object = SWIG_FromCharPtr(object); - if (!py_object) { - BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR, log_level, BT_LOG_TAG, - "Failed to create a Python string."); - goto error; - } - - py_results_addr = PyObject_CallMethod(py_cls, - "_bt_query_from_native", "(OOO)", py_priv_query_exec_ptr, - py_object, py_params_ptr); - if (!py_results_addr) { - BT_LOG_WRITE_CUR_LVL(BT_LOG_WARNING, log_level, BT_LOG_TAG, - "Failed to call Python class's _bt_query_from_native() method: " - "py-cls-addr=%p", py_cls); - status = py_exc_to_status_component_class(self_component_class, - log_level); - goto end; - } - - /* - * The returned object, on success, is an integer object - * (PyLong) containing the address of a BT value object (new - * reference). - */ - *result = PyLong_AsVoidPtr(py_results_addr); - BT_ASSERT(!PyErr_Occurred()); - BT_ASSERT(*result); - goto end; - -error: - PyErr_Clear(); - status = __BT_FUNC_STATUS_ERROR; - -end: - Py_XDECREF(py_params_ptr); - Py_XDECREF(py_priv_query_exec_ptr); - Py_XDECREF(py_query_func); - Py_XDECREF(py_object); - Py_XDECREF(py_results_addr); - return status; -} - -static -bt_component_class_query_method_status component_class_source_query( - bt_self_component_class_source *self_component_class_source, - bt_private_query_executor *priv_query_executor, - const char *object, const bt_value *params, - const bt_value **result) -{ - const bt_component_class_source *component_class_source = bt_self_component_class_source_as_component_class_source(self_component_class_source); - const bt_component_class *component_class = bt_component_class_source_as_component_class_const(component_class_source); - bt_self_component_class *self_component_class = bt_self_component_class_source_as_self_component_class(self_component_class_source); - - return component_class_query(component_class, self_component_class, - priv_query_executor, object, params, result); -} - -static -bt_component_class_query_method_status component_class_filter_query( - bt_self_component_class_filter *self_component_class_filter, - bt_private_query_executor *priv_query_executor, - const char *object, const bt_value *params, - const bt_value **result) -{ - const bt_component_class_filter *component_class_filter = bt_self_component_class_filter_as_component_class_filter(self_component_class_filter); - const bt_component_class *component_class = bt_component_class_filter_as_component_class_const(component_class_filter); - bt_self_component_class *self_component_class = bt_self_component_class_filter_as_self_component_class(self_component_class_filter); - - return component_class_query(component_class, self_component_class, - priv_query_executor, object, params, result); -} - -static -bt_component_class_query_method_status component_class_sink_query( - bt_self_component_class_sink *self_component_class_sink, - bt_private_query_executor *priv_query_executor, - const char *object, const bt_value *params, - const bt_value **result) -{ - const bt_component_class_sink *component_class_sink = bt_self_component_class_sink_as_component_class_sink(self_component_class_sink); - const bt_component_class *component_class = bt_component_class_sink_as_component_class_const(component_class_sink); - bt_self_component_class *self_component_class = bt_self_component_class_sink_as_self_component_class(self_component_class_sink); - - return component_class_query(component_class, self_component_class, - priv_query_executor, object, params, result); -} - -static -bt_component_class_message_iterator_init_method_status -component_class_message_iterator_init( - bt_self_message_iterator *self_message_iterator, - bt_self_component *self_component, - bt_self_component_port_output *self_component_port_output) -{ - bt_component_class_message_iterator_init_method_status status = __BT_FUNC_STATUS_OK; - PyObject *py_comp_cls = NULL; - PyObject *py_iter_cls = NULL; - PyObject *py_iter_ptr = NULL; - PyObject *py_component_port_output_ptr = NULL; - PyObject *py_init_method_result = NULL; - PyObject *py_iter = NULL; - PyObject *py_comp; - bt_logging_level log_level = get_self_component_log_level( - self_component); - - py_comp = bt_self_component_get_data(self_component); - - /* Find user's Python message iterator class */ - py_comp_cls = PyObject_GetAttrString(py_comp, "__class__"); - if (!py_comp_cls) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, - "Cannot get Python object's `__class__` attribute."); - goto python_error; - } - - py_iter_cls = PyObject_GetAttrString(py_comp_cls, "_iter_cls"); - if (!py_iter_cls) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, - "Cannot get Python class's `_iter_cls` attribute."); - goto python_error; - } - - py_iter_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_message_iterator), - SWIGTYPE_p_bt_self_message_iterator, 0); - if (!py_iter_ptr) { - const char *err = "Failed to create a SWIG pointer object."; - - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, - "%s", err); - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR( - self_message_iterator, err); - goto error; - } - - /* - * Create object with borrowed native message iterator - * reference: - * - * py_iter = py_iter_cls.__new__(py_iter_cls, py_iter_ptr) - */ - py_iter = PyObject_CallMethod(py_iter_cls, "__new__", - "(OO)", py_iter_cls, py_iter_ptr); - if (!py_iter) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, - "Failed to call Python class's __new__() method: " - "py-cls-addr=%p", py_iter_cls); - goto python_error; - } - - /* - * Initialize object: - * - * py_iter.__init__(self_output_port) - * - * through the _init_for_native helper static method. - * - * At this point, py_iter._ptr is set, so this initialization - * function has access to self._component (which gives it the - * user Python component object from which the iterator was - * created). - */ - py_component_port_output_ptr = SWIG_NewPointerObj( - SWIG_as_voidptr(self_component_port_output), - SWIGTYPE_p_bt_self_component_port_output, 0); - if (!py_component_port_output_ptr) { - const char *err = "Failed to create a SWIG pointer object."; - - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, - "%s", err); - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR( - self_message_iterator, err); - goto error; - } - - py_init_method_result = PyObject_CallMethod(py_iter, - "_bt_init_from_native", "O", py_component_port_output_ptr); - if (!py_init_method_result) { - BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, - "User's __init__() method failed:"); - goto python_error; - } - - /* - * Since the Python code can never instantiate a user-defined - * message iterator class, the native message iterator - * object does NOT belong to a user Python message iterator - * object (borrowed reference). However this Python object is - * owned by this native message iterator object. - * - * In the Python world, the lifetime of the native message - * iterator is managed by a _GenericMessageIterator - * instance: - * - * _GenericMessageIterator instance: - * owns a native bt_message_iterator object (iter) - * owns a _UserMessageIterator instance (py_iter) - * self._ptr is a borrowed reference to the - * native bt_private_connection_private_message_iterator - * object (iter) - */ - bt_self_message_iterator_set_data(self_message_iterator, py_iter); - py_iter = NULL; - goto end; - -python_error: - /* Handling of errors that cause a Python exception to be set. */ - status = py_exc_to_status_message_iterator(self_message_iterator); - BT_ASSERT(status != __BT_FUNC_STATUS_OK); - goto end; - -error: - /* Handling of errors that don't cause a Python exception to be set. */ - status = __BT_FUNC_STATUS_ERROR; - -end: - BT_ASSERT(!PyErr_Occurred()); - - Py_XDECREF(py_comp_cls); - Py_XDECREF(py_iter_cls); - Py_XDECREF(py_iter_ptr); - Py_XDECREF(py_component_port_output_ptr); - Py_XDECREF(py_init_method_result); - Py_XDECREF(py_iter); - return status; -} - -static -bt_component_class_message_iterator_init_method_status -component_class_source_message_iterator_init( - bt_self_message_iterator *self_message_iterator, - bt_self_component_source *self_component_source, - bt_self_component_port_output *self_component_port_output) -{ - bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source); - - return component_class_message_iterator_init(self_message_iterator, self_component, self_component_port_output); -} - -static -bt_component_class_message_iterator_init_method_status -component_class_filter_message_iterator_init( - bt_self_message_iterator *self_message_iterator, - bt_self_component_filter *self_component_filter, - bt_self_component_port_output *self_component_port_output) -{ - bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter); - - return component_class_message_iterator_init(self_message_iterator, self_component, self_component_port_output); -} - -static -void component_class_message_iterator_finalize( - bt_self_message_iterator *message_iterator) -{ - PyObject *py_message_iter = bt_self_message_iterator_get_data( - message_iterator); - PyObject *py_method_result = NULL; - - BT_ASSERT(py_message_iter); - - /* Call user's _user_finalize() method */ - py_method_result = PyObject_CallMethod(py_message_iter, - "_user_finalize", NULL); - - if (PyErr_Occurred()) { - bt_self_component *self_comp = - bt_self_message_iterator_borrow_component( - message_iterator); - bt_logging_level log_level = get_self_component_log_level( - self_comp); - - BT_COMP_LOG_CUR_LVL(BT_LOG_WARNING, log_level, self_comp, - "User's _user_finalize() method raised an exception: ignoring:"); - logw_exception(get_self_message_iterator_log_level( - message_iterator)); - } - - /* - * Ignore any exception raised by the _user_finalize() method - * because it won't change anything at this point: the component - * is being destroyed anyway. - */ - PyErr_Clear(); - Py_XDECREF(py_method_result); - Py_DECREF(py_message_iter); -} - -/* Valid for both sources and filters. */ - -static -bt_component_class_message_iterator_next_method_status -component_class_message_iterator_next( - bt_self_message_iterator *message_iterator, - bt_message_array_const msgs, uint64_t capacity, - uint64_t *count) -{ - bt_component_class_message_iterator_next_method_status status = __BT_FUNC_STATUS_OK; - PyObject *py_message_iter = bt_self_message_iterator_get_data(message_iterator); - PyObject *py_method_result = NULL; - - BT_ASSERT(py_message_iter); - py_method_result = PyObject_CallMethod(py_message_iter, - "_bt_next_from_native", NULL); - if (!py_method_result) { - status = py_exc_to_status_message_iterator(message_iterator); - BT_ASSERT(status != __BT_FUNC_STATUS_OK); - goto end; - } - - /* - * The returned object, on success, is an integer object - * (PyLong) containing the address of a native message - * object (which is now ours). - */ - msgs[0] = PyLong_AsVoidPtr(py_method_result); - *count = 1; - - /* Clear potential overflow error; should never happen */ - BT_ASSERT(!PyErr_Occurred()); - goto end; - -end: - Py_XDECREF(py_method_result); - return status; -} - -static -bt_component_class_sink_consume_method_status -component_class_sink_consume(bt_self_component_sink *self_component_sink) -{ - bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink); - PyObject *py_comp = bt_self_component_get_data(self_component); - PyObject *py_method_result = NULL; - bt_component_class_sink_consume_method_status status; - - BT_ASSERT(py_comp); - py_method_result = PyObject_CallMethod(py_comp, - "_user_consume", NULL); - status = py_exc_to_status_component(self_component); - BT_ASSERT(py_method_result || status != __BT_FUNC_STATUS_OK); - Py_XDECREF(py_method_result); - return status; -} - -static -int component_class_set_help_and_desc( - bt_component_class *component_class, - const char *description, const char *help) -{ - int ret; - - if (description) { - ret = bt_component_class_set_description(component_class, description); - if (ret) { - BT_LOGE("Cannot set component class's description: " - "comp-cls-addr=%p", component_class); - goto end; - } - } - - if (help) { - ret = bt_component_class_set_help(component_class, help); - if (ret) { - BT_LOGE("Cannot set component class's help text: " - "comp-cls-addr=%p", component_class); - goto end; - } - } - - ret = 0; - -end: - return ret; -} - -static -bt_component_class_source *bt_bt2_component_class_source_create( - PyObject *py_cls, const char *name, const char *description, - const char *help) -{ - bt_component_class_source *component_class_source; - bt_component_class *component_class; - int ret; - - BT_ASSERT(py_cls); - component_class_source = bt_component_class_source_create(name, - component_class_message_iterator_next); - if (!component_class_source) { - BT_LOGE_STR("Cannot create source component class."); - goto end; - } - - component_class = bt_component_class_source_as_component_class(component_class_source); - - if (component_class_set_help_and_desc(component_class, description, help)) { - goto end; - } - - ret = bt_component_class_source_set_init_method(component_class_source, component_class_source_init); - BT_ASSERT(ret == 0); - ret = bt_component_class_source_set_finalize_method(component_class_source, component_class_source_finalize); - BT_ASSERT(ret == 0); - ret = bt_component_class_source_set_message_iterator_can_seek_beginning_method(component_class_source, - component_class_can_seek_beginning); - BT_ASSERT(ret == 0); - ret = bt_component_class_source_set_message_iterator_seek_beginning_method(component_class_source, - component_class_seek_beginning); - BT_ASSERT(ret == 0); - ret = bt_component_class_source_set_output_port_connected_method(component_class_source, - component_class_source_output_port_connected); - BT_ASSERT(ret == 0); - ret = bt_component_class_source_set_query_method(component_class_source, component_class_source_query); - BT_ASSERT(ret == 0); - ret = bt_component_class_source_set_message_iterator_init_method( - component_class_source, component_class_source_message_iterator_init); - BT_ASSERT(ret == 0); - ret = bt_component_class_source_set_message_iterator_finalize_method( - component_class_source, component_class_message_iterator_finalize); - BT_ASSERT(ret == 0); - register_cc_ptr_to_py_cls(component_class, py_cls); - -end: - return component_class_source; -} - -static -bt_component_class_filter *bt_bt2_component_class_filter_create( - PyObject *py_cls, const char *name, const char *description, - const char *help) -{ - bt_component_class *component_class; - bt_component_class_filter *component_class_filter; - int ret; - - BT_ASSERT(py_cls); - component_class_filter = bt_component_class_filter_create(name, - component_class_message_iterator_next); - if (!component_class_filter) { - BT_LOGE_STR("Cannot create filter component class."); - goto end; - } - - component_class = bt_component_class_filter_as_component_class(component_class_filter); - - if (component_class_set_help_and_desc(component_class, description, help)) { - goto end; - } - - ret = bt_component_class_filter_set_init_method(component_class_filter, component_class_filter_init); - BT_ASSERT(ret == 0); - ret = bt_component_class_filter_set_finalize_method (component_class_filter, component_class_filter_finalize); - BT_ASSERT(ret == 0); - ret = bt_component_class_filter_set_message_iterator_can_seek_beginning_method(component_class_filter, - component_class_can_seek_beginning); - BT_ASSERT(ret == 0); - ret = bt_component_class_filter_set_message_iterator_seek_beginning_method(component_class_filter, - component_class_seek_beginning); - BT_ASSERT(ret == 0); - ret = bt_component_class_filter_set_input_port_connected_method(component_class_filter, - component_class_filter_input_port_connected); - BT_ASSERT(ret == 0); - ret = bt_component_class_filter_set_output_port_connected_method(component_class_filter, - component_class_filter_output_port_connected); - BT_ASSERT(ret == 0); - ret = bt_component_class_filter_set_query_method(component_class_filter, component_class_filter_query); - BT_ASSERT(ret == 0); - ret = bt_component_class_filter_set_message_iterator_init_method( - component_class_filter, component_class_filter_message_iterator_init); - BT_ASSERT(ret == 0); - ret = bt_component_class_filter_set_message_iterator_finalize_method( - component_class_filter, component_class_message_iterator_finalize); - BT_ASSERT(ret == 0); - register_cc_ptr_to_py_cls(component_class, py_cls); - -end: - return component_class_filter; -} - -static -bt_component_class_sink *bt_bt2_component_class_sink_create( - PyObject *py_cls, const char *name, const char *description, - const char *help) -{ - bt_component_class_sink *component_class_sink; - bt_component_class *component_class; - int ret; - - BT_ASSERT(py_cls); - component_class_sink = bt_component_class_sink_create(name, component_class_sink_consume); - - if (!component_class_sink) { - BT_LOGE_STR("Cannot create sink component class."); - goto end; - } - - component_class = bt_component_class_sink_as_component_class(component_class_sink); - - if (component_class_set_help_and_desc(component_class, description, help)) { - goto end; - } - - ret = bt_component_class_sink_set_init_method(component_class_sink, component_class_sink_init); - BT_ASSERT(ret == 0); - ret = bt_component_class_sink_set_finalize_method(component_class_sink, component_class_sink_finalize); - BT_ASSERT(ret == 0); - ret = bt_component_class_sink_set_input_port_connected_method(component_class_sink, - component_class_sink_input_port_connected); - BT_ASSERT(ret == 0); - ret = bt_component_class_sink_set_graph_is_configured_method(component_class_sink, - component_class_sink_graph_is_configured); - BT_ASSERT(ret == 0); - ret = bt_component_class_sink_set_query_method(component_class_sink, component_class_sink_query); - BT_ASSERT(ret == 0); - register_cc_ptr_to_py_cls(component_class, py_cls); - -end: - return component_class_sink; -} +#include "native_bt_component_class.i.h" %} struct bt_component_class_source *bt_bt2_component_class_source_create( diff --git a/src/bindings/python/bt2/bt2/native_bt_component_class.i.h b/src/bindings/python/bt2/bt2/native_bt_component_class.i.h new file mode 100644 index 00000000..6844fe1a --- /dev/null +++ b/src/bindings/python/bt2/bt2/native_bt_component_class.i.h @@ -0,0 +1,1411 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "logging/comp-logging.h" + +/* + * This hash table associates a BT component class object address to a + * user-defined Python class (PyObject *). The keys and values are NOT + * owned by this hash table. The Python class objects are owned by the + * Python module, which should not be unloaded until it is not possible + * to create a user Python component anyway. + * + * This hash table is written to when a user-defined Python component + * class is created by one of the bt_bt2_component_class_*_create() + * functions. + * + * This function is read from when a user calls bt_component_create() + * with a component class pointer created by one of the functions above. + * In this case, the original Python class needs to be found to + * instantiate it and associate the created Python component object with + * a BT component object instance. + */ + +static GHashTable *bt_cc_ptr_to_py_cls; + +static +void register_cc_ptr_to_py_cls(struct bt_component_class *bt_cc, + PyObject *py_cls) +{ + if (!bt_cc_ptr_to_py_cls) { + /* + * Lazy-initializing this GHashTable because GLib + * might not be initialized yet and it needs to be + * before we call g_hash_table_new() + */ + BT_LOGD_STR("Creating native component class to Python component class hash table."); + bt_cc_ptr_to_py_cls = g_hash_table_new(g_direct_hash, g_direct_equal); + BT_ASSERT(bt_cc_ptr_to_py_cls); + } + + g_hash_table_insert(bt_cc_ptr_to_py_cls, (gpointer) bt_cc, + (gpointer) py_cls); +} + +static +PyObject *lookup_cc_ptr_to_py_cls(const bt_component_class *bt_cc) +{ + if (!bt_cc_ptr_to_py_cls) { + BT_LOGW("Cannot look up Python component class because hash table is NULL: " + "comp-cls-addr=%p", bt_cc); + return NULL; + } + + return (PyObject *) g_hash_table_lookup(bt_cc_ptr_to_py_cls, + (gconstpointer) bt_cc); +} + + +/* + * Useful Python objects. + */ + +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_unknown_object_type = NULL; + +static +void bt_bt2_cc_init_from_bt2(void) +{ + /* + * This is called once the bt2 package is loaded. + * + * Those modules and functions are needed while the package is + * used. Loading them here is safe because we know the bt2 + * package is imported, and we know that the user cannot use the + * code here without importing bt2 first. + */ + py_mod_bt2 = PyImport_ImportModule("bt2"); + BT_ASSERT(py_mod_bt2); + 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); + py_mod_bt2_exc_stop_type = + PyObject_GetAttrString(py_mod_bt2, "Stop"); + BT_ASSERT(py_mod_bt2_exc_stop_type); + py_mod_bt2_exc_unknown_object_type = + PyObject_GetAttrString(py_mod_bt2, "UnknownObject"); + BT_ASSERT(py_mod_bt2_exc_unknown_object_type); +} + +static +void bt_bt2_cc_exit_handler(void) +{ + /* + * This is an exit handler (set by the bt2 package). + * + * We only give back the references that we took in + * bt_bt2_cc_init_from_bt2() here. The global variables continue + * to exist for the code of this file, but they are now borrowed + * references. If this code is executed, it means that somehow + * the modules are still loaded, so it should be safe to use + * them even without a strong reference. + * + * We cannot do this in the library's destructor because it + * gets executed once Python is already finalized. + */ + Py_XDECREF(py_mod_bt2); + Py_XDECREF(py_mod_bt2_exc_error_type); + Py_XDECREF(py_mod_bt2_exc_try_again_type); + Py_XDECREF(py_mod_bt2_exc_stop_type); + Py_XDECREF(py_mod_bt2_exc_unknown_object_type); +} + + +/* Library destructor */ + +__attribute__((destructor)) +static +void native_comp_class_dtor(void) { + /* Destroy component class association hash table */ + if (bt_cc_ptr_to_py_cls) { + BT_LOGD_STR("Destroying native component class to Python component class hash table."); + g_hash_table_destroy(bt_cc_ptr_to_py_cls); + } +} + +static +void restore_current_thread_error_and_append_exception_chain_recursive( + int active_log_level, PyObject *py_exc_value, + bt_self_component_class *self_component_class, + bt_self_component *self_component, + bt_self_message_iterator *self_message_iterator, + const char *module_name) +{ + PyObject *py_exc_cause_value; + PyObject *py_exc_type = NULL; + PyObject *py_exc_tb = NULL; + GString *gstr = NULL; + + /* If this exception has a cause, handle that one first. */ + py_exc_cause_value = PyException_GetCause(py_exc_value); + if (py_exc_cause_value) { + restore_current_thread_error_and_append_exception_chain_recursive( + active_log_level, py_exc_cause_value, + self_component_class, self_component, + self_message_iterator, module_name); + } + + /* + * If the raised exception is a bt2._Error, restore the wrapped error. + */ + if (PyErr_GivenExceptionMatches(py_exc_value, py_mod_bt2_exc_error_type)) { + PyObject *py_error_swig_ptr; + const bt_error *error; + int ret; + + /* + * We never raise a bt2._Error with a cause: it should be the + * end of the chain. + */ + BT_ASSERT(!py_exc_cause_value); + + /* + * We steal the error object from the exception, to move + * it back as the current thread's error. + */ + py_error_swig_ptr = PyObject_GetAttrString(py_exc_value, "_ptr"); + BT_ASSERT(py_error_swig_ptr); + + ret = PyObject_SetAttrString(py_exc_value, "_ptr", Py_None); + BT_ASSERT(ret == 0); + + ret = SWIG_ConvertPtr(py_error_swig_ptr, (void **) &error, + SWIGTYPE_p_bt_error, 0); + BT_ASSERT(ret == 0); + + BT_CURRENT_THREAD_MOVE_ERROR_AND_RESET(error); + + Py_DECREF(py_error_swig_ptr); + } + + py_exc_type = PyObject_Type(py_exc_value); + py_exc_tb = PyException_GetTraceback(py_exc_value); + + gstr = bt_py_common_format_exception(py_exc_type, py_exc_value, + py_exc_tb, active_log_level, false); + if (!gstr) { + /* bt_py_common_format_exception has already warned. */ + goto end; + } + + if (self_component_class) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT_CLASS( + self_component_class, "%s", gstr->str); + } else if (self_component) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT( + self_component, "%s", gstr->str); + } else if (self_message_iterator) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR( + self_message_iterator, "%s", gstr->str); + } else { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN( + module_name, "%s", gstr->str); + } + +end: + if (gstr) { + g_string_free(gstr, TRUE); + } + + Py_XDECREF(py_exc_cause_value); + Py_XDECREF(py_exc_type); + Py_XDECREF(py_exc_tb); +} + +/* + * If you have the following code: + * + * try: + * try: + * something_that_raises_bt2_error() + * except bt2._Error as e1: + * raise ValueError from e1 + * except ValueError as e2: + * raise TypeError from e2 + * + * We will have the following exception chain: + * + * TypeError -> ValueError -> bt2._Error + * + * Where the TypeError is the current exception (obtained from PyErr_Fetch). + * + * The bt2._Error contains a `struct bt_error *` that used to be the current + * thread's error, at the moment the exception was raised. + * + * This function gets to the bt2._Error and restores the wrapped + * `struct bt_error *` as the current thread's error. + * + * Then, for each exception in the chain, starting with the oldest one, it adds + * an error cause to the current thread's error. + */ +static +void restore_bt_error_and_append_current_exception_chain( + int active_log_level, + bt_self_component_class *self_component_class, + bt_self_component *self_component, + bt_self_message_iterator *self_message_iterator, + const char *module_name) +{ + BT_ASSERT(PyErr_Occurred()); + + /* Used to access and restore the current exception. */ + PyObject *py_exc_type; + PyObject *py_exc_value; + PyObject *py_exc_tb; + + /* Fetch and normalize the Python exception. */ + PyErr_Fetch(&py_exc_type, &py_exc_value, &py_exc_tb); + PyErr_NormalizeException(&py_exc_type, &py_exc_value, &py_exc_tb); + BT_ASSERT(py_exc_type); + BT_ASSERT(py_exc_value); + BT_ASSERT(py_exc_tb); + + /* + * Set the exception's traceback so it's possible to get it using + * PyException_GetTraceback in + * restore_current_thread_error_and_append_exception_chain_recursive. + */ + PyException_SetTraceback(py_exc_value, py_exc_tb); + + restore_current_thread_error_and_append_exception_chain_recursive( + active_log_level, py_exc_value, self_component_class, + self_component, self_message_iterator, module_name); + + PyErr_Restore(py_exc_type, py_exc_value, py_exc_tb); +} + +static inline +void log_exception_and_maybe_append_error(int func_log_level, + int active_log_level, bool append_error, + bt_self_component_class *self_component_class, + bt_self_component *self_component, + bt_self_message_iterator *self_message_iterator, + const char *module_name) +{ + GString *gstr; + + BT_ASSERT(PyErr_Occurred()); + gstr = bt_py_common_format_current_exception(active_log_level); + if (!gstr) { + /* bt_py_common_format_current_exception() logs errors */ + goto end; + } + + BT_COMP_LOG_CUR_LVL(func_log_level, active_log_level, self_component, + "%s", gstr->str); + + if (append_error) { + restore_bt_error_and_append_current_exception_chain( + active_log_level, self_component_class, self_component, + self_message_iterator, module_name); + + } + +end: + if (gstr) { + g_string_free(gstr, TRUE); + } +} + +static +bt_logging_level get_self_component_log_level(bt_self_component *self_comp) +{ + return bt_component_get_logging_level( + bt_self_component_as_component(self_comp)); +} + +static +bt_logging_level get_self_message_iterator_log_level( + bt_self_message_iterator *self_msg_iter) +{ + bt_self_component *self_comp = + bt_self_message_iterator_borrow_component(self_msg_iter); + + return get_self_component_log_level(self_comp); +} + +static inline +void loge_exception(const char *module_name, int active_log_level) +{ + log_exception_and_maybe_append_error(BT_LOG_ERROR, active_log_level, + true, NULL, NULL, NULL, module_name); +} + +static +void loge_exception_message_iterator( + bt_self_message_iterator *self_message_iterator) +{ + bt_logging_level log_level = get_self_message_iterator_log_level( + self_message_iterator); + + log_exception_and_maybe_append_error(BT_LOG_ERROR, log_level, + true, NULL, NULL, self_message_iterator, NULL); +} + +static inline +void logw_exception(int active_log_level) +{ + log_exception_and_maybe_append_error(BT_LOG_WARNING, active_log_level, + false, NULL, NULL, NULL, NULL); +} + +static inline +int py_exc_to_status(bt_self_component_class *self_component_class, + bt_self_component *self_component, + bt_self_message_iterator *self_message_iterator, + const char *module_name, int active_log_level) +{ + int status = __BT_FUNC_STATUS_OK; + PyObject *exc = PyErr_Occurred(); + + if (!exc) { + goto end; + } + + if (PyErr_GivenExceptionMatches(exc, + py_mod_bt2_exc_try_again_type)) { + status = __BT_FUNC_STATUS_AGAIN; + } else if (PyErr_GivenExceptionMatches(exc, + py_mod_bt2_exc_stop_type)) { + status = __BT_FUNC_STATUS_END; + } else if (PyErr_GivenExceptionMatches(exc, + py_mod_bt2_exc_unknown_object_type)) { + status = __BT_FUNC_STATUS_UNKNOWN_OBJECT; + } else { + /* + * Unknown exception: convert to general error. + * + * Because we only want to fetch the log level when + * we actually get an exception, and not systematically + * when we call py_exc_to_status() (as py_exc_to_status() + * can return `__BT_FUNC_STATUS_OK`), we get it here + * depending on the actor's type. + */ + if (self_component) { + active_log_level = get_self_component_log_level( + self_component); + } else if (self_message_iterator) { + active_log_level = get_self_message_iterator_log_level( + self_message_iterator); + } + + BT_ASSERT(active_log_level != -1); + log_exception_and_maybe_append_error(BT_LOG_WARNING, + active_log_level, true, + self_component_class, self_component, + self_message_iterator, module_name); + + if (PyErr_GivenExceptionMatches(exc, + py_mod_bt2_exc_memory_error)) { + status = __BT_FUNC_STATUS_MEMORY_ERROR; + } else { + status = __BT_FUNC_STATUS_ERROR; + } + } + +end: + PyErr_Clear(); + return status; +} + +static +int py_exc_to_status_component_class( + bt_self_component_class *self_component_class, + int active_log_level) +{ + return py_exc_to_status(self_component_class, NULL, NULL, NULL, + active_log_level); +} + +static +int py_exc_to_status_component(bt_self_component *self_component) +{ + return py_exc_to_status(NULL, self_component, NULL, NULL, -1); +} + +static +int py_exc_to_status_message_iterator( + bt_self_message_iterator *self_message_iterator) +{ + return py_exc_to_status(NULL, NULL, self_message_iterator, NULL, -1); +} + +/* Component class proxy methods (delegate to the attached Python object) */ + +static +bt_component_class_init_method_status component_class_init( + bt_self_component *self_component, + void *self_component_v, + swig_type_info *self_comp_cls_type_swig_type, + const bt_value *params, + void *init_method_data) +{ + const bt_component *component = bt_self_component_as_component(self_component); + const bt_component_class *component_class = bt_component_borrow_class_const(component); + bt_component_class_init_method_status status = __BT_FUNC_STATUS_OK; + PyObject *py_cls = NULL; + PyObject *py_comp = NULL; + PyObject *py_params_ptr = NULL; + PyObject *py_comp_ptr = NULL; + bt_logging_level log_level = get_self_component_log_level( + self_component); + + (void) init_method_data; + + BT_ASSERT(self_component); + BT_ASSERT(self_component_v); + BT_ASSERT(self_comp_cls_type_swig_type); + + /* + * Get the user-defined Python class which created this + * component's class in the first place (borrowed + * reference). + */ + py_cls = lookup_cc_ptr_to_py_cls(component_class); + if (!py_cls) { + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, + "Cannot find Python class associated to native component class: " + "comp-cls-addr=%p", component_class); + goto error; + } + + /* Parameters pointer -> SWIG pointer Python object */ + py_params_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(params), + SWIGTYPE_p_bt_value, 0); + if (!py_params_ptr) { + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, + "Failed to create a SWIG pointer object."); + goto error; + } + + py_comp_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_component_v), + self_comp_cls_type_swig_type, 0); + if (!py_comp_ptr) { + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, + "Failed to create a SWIG pointer object."); + goto error; + } + + /* + * Do the equivalent of this: + * + * py_comp = py_cls._bt_init_from_native(py_comp_ptr, py_params_ptr) + * + * _UserComponentType._bt_init_from_native() calls the Python + * component object's __init__() function. + */ + py_comp = PyObject_CallMethod(py_cls, + "_bt_init_from_native", "(OO)", py_comp_ptr, py_params_ptr); + if (!py_comp) { + BT_COMP_LOG_CUR_LVL(BT_LOG_WARNING, log_level, self_component, + "Failed to call Python class's _bt_init_from_native() method: " + "py-cls-addr=%p", py_cls); + status = py_exc_to_status_component(self_component); + goto end; + } + + /* + * Our user Python component object is now fully created and + * initialized by the user. Since we just created it, this + * native component is its only (persistent) owner. + */ + bt_self_component_set_data(self_component, py_comp); + py_comp = NULL; + goto end; + +error: + status = __BT_FUNC_STATUS_ERROR; + + /* + * Clear any exception: we're returning a bad status anyway. If + * this call originated from Python (creation from a plugin's + * component class, for example), then the user gets an + * appropriate creation error. + */ + PyErr_Clear(); + +end: + Py_XDECREF(py_comp); + Py_XDECREF(py_params_ptr); + Py_XDECREF(py_comp_ptr); + return status; +} + +/* + * Method of bt_component_class_source to initialize a bt_self_component_source + * of that class. + */ + +static +bt_component_class_init_method_status component_class_source_init( + bt_self_component_source *self_component_source, + const bt_value *params, void *init_method_data) +{ + bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source); + return component_class_init( + self_component, + self_component_source, + SWIGTYPE_p_bt_self_component_source, + params, init_method_data); +} + +static +bt_component_class_init_method_status component_class_filter_init( + bt_self_component_filter *self_component_filter, + const bt_value *params, void *init_method_data) +{ + bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter); + return component_class_init( + self_component, + self_component_filter, + SWIGTYPE_p_bt_self_component_filter, + params, init_method_data); +} + +static +bt_component_class_init_method_status component_class_sink_init( + bt_self_component_sink *self_component_sink, + const bt_value *params, void *init_method_data) +{ + bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink); + return component_class_init( + self_component, + self_component_sink, + SWIGTYPE_p_bt_self_component_sink, + params, init_method_data); +} + +static +void component_class_finalize(bt_self_component *self_component) +{ + PyObject *py_comp = bt_self_component_get_data(self_component); + BT_ASSERT(py_comp); + + /* Call user's _user_finalize() method */ + PyObject *py_method_result = PyObject_CallMethod(py_comp, + "_user_finalize", NULL); + + if (PyErr_Occurred()) { + bt_logging_level log_level = get_self_component_log_level( + self_component); + + BT_COMP_LOG_CUR_LVL(BT_LOG_WARNING, log_level, self_component, + "User component's _user_finalize() method raised an exception: ignoring:"); + logw_exception(log_level); + } + + /* + * Ignore any exception raised by the _user_finalize() method + * because it won't change anything at this point: the component + * is being destroyed anyway. + */ + PyErr_Clear(); + Py_XDECREF(py_method_result); + Py_DECREF(py_comp); +} + +static +void component_class_source_finalize(bt_self_component_source *self_component_source) +{ + bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source); + component_class_finalize(self_component); +} + +static +void component_class_filter_finalize(bt_self_component_filter *self_component_filter) +{ + bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter); + component_class_finalize(self_component); +} + +static +void component_class_sink_finalize(bt_self_component_sink *self_component_sink) +{ + bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink); + component_class_finalize(self_component); +} + +static +bt_bool component_class_can_seek_beginning( + bt_self_message_iterator *self_message_iterator) +{ + PyObject *py_iter; + PyObject *py_result = NULL; + bt_bool can_seek_beginning = false; + + py_iter = bt_self_message_iterator_get_data(self_message_iterator); + BT_ASSERT(py_iter); + + py_result = PyObject_GetAttrString(py_iter, "_bt_can_seek_beginning_from_native"); + + BT_ASSERT(!py_result || PyBool_Check(py_result)); + + if (py_result) { + can_seek_beginning = PyObject_IsTrue(py_result); + } else { + /* + * Once can_seek_beginning can report errors, convert the + * exception to a status. For now, log and return false; + */ + loge_exception_message_iterator(self_message_iterator); + PyErr_Clear(); + } + + Py_XDECREF(py_result); + + return can_seek_beginning; +} + +static +bt_component_class_message_iterator_seek_beginning_method_status +component_class_seek_beginning(bt_self_message_iterator *self_message_iterator) +{ + PyObject *py_iter; + PyObject *py_result; + bt_component_class_message_iterator_seek_beginning_method_status status; + + py_iter = bt_self_message_iterator_get_data(self_message_iterator); + BT_ASSERT(py_iter); + py_result = PyObject_CallMethod(py_iter, "_bt_seek_beginning_from_native", + NULL); + BT_ASSERT(!py_result || py_result == Py_None); + status = py_exc_to_status_message_iterator(self_message_iterator); + Py_XDECREF(py_result); + return status; +} + +static +bt_component_class_port_connected_method_status component_class_port_connected( + bt_self_component *self_component, + void *self_component_port, + swig_type_info *self_component_port_swig_type, + bt_port_type self_component_port_type, + const void *other_port, + swig_type_info *other_port_swig_type) +{ + bt_component_class_port_connected_method_status status; + PyObject *py_comp = NULL; + PyObject *py_self_port_ptr = NULL; + PyObject *py_other_port_ptr = NULL; + PyObject *py_method_result = NULL; + bt_logging_level log_level = get_self_component_log_level( + self_component); + + py_comp = bt_self_component_get_data(self_component); + BT_ASSERT(py_comp); + py_self_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_component_port), + self_component_port_swig_type, 0); + if (!py_self_port_ptr) { + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, + "Failed to create a SWIG pointer object."); + status = __BT_FUNC_STATUS_MEMORY_ERROR; + goto end; + } + + py_other_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(other_port), + other_port_swig_type, 0); + if (!py_other_port_ptr) { + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, + "Failed to create a SWIG pointer object."); + status = __BT_FUNC_STATUS_MEMORY_ERROR; + goto end; } + + py_method_result = PyObject_CallMethod(py_comp, + "_bt_port_connected_from_native", "(OiO)", py_self_port_ptr, + self_component_port_type, py_other_port_ptr); + BT_ASSERT(!py_method_result || py_method_result == Py_None); + status = py_exc_to_status_component(self_component); + +end: + Py_XDECREF(py_self_port_ptr); + Py_XDECREF(py_other_port_ptr); + Py_XDECREF(py_method_result); + return status; +} + +static +bt_component_class_port_connected_method_status +component_class_source_output_port_connected( + bt_self_component_source *self_component_source, + bt_self_component_port_output *self_component_port_output, + const bt_port_input *other_port_input) +{ + bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source); + + return component_class_port_connected( + self_component, + self_component_port_output, + SWIGTYPE_p_bt_self_component_port_output, + BT_PORT_TYPE_OUTPUT, + other_port_input, + SWIGTYPE_p_bt_port_input); +} + +static +bt_component_class_port_connected_method_status +component_class_filter_input_port_connected( + bt_self_component_filter *self_component_filter, + bt_self_component_port_input *self_component_port_input, + const bt_port_output *other_port_output) +{ + bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter); + + return component_class_port_connected( + self_component, + self_component_port_input, + SWIGTYPE_p_bt_self_component_port_input, + BT_PORT_TYPE_INPUT, + other_port_output, + SWIGTYPE_p_bt_port_output); +} + +static +bt_component_class_port_connected_method_status +component_class_filter_output_port_connected( + bt_self_component_filter *self_component_filter, + bt_self_component_port_output *self_component_port_output, + const bt_port_input *other_port_input) +{ + bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter); + + return component_class_port_connected( + self_component, + self_component_port_output, + SWIGTYPE_p_bt_self_component_port_output, + BT_PORT_TYPE_OUTPUT, + other_port_input, + SWIGTYPE_p_bt_port_input); +} + +static +bt_component_class_port_connected_method_status +component_class_sink_input_port_connected( + bt_self_component_sink *self_component_sink, + bt_self_component_port_input *self_component_port_input, + const bt_port_output *other_port_output) +{ + bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink); + + return component_class_port_connected( + self_component, + self_component_port_input, + SWIGTYPE_p_bt_self_component_port_input, + BT_PORT_TYPE_INPUT, + other_port_output, + SWIGTYPE_p_bt_port_output); +} + +static +bt_component_class_sink_graph_is_configured_method_status +component_class_sink_graph_is_configured( + bt_self_component_sink *self_component_sink) +{ + PyObject *py_comp = NULL; + PyObject *py_method_result = NULL; + bt_component_class_sink_graph_is_configured_method_status status = __BT_FUNC_STATUS_OK; + bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink); + + py_comp = bt_self_component_get_data(self_component); + py_method_result = PyObject_CallMethod(py_comp, + "_bt_graph_is_configured_from_native", NULL); + BT_ASSERT(!py_method_result || py_method_result == Py_None); + status = py_exc_to_status_component(self_component); + Py_XDECREF(py_method_result); + return status; +} + +static +bt_component_class_query_method_status component_class_query( + const bt_component_class *component_class, + bt_self_component_class *self_component_class, + bt_private_query_executor *priv_query_executor, + const char *object, const bt_value *params, + const bt_value **result) +{ + PyObject *py_cls = NULL; + PyObject *py_params_ptr = NULL; + PyObject *py_priv_query_exec_ptr = NULL; + PyObject *py_query_func = NULL; + PyObject *py_object = NULL; + PyObject *py_results_addr = NULL; + bt_component_class_query_method_status status = __BT_FUNC_STATUS_OK; + const bt_query_executor *query_exec = + bt_private_query_executor_as_query_executor_const( + priv_query_executor); + bt_logging_level log_level = + bt_query_executor_get_logging_level(query_exec); + + py_cls = lookup_cc_ptr_to_py_cls(component_class); + if (!py_cls) { + BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR, log_level, BT_LOG_TAG, + "Cannot find Python class associated to native component class: " + "comp-cls-addr=%p", component_class); + goto error; + } + + py_params_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(params), + SWIGTYPE_p_bt_value, 0); + if (!py_params_ptr) { + BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR, log_level, BT_LOG_TAG, + "Failed to create a SWIG pointer object."); + goto error; + } + + py_priv_query_exec_ptr = SWIG_NewPointerObj( + SWIG_as_voidptr(priv_query_executor), + SWIGTYPE_p_bt_private_query_executor, 0); + if (!py_priv_query_exec_ptr) { + BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR, log_level, BT_LOG_TAG, + "Failed to create a SWIG pointer object."); + goto error; + } + + py_object = SWIG_FromCharPtr(object); + if (!py_object) { + BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR, log_level, BT_LOG_TAG, + "Failed to create a Python string."); + goto error; + } + + py_results_addr = PyObject_CallMethod(py_cls, + "_bt_query_from_native", "(OOO)", py_priv_query_exec_ptr, + py_object, py_params_ptr); + if (!py_results_addr) { + BT_LOG_WRITE_CUR_LVL(BT_LOG_WARNING, log_level, BT_LOG_TAG, + "Failed to call Python class's _bt_query_from_native() method: " + "py-cls-addr=%p", py_cls); + status = py_exc_to_status_component_class(self_component_class, + log_level); + goto end; + } + + /* + * The returned object, on success, is an integer object + * (PyLong) containing the address of a BT value object (new + * reference). + */ + *result = PyLong_AsVoidPtr(py_results_addr); + BT_ASSERT(!PyErr_Occurred()); + BT_ASSERT(*result); + goto end; + +error: + PyErr_Clear(); + status = __BT_FUNC_STATUS_ERROR; + +end: + Py_XDECREF(py_params_ptr); + Py_XDECREF(py_priv_query_exec_ptr); + Py_XDECREF(py_query_func); + Py_XDECREF(py_object); + Py_XDECREF(py_results_addr); + return status; +} + +static +bt_component_class_query_method_status component_class_source_query( + bt_self_component_class_source *self_component_class_source, + bt_private_query_executor *priv_query_executor, + const char *object, const bt_value *params, + const bt_value **result) +{ + const bt_component_class_source *component_class_source = bt_self_component_class_source_as_component_class_source(self_component_class_source); + const bt_component_class *component_class = bt_component_class_source_as_component_class_const(component_class_source); + bt_self_component_class *self_component_class = bt_self_component_class_source_as_self_component_class(self_component_class_source); + + return component_class_query(component_class, self_component_class, + priv_query_executor, object, params, result); +} + +static +bt_component_class_query_method_status component_class_filter_query( + bt_self_component_class_filter *self_component_class_filter, + bt_private_query_executor *priv_query_executor, + const char *object, const bt_value *params, + const bt_value **result) +{ + const bt_component_class_filter *component_class_filter = bt_self_component_class_filter_as_component_class_filter(self_component_class_filter); + const bt_component_class *component_class = bt_component_class_filter_as_component_class_const(component_class_filter); + bt_self_component_class *self_component_class = bt_self_component_class_filter_as_self_component_class(self_component_class_filter); + + return component_class_query(component_class, self_component_class, + priv_query_executor, object, params, result); +} + +static +bt_component_class_query_method_status component_class_sink_query( + bt_self_component_class_sink *self_component_class_sink, + bt_private_query_executor *priv_query_executor, + const char *object, const bt_value *params, + const bt_value **result) +{ + const bt_component_class_sink *component_class_sink = bt_self_component_class_sink_as_component_class_sink(self_component_class_sink); + const bt_component_class *component_class = bt_component_class_sink_as_component_class_const(component_class_sink); + bt_self_component_class *self_component_class = bt_self_component_class_sink_as_self_component_class(self_component_class_sink); + + return component_class_query(component_class, self_component_class, + priv_query_executor, object, params, result); +} + +static +bt_component_class_message_iterator_init_method_status +component_class_message_iterator_init( + bt_self_message_iterator *self_message_iterator, + bt_self_component *self_component, + bt_self_component_port_output *self_component_port_output) +{ + bt_component_class_message_iterator_init_method_status status = __BT_FUNC_STATUS_OK; + PyObject *py_comp_cls = NULL; + PyObject *py_iter_cls = NULL; + PyObject *py_iter_ptr = NULL; + PyObject *py_component_port_output_ptr = NULL; + PyObject *py_init_method_result = NULL; + PyObject *py_iter = NULL; + PyObject *py_comp; + bt_logging_level log_level = get_self_component_log_level( + self_component); + + py_comp = bt_self_component_get_data(self_component); + + /* Find user's Python message iterator class */ + py_comp_cls = PyObject_GetAttrString(py_comp, "__class__"); + if (!py_comp_cls) { + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, + "Cannot get Python object's `__class__` attribute."); + goto python_error; + } + + py_iter_cls = PyObject_GetAttrString(py_comp_cls, "_iter_cls"); + if (!py_iter_cls) { + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, + "Cannot get Python class's `_iter_cls` attribute."); + goto python_error; + } + + py_iter_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_message_iterator), + SWIGTYPE_p_bt_self_message_iterator, 0); + if (!py_iter_ptr) { + const char *err = "Failed to create a SWIG pointer object."; + + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, + "%s", err); + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR( + self_message_iterator, err); + goto error; + } + + /* + * Create object with borrowed native message iterator + * reference: + * + * py_iter = py_iter_cls.__new__(py_iter_cls, py_iter_ptr) + */ + py_iter = PyObject_CallMethod(py_iter_cls, "__new__", + "(OO)", py_iter_cls, py_iter_ptr); + if (!py_iter) { + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, + "Failed to call Python class's __new__() method: " + "py-cls-addr=%p", py_iter_cls); + goto python_error; + } + + /* + * Initialize object: + * + * py_iter.__init__(self_output_port) + * + * through the _init_for_native helper static method. + * + * At this point, py_iter._ptr is set, so this initialization + * function has access to self._component (which gives it the + * user Python component object from which the iterator was + * created). + */ + py_component_port_output_ptr = SWIG_NewPointerObj( + SWIG_as_voidptr(self_component_port_output), + SWIGTYPE_p_bt_self_component_port_output, 0); + if (!py_component_port_output_ptr) { + const char *err = "Failed to create a SWIG pointer object."; + + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, + "%s", err); + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR( + self_message_iterator, err); + goto error; + } + + py_init_method_result = PyObject_CallMethod(py_iter, + "_bt_init_from_native", "O", py_component_port_output_ptr); + if (!py_init_method_result) { + BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_component, + "User's __init__() method failed:"); + goto python_error; + } + + /* + * Since the Python code can never instantiate a user-defined + * message iterator class, the native message iterator + * object does NOT belong to a user Python message iterator + * object (borrowed reference). However this Python object is + * owned by this native message iterator object. + * + * In the Python world, the lifetime of the native message + * iterator is managed by a _GenericMessageIterator + * instance: + * + * _GenericMessageIterator instance: + * owns a native bt_message_iterator object (iter) + * owns a _UserMessageIterator instance (py_iter) + * self._ptr is a borrowed reference to the + * native bt_private_connection_private_message_iterator + * object (iter) + */ + bt_self_message_iterator_set_data(self_message_iterator, py_iter); + py_iter = NULL; + goto end; + +python_error: + /* Handling of errors that cause a Python exception to be set. */ + status = py_exc_to_status_message_iterator(self_message_iterator); + BT_ASSERT(status != __BT_FUNC_STATUS_OK); + goto end; + +error: + /* Handling of errors that don't cause a Python exception to be set. */ + status = __BT_FUNC_STATUS_ERROR; + +end: + BT_ASSERT(!PyErr_Occurred()); + + Py_XDECREF(py_comp_cls); + Py_XDECREF(py_iter_cls); + Py_XDECREF(py_iter_ptr); + Py_XDECREF(py_component_port_output_ptr); + Py_XDECREF(py_init_method_result); + Py_XDECREF(py_iter); + return status; +} + +static +bt_component_class_message_iterator_init_method_status +component_class_source_message_iterator_init( + bt_self_message_iterator *self_message_iterator, + bt_self_component_source *self_component_source, + bt_self_component_port_output *self_component_port_output) +{ + bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source); + + return component_class_message_iterator_init(self_message_iterator, self_component, self_component_port_output); +} + +static +bt_component_class_message_iterator_init_method_status +component_class_filter_message_iterator_init( + bt_self_message_iterator *self_message_iterator, + bt_self_component_filter *self_component_filter, + bt_self_component_port_output *self_component_port_output) +{ + bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter); + + return component_class_message_iterator_init(self_message_iterator, self_component, self_component_port_output); +} + +static +void component_class_message_iterator_finalize( + bt_self_message_iterator *message_iterator) +{ + PyObject *py_message_iter = bt_self_message_iterator_get_data( + message_iterator); + PyObject *py_method_result = NULL; + + BT_ASSERT(py_message_iter); + + /* Call user's _user_finalize() method */ + py_method_result = PyObject_CallMethod(py_message_iter, + "_user_finalize", NULL); + + if (PyErr_Occurred()) { + bt_self_component *self_comp = + bt_self_message_iterator_borrow_component( + message_iterator); + bt_logging_level log_level = get_self_component_log_level( + self_comp); + + BT_COMP_LOG_CUR_LVL(BT_LOG_WARNING, log_level, self_comp, + "User's _user_finalize() method raised an exception: ignoring:"); + logw_exception(get_self_message_iterator_log_level( + message_iterator)); + } + + /* + * Ignore any exception raised by the _user_finalize() method + * because it won't change anything at this point: the component + * is being destroyed anyway. + */ + PyErr_Clear(); + Py_XDECREF(py_method_result); + Py_DECREF(py_message_iter); +} + +/* Valid for both sources and filters. */ + +static +bt_component_class_message_iterator_next_method_status +component_class_message_iterator_next( + bt_self_message_iterator *message_iterator, + bt_message_array_const msgs, uint64_t capacity, + uint64_t *count) +{ + bt_component_class_message_iterator_next_method_status status = __BT_FUNC_STATUS_OK; + PyObject *py_message_iter = bt_self_message_iterator_get_data(message_iterator); + PyObject *py_method_result = NULL; + + BT_ASSERT(py_message_iter); + py_method_result = PyObject_CallMethod(py_message_iter, + "_bt_next_from_native", NULL); + if (!py_method_result) { + status = py_exc_to_status_message_iterator(message_iterator); + BT_ASSERT(status != __BT_FUNC_STATUS_OK); + goto end; + } + + /* + * The returned object, on success, is an integer object + * (PyLong) containing the address of a native message + * object (which is now ours). + */ + msgs[0] = PyLong_AsVoidPtr(py_method_result); + *count = 1; + + /* Clear potential overflow error; should never happen */ + BT_ASSERT(!PyErr_Occurred()); + goto end; + +end: + Py_XDECREF(py_method_result); + return status; +} + +static +bt_component_class_sink_consume_method_status +component_class_sink_consume(bt_self_component_sink *self_component_sink) +{ + bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink); + PyObject *py_comp = bt_self_component_get_data(self_component); + PyObject *py_method_result = NULL; + bt_component_class_sink_consume_method_status status; + + BT_ASSERT(py_comp); + py_method_result = PyObject_CallMethod(py_comp, + "_user_consume", NULL); + status = py_exc_to_status_component(self_component); + BT_ASSERT(py_method_result || status != __BT_FUNC_STATUS_OK); + Py_XDECREF(py_method_result); + return status; +} + +static +int component_class_set_help_and_desc( + bt_component_class *component_class, + const char *description, const char *help) +{ + int ret; + + if (description) { + ret = bt_component_class_set_description(component_class, description); + if (ret) { + BT_LOGE("Cannot set component class's description: " + "comp-cls-addr=%p", component_class); + goto end; + } + } + + if (help) { + ret = bt_component_class_set_help(component_class, help); + if (ret) { + BT_LOGE("Cannot set component class's help text: " + "comp-cls-addr=%p", component_class); + goto end; + } + } + + ret = 0; + +end: + return ret; +} + +static +bt_component_class_source *bt_bt2_component_class_source_create( + PyObject *py_cls, const char *name, const char *description, + const char *help) +{ + bt_component_class_source *component_class_source; + bt_component_class *component_class; + int ret; + + BT_ASSERT(py_cls); + component_class_source = bt_component_class_source_create(name, + component_class_message_iterator_next); + if (!component_class_source) { + BT_LOGE_STR("Cannot create source component class."); + goto end; + } + + component_class = bt_component_class_source_as_component_class(component_class_source); + + if (component_class_set_help_and_desc(component_class, description, help)) { + goto end; + } + + ret = bt_component_class_source_set_init_method(component_class_source, component_class_source_init); + BT_ASSERT(ret == 0); + ret = bt_component_class_source_set_finalize_method(component_class_source, component_class_source_finalize); + BT_ASSERT(ret == 0); + ret = bt_component_class_source_set_message_iterator_can_seek_beginning_method(component_class_source, + component_class_can_seek_beginning); + BT_ASSERT(ret == 0); + ret = bt_component_class_source_set_message_iterator_seek_beginning_method(component_class_source, + component_class_seek_beginning); + BT_ASSERT(ret == 0); + ret = bt_component_class_source_set_output_port_connected_method(component_class_source, + component_class_source_output_port_connected); + BT_ASSERT(ret == 0); + ret = bt_component_class_source_set_query_method(component_class_source, component_class_source_query); + BT_ASSERT(ret == 0); + ret = bt_component_class_source_set_message_iterator_init_method( + component_class_source, component_class_source_message_iterator_init); + BT_ASSERT(ret == 0); + ret = bt_component_class_source_set_message_iterator_finalize_method( + component_class_source, component_class_message_iterator_finalize); + BT_ASSERT(ret == 0); + register_cc_ptr_to_py_cls(component_class, py_cls); + +end: + return component_class_source; +} + +static +bt_component_class_filter *bt_bt2_component_class_filter_create( + PyObject *py_cls, const char *name, const char *description, + const char *help) +{ + bt_component_class *component_class; + bt_component_class_filter *component_class_filter; + int ret; + + BT_ASSERT(py_cls); + component_class_filter = bt_component_class_filter_create(name, + component_class_message_iterator_next); + if (!component_class_filter) { + BT_LOGE_STR("Cannot create filter component class."); + goto end; + } + + component_class = bt_component_class_filter_as_component_class(component_class_filter); + + if (component_class_set_help_and_desc(component_class, description, help)) { + goto end; + } + + ret = bt_component_class_filter_set_init_method(component_class_filter, component_class_filter_init); + BT_ASSERT(ret == 0); + ret = bt_component_class_filter_set_finalize_method (component_class_filter, component_class_filter_finalize); + BT_ASSERT(ret == 0); + ret = bt_component_class_filter_set_message_iterator_can_seek_beginning_method(component_class_filter, + component_class_can_seek_beginning); + BT_ASSERT(ret == 0); + ret = bt_component_class_filter_set_message_iterator_seek_beginning_method(component_class_filter, + component_class_seek_beginning); + BT_ASSERT(ret == 0); + ret = bt_component_class_filter_set_input_port_connected_method(component_class_filter, + component_class_filter_input_port_connected); + BT_ASSERT(ret == 0); + ret = bt_component_class_filter_set_output_port_connected_method(component_class_filter, + component_class_filter_output_port_connected); + BT_ASSERT(ret == 0); + ret = bt_component_class_filter_set_query_method(component_class_filter, component_class_filter_query); + BT_ASSERT(ret == 0); + ret = bt_component_class_filter_set_message_iterator_init_method( + component_class_filter, component_class_filter_message_iterator_init); + BT_ASSERT(ret == 0); + ret = bt_component_class_filter_set_message_iterator_finalize_method( + component_class_filter, component_class_message_iterator_finalize); + BT_ASSERT(ret == 0); + register_cc_ptr_to_py_cls(component_class, py_cls); + +end: + return component_class_filter; +} + +static +bt_component_class_sink *bt_bt2_component_class_sink_create( + PyObject *py_cls, const char *name, const char *description, + const char *help) +{ + bt_component_class_sink *component_class_sink; + bt_component_class *component_class; + int ret; + + BT_ASSERT(py_cls); + component_class_sink = bt_component_class_sink_create(name, component_class_sink_consume); + + if (!component_class_sink) { + BT_LOGE_STR("Cannot create sink component class."); + goto end; + } + + component_class = bt_component_class_sink_as_component_class(component_class_sink); + + if (component_class_set_help_and_desc(component_class, description, help)) { + goto end; + } + + ret = bt_component_class_sink_set_init_method(component_class_sink, component_class_sink_init); + BT_ASSERT(ret == 0); + ret = bt_component_class_sink_set_finalize_method(component_class_sink, component_class_sink_finalize); + BT_ASSERT(ret == 0); + ret = bt_component_class_sink_set_input_port_connected_method(component_class_sink, + component_class_sink_input_port_connected); + BT_ASSERT(ret == 0); + ret = bt_component_class_sink_set_graph_is_configured_method(component_class_sink, + component_class_sink_graph_is_configured); + BT_ASSERT(ret == 0); + ret = bt_component_class_sink_set_query_method(component_class_sink, component_class_sink_query); + BT_ASSERT(ret == 0); + register_cc_ptr_to_py_cls(component_class, py_cls); + +end: + return component_class_sink; +} diff --git a/src/bindings/python/bt2/bt2/native_bt_graph.i b/src/bindings/python/bt2/bt2/native_bt_graph.i index a4e72a2f..ccb3c246 100644 --- a/src/bindings/python/bt2/bt2/native_bt_graph.i +++ b/src/bindings/python/bt2/bt2/native_bt_graph.i @@ -107,497 +107,7 @@ /* Helper functions for Python */ %{ -static -void graph_listener_removed(void *py_callable) -{ - BT_ASSERT(py_callable); - Py_DECREF(py_callable); -} - -static bt_graph_listener_func_status port_added_listener( - const void *component, - swig_type_info *component_swig_type, - bt_component_class_type component_class_type, - const void *port, - swig_type_info *port_swig_type, - bt_port_type port_type, - void *py_callable) -{ - PyObject *py_component_ptr = NULL; - PyObject *py_port_ptr = NULL; - PyObject *py_res = NULL; - bt_graph_listener_func_status status; - - py_component_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(component), component_swig_type, 0); - if (!py_component_ptr) { - BT_LOGF_STR("Failed to create component SWIG pointer object."); - status = __BT_FUNC_STATUS_MEMORY_ERROR; - goto end; - } - - py_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(port), port_swig_type, 0); - if (!py_port_ptr) { - BT_LOGF_STR("Failed to create port SWIG pointer object."); - status = __BT_FUNC_STATUS_MEMORY_ERROR; - goto end; - } - - py_res = PyObject_CallFunction(py_callable, "(OiOi)", - py_component_ptr, component_class_type, py_port_ptr, port_type); - if (!py_res) { - loge_exception("Graph's port added listener (Python)", - BT_LOG_OUTPUT_LEVEL); - PyErr_Clear(); - status = __BT_FUNC_STATUS_ERROR; - goto end; - } - - BT_ASSERT(py_res == Py_None); - status = __BT_FUNC_STATUS_OK; - -end: - Py_XDECREF(py_res); - Py_XDECREF(py_port_ptr); - Py_XDECREF(py_component_ptr); - return status; -} - -static -bt_graph_listener_func_status -source_component_output_port_added_listener(const bt_component_source *component_source, - const bt_port_output *port_output, void *py_callable) -{ - return port_added_listener( - component_source, SWIGTYPE_p_bt_component_source, BT_COMPONENT_CLASS_TYPE_SOURCE, - port_output, SWIGTYPE_p_bt_port_output, BT_PORT_TYPE_OUTPUT, py_callable); -} - -static -bt_graph_listener_func_status -filter_component_input_port_added_listener(const bt_component_filter *component_filter, - const bt_port_input *port_input, void *py_callable) -{ - return port_added_listener( - component_filter, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER, - port_input, SWIGTYPE_p_bt_port_input, BT_PORT_TYPE_INPUT, py_callable); -} - -static -bt_graph_listener_func_status -filter_component_output_port_added_listener(const bt_component_filter *component_filter, - const bt_port_output *port_output, void *py_callable) -{ - return port_added_listener( - component_filter, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER, - port_output, SWIGTYPE_p_bt_port_output, BT_PORT_TYPE_OUTPUT, py_callable); -} - -static -bt_graph_listener_func_status -sink_component_input_port_added_listener(const bt_component_sink *component_sink, - const bt_port_input *port_input, void *py_callable) -{ - return port_added_listener( - component_sink, SWIGTYPE_p_bt_component_sink, BT_COMPONENT_CLASS_TYPE_SINK, - port_input, SWIGTYPE_p_bt_port_input, BT_PORT_TYPE_INPUT, py_callable); -} - -static -PyObject *bt_bt2_graph_add_port_added_listener(struct bt_graph *graph, - PyObject *py_callable) -{ - PyObject *py_listener_ids = NULL; - PyObject *py_listener_id = NULL; - bt_listener_id listener_id; - bt_graph_add_listener_status status; - const char * const module_name = - "graph_add_port_added_listener() (Python)"; - - BT_ASSERT(graph); - BT_ASSERT(py_callable); - - /* - * Behind the scene, we will be registering 4 different listeners and - * return all of their ids. - */ - py_listener_ids = PyTuple_New(4); - if (!py_listener_ids) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, - "Failed to allocate one PyTuple."); - goto error; - } - - /* source output port */ - status = bt_graph_add_source_component_output_port_added_listener( - graph, source_component_output_port_added_listener, - graph_listener_removed, py_callable, &listener_id); - if (status != __BT_FUNC_STATUS_OK) { - /* - * bt_graph_add_source_component_output_port_added_listener has - * already logged/appended an error cause. - */ - goto error; - } - - py_listener_id = PyLong_FromUnsignedLongLong(listener_id); - if (!py_listener_id) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, - "Failed to allocate one PyLong."); - goto error; - } - - PyTuple_SET_ITEM(py_listener_ids, 0, py_listener_id); - py_listener_id = NULL; - - /* filter input port */ - status = bt_graph_add_filter_component_input_port_added_listener( - graph, filter_component_input_port_added_listener, - graph_listener_removed, py_callable, &listener_id); - if (status != __BT_FUNC_STATUS_OK) { - /* - * bt_graph_add_filter_component_input_port_added_listener has - * already logged/appended an error cause. - */ - goto error; - } - - py_listener_id = PyLong_FromUnsignedLongLong(listener_id); - if (!py_listener_id) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, - "Failed to allocate one PyLong."); - goto error; - } - - PyTuple_SET_ITEM(py_listener_ids, 1, py_listener_id); - py_listener_id = NULL; - - /* filter output port */ - status = bt_graph_add_filter_component_output_port_added_listener( - graph, filter_component_output_port_added_listener, - graph_listener_removed, py_callable, &listener_id); - if (status != __BT_FUNC_STATUS_OK) { - /* - * bt_graph_add_filter_component_output_port_added_listener has - * already logged/appended an error cause. - */ - goto error; - } - - py_listener_id = PyLong_FromUnsignedLongLong(listener_id); - if (!py_listener_id) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, - "Failed to allocate one PyLong."); - goto error; - } - - PyTuple_SET_ITEM(py_listener_ids, 2, py_listener_id); - py_listener_id = NULL; - - /* sink input port */ - status = bt_graph_add_sink_component_input_port_added_listener( - graph, sink_component_input_port_added_listener, - graph_listener_removed, py_callable, &listener_id); - if (status != __BT_FUNC_STATUS_OK) { - /* - * bt_graph_add_sink_component_input_port_added_listener has - * already logged/appended an error cause. - */ - goto error; - } - - py_listener_id = PyLong_FromUnsignedLongLong(listener_id); - if (!py_listener_id) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, - "Failed to allocate one PyLong."); - goto error; - } - - - PyTuple_SET_ITEM(py_listener_ids, 3, py_listener_id); - py_listener_id = NULL; - - Py_INCREF(py_callable); - Py_INCREF(py_callable); - Py_INCREF(py_callable); - Py_INCREF(py_callable); - - goto end; - -error: - Py_XDECREF(py_listener_ids); - py_listener_ids = Py_None; - Py_INCREF(py_listener_ids); - -end: - - Py_XDECREF(py_listener_id); - return py_listener_ids; -} - -static -bt_graph_listener_func_status ports_connected_listener( - const void *upstream_component, - swig_type_info *upstream_component_swig_type, - bt_component_class_type upstream_component_class_type, - const bt_port_output *upstream_port, - const void *downstream_component, - swig_type_info *downstream_component_swig_type, - bt_component_class_type downstream_component_class_type, - const bt_port_input *downstream_port, - void *py_callable) -{ - PyObject *py_upstream_component_ptr = NULL; - PyObject *py_upstream_port_ptr = NULL; - PyObject *py_downstream_component_ptr = NULL; - PyObject *py_downstream_port_ptr = NULL; - PyObject *py_res = NULL; - bt_graph_listener_func_status status; - - py_upstream_component_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(upstream_component), - upstream_component_swig_type, 0); - if (!py_upstream_component_ptr) { - BT_LOGF_STR("Failed to create upstream component SWIG pointer object."); - status = __BT_FUNC_STATUS_MEMORY_ERROR; - goto end; - } - - py_upstream_port_ptr = SWIG_NewPointerObj( - SWIG_as_voidptr(upstream_port), SWIGTYPE_p_bt_port_output, 0); - if (!py_upstream_port_ptr) { - BT_LOGF_STR("Failed to create upstream port SWIG pointer object."); - status = __BT_FUNC_STATUS_MEMORY_ERROR; - goto end; - } - - py_downstream_component_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(downstream_component), - downstream_component_swig_type, 0); - if (!py_downstream_component_ptr) { - BT_LOGF_STR("Failed to create downstream component SWIG pointer object."); - status = __BT_FUNC_STATUS_MEMORY_ERROR; - goto end; - } - - py_downstream_port_ptr = SWIG_NewPointerObj( - SWIG_as_voidptr(downstream_port), SWIGTYPE_p_bt_port_input, 0); - if (!py_downstream_port_ptr) { - BT_LOGF_STR("Failed to create downstream port SWIG pointer object."); - status = __BT_FUNC_STATUS_MEMORY_ERROR; - goto end; - } - - py_res = PyObject_CallFunction(py_callable, "(OiOOiO)", - py_upstream_component_ptr, upstream_component_class_type, - py_upstream_port_ptr, - py_downstream_component_ptr, downstream_component_class_type, - py_downstream_port_ptr); - if (!py_res) { - loge_exception("Graph's port connected listener (Python)", - BT_LOG_OUTPUT_LEVEL); - PyErr_Clear(); - status = __BT_FUNC_STATUS_ERROR; - goto end; - } - - BT_ASSERT(py_res == Py_None); - status = __BT_FUNC_STATUS_OK; - -end: - Py_XDECREF(py_upstream_component_ptr); - Py_XDECREF(py_upstream_port_ptr); - Py_XDECREF(py_downstream_component_ptr); - Py_XDECREF(py_downstream_port_ptr); - Py_XDECREF(py_res); - return status; -} - -static -bt_graph_listener_func_status source_filter_component_ports_connected_listener( - const bt_component_source *source_component, - const bt_component_filter *filter_component, - const bt_port_output *upstream_port, - const bt_port_input *downstream_port, void *py_callable) -{ - return ports_connected_listener( - source_component, SWIGTYPE_p_bt_component_source, BT_COMPONENT_CLASS_TYPE_SOURCE, - upstream_port, - filter_component, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER, - downstream_port, - py_callable); -} - -static -bt_graph_listener_func_status source_sink_component_ports_connected_listener( - const bt_component_source *source_component, - const bt_component_sink *sink_component, - const bt_port_output *upstream_port, - const bt_port_input *downstream_port, void *py_callable) -{ - return ports_connected_listener( - source_component, SWIGTYPE_p_bt_component_source, BT_COMPONENT_CLASS_TYPE_SOURCE, - upstream_port, - sink_component, SWIGTYPE_p_bt_component_sink, BT_COMPONENT_CLASS_TYPE_SINK, - downstream_port, - py_callable); -} - -static -bt_graph_listener_func_status filter_filter_component_ports_connected_listener( - const bt_component_filter *filter_component_left, - const bt_component_filter *filter_component_right, - const bt_port_output *upstream_port, - const bt_port_input *downstream_port, void *py_callable) -{ - return ports_connected_listener( - filter_component_left, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER, - upstream_port, - filter_component_right, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER, - downstream_port, - py_callable); -} - -static -bt_graph_listener_func_status filter_sink_component_ports_connected_listener( - const bt_component_filter *filter_component, - const bt_component_sink *sink_component, - const bt_port_output *upstream_port, - const bt_port_input *downstream_port, void *py_callable) -{ - return ports_connected_listener( - filter_component, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER, - upstream_port, - sink_component, SWIGTYPE_p_bt_component_sink, BT_COMPONENT_CLASS_TYPE_SINK, - downstream_port, - py_callable); -} - -static -PyObject *bt_bt2_graph_add_ports_connected_listener(struct bt_graph *graph, - PyObject *py_callable) -{ - PyObject *py_listener_ids = NULL; - PyObject *py_listener_id = NULL; - bt_listener_id listener_id; - bt_graph_add_listener_status status; - const char * const module_name = - "graph_add_ports_connected_listener() (Python)"; - - BT_ASSERT(graph); - BT_ASSERT(py_callable); - - /* Behind the scene, we will be registering 4 different listeners and - * return all of their ids. */ - py_listener_ids = PyTuple_New(4); - if (!py_listener_ids) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, - "Failed to allocate one PyTuple."); - goto error; - } - - /* source -> filter connection */ - status = bt_graph_add_source_filter_component_ports_connected_listener( - graph, source_filter_component_ports_connected_listener, - graph_listener_removed, py_callable, &listener_id); - if (status != __BT_FUNC_STATUS_OK) { - /* - * bt_graph_add_source_filter_component_ports_connected_listener - * has already logged/appended an error cause. - */ - goto error; - } - - py_listener_id = PyLong_FromUnsignedLongLong(listener_id); - if (!py_listener_id) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, - "Failed to allocate one PyLong."); - goto error; - } - - PyTuple_SET_ITEM(py_listener_ids, 0, py_listener_id); - py_listener_id = NULL; - - /* source -> sink connection */ - status = bt_graph_add_source_sink_component_ports_connected_listener( - graph, source_sink_component_ports_connected_listener, - graph_listener_removed, py_callable, &listener_id); - if (status != __BT_FUNC_STATUS_OK) { - /* - * bt_graph_add_source_sink_component_ports_connected_listener - * has already logged/appended an error cause. - */ - goto error; - } - - py_listener_id = PyLong_FromUnsignedLongLong(listener_id); - if (!py_listener_id) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, - "Failed to allocate one PyLong."); - goto error; - } - - PyTuple_SET_ITEM(py_listener_ids, 1, py_listener_id); - py_listener_id = NULL; - - /* filter -> filter connection */ - status = bt_graph_add_filter_filter_component_ports_connected_listener( - graph, filter_filter_component_ports_connected_listener, - graph_listener_removed, py_callable, &listener_id); - if (status != __BT_FUNC_STATUS_OK) { - /* - * bt_graph_add_filter_filter_component_ports_connected_listener - * has already logged/appended an error cause. - */ - goto error; - } - - py_listener_id = PyLong_FromUnsignedLongLong(listener_id); - if (!py_listener_id) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, - "Failed to allocate one PyLong."); - goto error; - } - - PyTuple_SET_ITEM(py_listener_ids, 2, py_listener_id); - py_listener_id = NULL; - - /* filter -> sink connection */ - status = bt_graph_add_filter_sink_component_ports_connected_listener( - graph, filter_sink_component_ports_connected_listener, - graph_listener_removed, py_callable, &listener_id); - if (status != __BT_FUNC_STATUS_OK) { - /* - * bt_graph_add_filter_sink_component_ports_connected_listener - * has already logged/appended an error cause. - */ - goto error; - } - - py_listener_id = PyLong_FromUnsignedLongLong(listener_id); - if (!py_listener_id) { - BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, - "Failed to allocate one PyLong."); - goto error; - } - - PyTuple_SET_ITEM(py_listener_ids, 3, py_listener_id); - py_listener_id = NULL; - - Py_INCREF(py_callable); - Py_INCREF(py_callable); - Py_INCREF(py_callable); - Py_INCREF(py_callable); - - goto end; - -error: - Py_XDECREF(py_listener_ids); - py_listener_ids = Py_None; - Py_INCREF(py_listener_ids); - -end: - - Py_XDECREF(py_listener_id); - return py_listener_ids; -} +#include "native_bt_graph.i.h" %} PyObject *bt_bt2_graph_add_port_added_listener(struct bt_graph *graph, diff --git a/src/bindings/python/bt2/bt2/native_bt_graph.i.h b/src/bindings/python/bt2/bt2/native_bt_graph.i.h new file mode 100644 index 00000000..bccc1825 --- /dev/null +++ b/src/bindings/python/bt2/bt2/native_bt_graph.i.h @@ -0,0 +1,515 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +static +void graph_listener_removed(void *py_callable) +{ + BT_ASSERT(py_callable); + Py_DECREF(py_callable); +} + +static bt_graph_listener_func_status port_added_listener( + const void *component, + swig_type_info *component_swig_type, + bt_component_class_type component_class_type, + const void *port, + swig_type_info *port_swig_type, + bt_port_type port_type, + void *py_callable) +{ + PyObject *py_component_ptr = NULL; + PyObject *py_port_ptr = NULL; + PyObject *py_res = NULL; + bt_graph_listener_func_status status; + + py_component_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(component), component_swig_type, 0); + if (!py_component_ptr) { + BT_LOGF_STR("Failed to create component SWIG pointer object."); + status = __BT_FUNC_STATUS_MEMORY_ERROR; + goto end; + } + + py_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(port), port_swig_type, 0); + if (!py_port_ptr) { + BT_LOGF_STR("Failed to create port SWIG pointer object."); + status = __BT_FUNC_STATUS_MEMORY_ERROR; + goto end; + } + + py_res = PyObject_CallFunction(py_callable, "(OiOi)", + py_component_ptr, component_class_type, py_port_ptr, port_type); + if (!py_res) { + loge_exception("Graph's port added listener (Python)", + BT_LOG_OUTPUT_LEVEL); + PyErr_Clear(); + status = __BT_FUNC_STATUS_ERROR; + goto end; + } + + BT_ASSERT(py_res == Py_None); + status = __BT_FUNC_STATUS_OK; + +end: + Py_XDECREF(py_res); + Py_XDECREF(py_port_ptr); + Py_XDECREF(py_component_ptr); + return status; +} + +static +bt_graph_listener_func_status +source_component_output_port_added_listener(const bt_component_source *component_source, + const bt_port_output *port_output, void *py_callable) +{ + return port_added_listener( + component_source, SWIGTYPE_p_bt_component_source, BT_COMPONENT_CLASS_TYPE_SOURCE, + port_output, SWIGTYPE_p_bt_port_output, BT_PORT_TYPE_OUTPUT, py_callable); +} + +static +bt_graph_listener_func_status +filter_component_input_port_added_listener(const bt_component_filter *component_filter, + const bt_port_input *port_input, void *py_callable) +{ + return port_added_listener( + component_filter, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER, + port_input, SWIGTYPE_p_bt_port_input, BT_PORT_TYPE_INPUT, py_callable); +} + +static +bt_graph_listener_func_status +filter_component_output_port_added_listener(const bt_component_filter *component_filter, + const bt_port_output *port_output, void *py_callable) +{ + return port_added_listener( + component_filter, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER, + port_output, SWIGTYPE_p_bt_port_output, BT_PORT_TYPE_OUTPUT, py_callable); +} + +static +bt_graph_listener_func_status +sink_component_input_port_added_listener(const bt_component_sink *component_sink, + const bt_port_input *port_input, void *py_callable) +{ + return port_added_listener( + component_sink, SWIGTYPE_p_bt_component_sink, BT_COMPONENT_CLASS_TYPE_SINK, + port_input, SWIGTYPE_p_bt_port_input, BT_PORT_TYPE_INPUT, py_callable); +} + +static +PyObject *bt_bt2_graph_add_port_added_listener(struct bt_graph *graph, + PyObject *py_callable) +{ + PyObject *py_listener_ids = NULL; + PyObject *py_listener_id = NULL; + bt_listener_id listener_id; + bt_graph_add_listener_status status; + const char * const module_name = + "graph_add_port_added_listener() (Python)"; + + BT_ASSERT(graph); + BT_ASSERT(py_callable); + + /* + * Behind the scene, we will be registering 4 different listeners and + * return all of their ids. + */ + py_listener_ids = PyTuple_New(4); + if (!py_listener_ids) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, + "Failed to allocate one PyTuple."); + goto error; + } + + /* source output port */ + status = bt_graph_add_source_component_output_port_added_listener( + graph, source_component_output_port_added_listener, + graph_listener_removed, py_callable, &listener_id); + if (status != __BT_FUNC_STATUS_OK) { + /* + * bt_graph_add_source_component_output_port_added_listener has + * already logged/appended an error cause. + */ + goto error; + } + + py_listener_id = PyLong_FromUnsignedLongLong(listener_id); + if (!py_listener_id) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, + "Failed to allocate one PyLong."); + goto error; + } + + PyTuple_SET_ITEM(py_listener_ids, 0, py_listener_id); + py_listener_id = NULL; + + /* filter input port */ + status = bt_graph_add_filter_component_input_port_added_listener( + graph, filter_component_input_port_added_listener, + graph_listener_removed, py_callable, &listener_id); + if (status != __BT_FUNC_STATUS_OK) { + /* + * bt_graph_add_filter_component_input_port_added_listener has + * already logged/appended an error cause. + */ + goto error; + } + + py_listener_id = PyLong_FromUnsignedLongLong(listener_id); + if (!py_listener_id) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, + "Failed to allocate one PyLong."); + goto error; + } + + PyTuple_SET_ITEM(py_listener_ids, 1, py_listener_id); + py_listener_id = NULL; + + /* filter output port */ + status = bt_graph_add_filter_component_output_port_added_listener( + graph, filter_component_output_port_added_listener, + graph_listener_removed, py_callable, &listener_id); + if (status != __BT_FUNC_STATUS_OK) { + /* + * bt_graph_add_filter_component_output_port_added_listener has + * already logged/appended an error cause. + */ + goto error; + } + + py_listener_id = PyLong_FromUnsignedLongLong(listener_id); + if (!py_listener_id) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, + "Failed to allocate one PyLong."); + goto error; + } + + PyTuple_SET_ITEM(py_listener_ids, 2, py_listener_id); + py_listener_id = NULL; + + /* sink input port */ + status = bt_graph_add_sink_component_input_port_added_listener( + graph, sink_component_input_port_added_listener, + graph_listener_removed, py_callable, &listener_id); + if (status != __BT_FUNC_STATUS_OK) { + /* + * bt_graph_add_sink_component_input_port_added_listener has + * already logged/appended an error cause. + */ + goto error; + } + + py_listener_id = PyLong_FromUnsignedLongLong(listener_id); + if (!py_listener_id) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, + "Failed to allocate one PyLong."); + goto error; + } + + + PyTuple_SET_ITEM(py_listener_ids, 3, py_listener_id); + py_listener_id = NULL; + + Py_INCREF(py_callable); + Py_INCREF(py_callable); + Py_INCREF(py_callable); + Py_INCREF(py_callable); + + goto end; + +error: + Py_XDECREF(py_listener_ids); + py_listener_ids = Py_None; + Py_INCREF(py_listener_ids); + +end: + + Py_XDECREF(py_listener_id); + return py_listener_ids; +} + +static +bt_graph_listener_func_status ports_connected_listener( + const void *upstream_component, + swig_type_info *upstream_component_swig_type, + bt_component_class_type upstream_component_class_type, + const bt_port_output *upstream_port, + const void *downstream_component, + swig_type_info *downstream_component_swig_type, + bt_component_class_type downstream_component_class_type, + const bt_port_input *downstream_port, + void *py_callable) +{ + PyObject *py_upstream_component_ptr = NULL; + PyObject *py_upstream_port_ptr = NULL; + PyObject *py_downstream_component_ptr = NULL; + PyObject *py_downstream_port_ptr = NULL; + PyObject *py_res = NULL; + bt_graph_listener_func_status status; + + py_upstream_component_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(upstream_component), + upstream_component_swig_type, 0); + if (!py_upstream_component_ptr) { + BT_LOGF_STR("Failed to create upstream component SWIG pointer object."); + status = __BT_FUNC_STATUS_MEMORY_ERROR; + goto end; + } + + py_upstream_port_ptr = SWIG_NewPointerObj( + SWIG_as_voidptr(upstream_port), SWIGTYPE_p_bt_port_output, 0); + if (!py_upstream_port_ptr) { + BT_LOGF_STR("Failed to create upstream port SWIG pointer object."); + status = __BT_FUNC_STATUS_MEMORY_ERROR; + goto end; + } + + py_downstream_component_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(downstream_component), + downstream_component_swig_type, 0); + if (!py_downstream_component_ptr) { + BT_LOGF_STR("Failed to create downstream component SWIG pointer object."); + status = __BT_FUNC_STATUS_MEMORY_ERROR; + goto end; + } + + py_downstream_port_ptr = SWIG_NewPointerObj( + SWIG_as_voidptr(downstream_port), SWIGTYPE_p_bt_port_input, 0); + if (!py_downstream_port_ptr) { + BT_LOGF_STR("Failed to create downstream port SWIG pointer object."); + status = __BT_FUNC_STATUS_MEMORY_ERROR; + goto end; + } + + py_res = PyObject_CallFunction(py_callable, "(OiOOiO)", + py_upstream_component_ptr, upstream_component_class_type, + py_upstream_port_ptr, + py_downstream_component_ptr, downstream_component_class_type, + py_downstream_port_ptr); + if (!py_res) { + loge_exception("Graph's port connected listener (Python)", + BT_LOG_OUTPUT_LEVEL); + PyErr_Clear(); + status = __BT_FUNC_STATUS_ERROR; + goto end; + } + + BT_ASSERT(py_res == Py_None); + status = __BT_FUNC_STATUS_OK; + +end: + Py_XDECREF(py_upstream_component_ptr); + Py_XDECREF(py_upstream_port_ptr); + Py_XDECREF(py_downstream_component_ptr); + Py_XDECREF(py_downstream_port_ptr); + Py_XDECREF(py_res); + return status; +} + +static +bt_graph_listener_func_status source_filter_component_ports_connected_listener( + const bt_component_source *source_component, + const bt_component_filter *filter_component, + const bt_port_output *upstream_port, + const bt_port_input *downstream_port, void *py_callable) +{ + return ports_connected_listener( + source_component, SWIGTYPE_p_bt_component_source, BT_COMPONENT_CLASS_TYPE_SOURCE, + upstream_port, + filter_component, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER, + downstream_port, + py_callable); +} + +static +bt_graph_listener_func_status source_sink_component_ports_connected_listener( + const bt_component_source *source_component, + const bt_component_sink *sink_component, + const bt_port_output *upstream_port, + const bt_port_input *downstream_port, void *py_callable) +{ + return ports_connected_listener( + source_component, SWIGTYPE_p_bt_component_source, BT_COMPONENT_CLASS_TYPE_SOURCE, + upstream_port, + sink_component, SWIGTYPE_p_bt_component_sink, BT_COMPONENT_CLASS_TYPE_SINK, + downstream_port, + py_callable); +} + +static +bt_graph_listener_func_status filter_filter_component_ports_connected_listener( + const bt_component_filter *filter_component_left, + const bt_component_filter *filter_component_right, + const bt_port_output *upstream_port, + const bt_port_input *downstream_port, void *py_callable) +{ + return ports_connected_listener( + filter_component_left, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER, + upstream_port, + filter_component_right, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER, + downstream_port, + py_callable); +} + +static +bt_graph_listener_func_status filter_sink_component_ports_connected_listener( + const bt_component_filter *filter_component, + const bt_component_sink *sink_component, + const bt_port_output *upstream_port, + const bt_port_input *downstream_port, void *py_callable) +{ + return ports_connected_listener( + filter_component, SWIGTYPE_p_bt_component_filter, BT_COMPONENT_CLASS_TYPE_FILTER, + upstream_port, + sink_component, SWIGTYPE_p_bt_component_sink, BT_COMPONENT_CLASS_TYPE_SINK, + downstream_port, + py_callable); +} + +static +PyObject *bt_bt2_graph_add_ports_connected_listener(struct bt_graph *graph, + PyObject *py_callable) +{ + PyObject *py_listener_ids = NULL; + PyObject *py_listener_id = NULL; + bt_listener_id listener_id; + bt_graph_add_listener_status status; + const char * const module_name = + "graph_add_ports_connected_listener() (Python)"; + + BT_ASSERT(graph); + BT_ASSERT(py_callable); + + /* Behind the scene, we will be registering 4 different listeners and + * return all of their ids. */ + py_listener_ids = PyTuple_New(4); + if (!py_listener_ids) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, + "Failed to allocate one PyTuple."); + goto error; + } + + /* source -> filter connection */ + status = bt_graph_add_source_filter_component_ports_connected_listener( + graph, source_filter_component_ports_connected_listener, + graph_listener_removed, py_callable, &listener_id); + if (status != __BT_FUNC_STATUS_OK) { + /* + * bt_graph_add_source_filter_component_ports_connected_listener + * has already logged/appended an error cause. + */ + goto error; + } + + py_listener_id = PyLong_FromUnsignedLongLong(listener_id); + if (!py_listener_id) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, + "Failed to allocate one PyLong."); + goto error; + } + + PyTuple_SET_ITEM(py_listener_ids, 0, py_listener_id); + py_listener_id = NULL; + + /* source -> sink connection */ + status = bt_graph_add_source_sink_component_ports_connected_listener( + graph, source_sink_component_ports_connected_listener, + graph_listener_removed, py_callable, &listener_id); + if (status != __BT_FUNC_STATUS_OK) { + /* + * bt_graph_add_source_sink_component_ports_connected_listener + * has already logged/appended an error cause. + */ + goto error; + } + + py_listener_id = PyLong_FromUnsignedLongLong(listener_id); + if (!py_listener_id) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, + "Failed to allocate one PyLong."); + goto error; + } + + PyTuple_SET_ITEM(py_listener_ids, 1, py_listener_id); + py_listener_id = NULL; + + /* filter -> filter connection */ + status = bt_graph_add_filter_filter_component_ports_connected_listener( + graph, filter_filter_component_ports_connected_listener, + graph_listener_removed, py_callable, &listener_id); + if (status != __BT_FUNC_STATUS_OK) { + /* + * bt_graph_add_filter_filter_component_ports_connected_listener + * has already logged/appended an error cause. + */ + goto error; + } + + py_listener_id = PyLong_FromUnsignedLongLong(listener_id); + if (!py_listener_id) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, + "Failed to allocate one PyLong."); + goto error; + } + + PyTuple_SET_ITEM(py_listener_ids, 2, py_listener_id); + py_listener_id = NULL; + + /* filter -> sink connection */ + status = bt_graph_add_filter_sink_component_ports_connected_listener( + graph, filter_sink_component_ports_connected_listener, + graph_listener_removed, py_callable, &listener_id); + if (status != __BT_FUNC_STATUS_OK) { + /* + * bt_graph_add_filter_sink_component_ports_connected_listener + * has already logged/appended an error cause. + */ + goto error; + } + + py_listener_id = PyLong_FromUnsignedLongLong(listener_id); + if (!py_listener_id) { + BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(module_name, + "Failed to allocate one PyLong."); + goto error; + } + + PyTuple_SET_ITEM(py_listener_ids, 3, py_listener_id); + py_listener_id = NULL; + + Py_INCREF(py_callable); + Py_INCREF(py_callable); + Py_INCREF(py_callable); + Py_INCREF(py_callable); + + goto end; + +error: + Py_XDECREF(py_listener_ids); + py_listener_ids = Py_None; + Py_INCREF(py_listener_ids); + +end: + + Py_XDECREF(py_listener_id); + return py_listener_ids; +} diff --git a/src/bindings/python/bt2/bt2/native_bt_message_iterator.i b/src/bindings/python/bt2/bt2/native_bt_message_iterator.i index eaae1ee7..7ebd7836 100644 --- a/src/bindings/python/bt2/bt2/native_bt_message_iterator.i +++ b/src/bindings/python/bt2/bt2/native_bt_message_iterator.i @@ -29,90 +29,7 @@ /* Helper functions for Python */ %{ -static PyObject *bt_bt2_get_user_component_from_user_msg_iter( - bt_self_message_iterator *self_message_iterator) -{ - bt_self_component *self_component = bt_self_message_iterator_borrow_component(self_message_iterator); - PyObject *py_comp; - - BT_ASSERT(self_component); - py_comp = bt_self_component_get_data(self_component); - BT_ASSERT(py_comp); - - /* Return new reference */ - Py_INCREF(py_comp); - return py_comp; -} - -static inline -PyObject *create_pylist_from_messages(bt_message_array_const messages, - uint64_t message_count) -{ - uint64_t i; - PyObject *py_msg_list = PyList_New(message_count); - - BT_ASSERT(py_msg_list); - - for (i = 0; i < message_count; i++) { - PyList_SET_ITEM(py_msg_list, i, - SWIG_NewPointerObj(SWIG_as_voidptr(messages[i]), - SWIGTYPE_p_bt_message, 0)); - } - - return py_msg_list; -} - -static -PyObject *get_msg_range_common(bt_message_iterator_next_status status, - bt_message_array_const messages, uint64_t message_count) -{ - PyObject *py_status; - PyObject *py_return_tuple; - PyObject *py_msg_list; - - py_return_tuple = PyTuple_New(2); - BT_ASSERT(py_return_tuple); - - /* Set tuple[0], status. */ - py_status = SWIG_From_long_SS_long(status); - PyTuple_SET_ITEM(py_return_tuple, 0, py_status); - - /* Set tuple[1], message list on success, None otherwise. */ - if (status == __BT_FUNC_STATUS_OK) { - py_msg_list = create_pylist_from_messages(messages, message_count); - } else { - py_msg_list = Py_None; - Py_INCREF(py_msg_list); - } - - PyTuple_SET_ITEM(py_return_tuple, 1, py_msg_list); - - return py_return_tuple; -} - -static PyObject *bt_bt2_self_component_port_input_get_msg_range( - bt_self_component_port_input_message_iterator *iter) -{ - bt_message_array_const messages; - uint64_t message_count = 0; - bt_message_iterator_next_status status; - - status = bt_self_component_port_input_message_iterator_next(iter, - &messages, &message_count); - return get_msg_range_common(status, messages, message_count); -} - -static PyObject *bt_bt2_port_output_get_msg_range( - bt_port_output_message_iterator *iter) -{ - bt_message_array_const messages; - uint64_t message_count = 0; - bt_message_iterator_next_status status; - - status = bt_port_output_message_iterator_next(iter, &messages, - &message_count); - return get_msg_range_common(status, messages, message_count); -} +#include "native_bt_message_iterator.i.h" %} PyObject *bt_bt2_get_user_component_from_user_msg_iter( diff --git a/src/bindings/python/bt2/bt2/native_bt_message_iterator.i.h b/src/bindings/python/bt2/bt2/native_bt_message_iterator.i.h new file mode 100644 index 00000000..2ce15de3 --- /dev/null +++ b/src/bindings/python/bt2/bt2/native_bt_message_iterator.i.h @@ -0,0 +1,108 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +static PyObject *bt_bt2_get_user_component_from_user_msg_iter( + bt_self_message_iterator *self_message_iterator) +{ + bt_self_component *self_component = bt_self_message_iterator_borrow_component(self_message_iterator); + PyObject *py_comp; + + BT_ASSERT(self_component); + py_comp = bt_self_component_get_data(self_component); + BT_ASSERT(py_comp); + + /* Return new reference */ + Py_INCREF(py_comp); + return py_comp; +} + +static inline +PyObject *create_pylist_from_messages(bt_message_array_const messages, + uint64_t message_count) +{ + uint64_t i; + PyObject *py_msg_list = PyList_New(message_count); + + BT_ASSERT(py_msg_list); + + for (i = 0; i < message_count; i++) { + PyList_SET_ITEM(py_msg_list, i, + SWIG_NewPointerObj(SWIG_as_voidptr(messages[i]), + SWIGTYPE_p_bt_message, 0)); + } + + return py_msg_list; +} + +static +PyObject *get_msg_range_common(bt_message_iterator_next_status status, + bt_message_array_const messages, uint64_t message_count) +{ + PyObject *py_status; + PyObject *py_return_tuple; + PyObject *py_msg_list; + + py_return_tuple = PyTuple_New(2); + BT_ASSERT(py_return_tuple); + + /* Set tuple[0], status. */ + py_status = SWIG_From_long_SS_long(status); + PyTuple_SET_ITEM(py_return_tuple, 0, py_status); + + /* Set tuple[1], message list on success, None otherwise. */ + if (status == __BT_FUNC_STATUS_OK) { + py_msg_list = create_pylist_from_messages(messages, message_count); + } else { + py_msg_list = Py_None; + Py_INCREF(py_msg_list); + } + + PyTuple_SET_ITEM(py_return_tuple, 1, py_msg_list); + + return py_return_tuple; +} + +static PyObject *bt_bt2_self_component_port_input_get_msg_range( + bt_self_component_port_input_message_iterator *iter) +{ + bt_message_array_const messages; + uint64_t message_count = 0; + bt_message_iterator_next_status status; + + status = bt_self_component_port_input_message_iterator_next(iter, + &messages, &message_count); + return get_msg_range_common(status, messages, message_count); +} + +static PyObject *bt_bt2_port_output_get_msg_range( + bt_port_output_message_iterator *iter) +{ + bt_message_array_const messages; + uint64_t message_count = 0; + bt_message_iterator_next_status status; + + status = bt_port_output_message_iterator_next(iter, &messages, + &message_count); + return get_msg_range_common(status, messages, message_count); +} diff --git a/src/bindings/python/bt2/bt2/native_bt_plugin.i b/src/bindings/python/bt2/bt2/native_bt_plugin.i index a0c2b3f1..e96ea6ed 100644 --- a/src/bindings/python/bt2/bt2/native_bt_plugin.i +++ b/src/bindings/python/bt2/bt2/native_bt_plugin.i @@ -69,6 +69,10 @@ /* Helpers */ +%{ +#include "native_bt_plugin.i.h" +%} + bt_property_availability bt_bt2_plugin_get_version( const bt_plugin *plugin, unsigned int *major, unsigned int *minor, unsigned int *patch, const char **extra); @@ -90,92 +94,3 @@ bt_plugin_find_all_from_file_status bt_bt2_plugin_find_all_from_file( bt_plugin_find_all_from_dir_status bt_bt2_plugin_find_all_from_dir( const char *path, bt_bool recurse, bt_bool fail_on_load_error, const bt_plugin_set **plugin_set); - -%{ -/* - * Those bt_bt2_*() functions below ensure that when the API function - * fails, the output parameter is set to `NULL`. This is necessary - * because the epilogue of the `something **OUT` typemap will use that - * value to make a Python object. We can't rely on the initial value of - * `*OUT`; it could point to unreadable memory. - */ - -bt_property_availability bt_bt2_plugin_get_version( - const bt_plugin *plugin, unsigned int *major, - unsigned int *minor, unsigned int *patch, const char **extra) -{ - bt_property_availability ret; - - ret = bt_plugin_get_version(plugin, major, minor, patch, extra); - - if (ret == BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) { - *extra = NULL; - } - - return ret; -} - -bt_plugin_find_status bt_bt2_plugin_find(const char *plugin_name, - bt_bool find_in_std_env_var, bt_bool find_in_user_dir, - bt_bool find_in_sys_dir, bt_bool find_in_static, - bt_bool fail_on_load_error, const bt_plugin **plugin) -{ - bt_plugin_find_status status; - - status = bt_plugin_find(plugin_name, find_in_std_env_var, - find_in_user_dir, find_in_sys_dir, find_in_static, - fail_on_load_error, plugin); - if (status != __BT_FUNC_STATUS_OK) { - *plugin = NULL; - } - - return status; -} - -bt_plugin_find_all_status bt_bt2_plugin_find_all(bt_bool find_in_std_env_var, - bt_bool find_in_user_dir, bt_bool find_in_sys_dir, - bt_bool find_in_static, bt_bool fail_on_load_error, - const bt_plugin_set **plugin_set) -{ - bt_plugin_find_all_status status; - - status = bt_plugin_find_all(find_in_std_env_var, - find_in_user_dir, find_in_sys_dir, find_in_static, - fail_on_load_error, plugin_set); - if (status != __BT_FUNC_STATUS_OK) { - *plugin_set = NULL; - } - - return status; -} - -bt_plugin_find_all_from_file_status bt_bt2_plugin_find_all_from_file( - const char *path, bt_bool fail_on_load_error, - const bt_plugin_set **plugin_set) -{ - bt_plugin_find_all_from_file_status status; - - status = bt_plugin_find_all_from_file(path, fail_on_load_error, - plugin_set); - if (status != __BT_FUNC_STATUS_OK) { - *plugin_set = NULL; - } - - return status; -} - -bt_plugin_find_all_from_dir_status bt_bt2_plugin_find_all_from_dir( - const char *path, bt_bool recurse, bt_bool fail_on_load_error, - const bt_plugin_set **plugin_set) -{ - bt_plugin_find_all_from_dir_status status; - - status = bt_plugin_find_all_from_dir(path, recurse, fail_on_load_error, - plugin_set); - if (status != __BT_FUNC_STATUS_OK) { - *plugin_set = NULL; - } - - return status; -} -%} diff --git a/src/bindings/python/bt2/bt2/native_bt_plugin.i.h b/src/bindings/python/bt2/bt2/native_bt_plugin.i.h new file mode 100644 index 00000000..7b15a213 --- /dev/null +++ b/src/bindings/python/bt2/bt2/native_bt_plugin.i.h @@ -0,0 +1,110 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2017 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* + * Those bt_bt2_*() functions below ensure that when the API function + * fails, the output parameter is set to `NULL`. This is necessary + * because the epilogue of the `something **OUT` typemap will use that + * value to make a Python object. We can't rely on the initial value of + * `*OUT`; it could point to unreadable memory. + */ + +bt_property_availability bt_bt2_plugin_get_version( + const bt_plugin *plugin, unsigned int *major, + unsigned int *minor, unsigned int *patch, const char **extra) +{ + bt_property_availability ret; + + ret = bt_plugin_get_version(plugin, major, minor, patch, extra); + + if (ret == BT_PROPERTY_AVAILABILITY_NOT_AVAILABLE) { + *extra = NULL; + } + + return ret; +} + +bt_plugin_find_status bt_bt2_plugin_find(const char *plugin_name, + bt_bool find_in_std_env_var, bt_bool find_in_user_dir, + bt_bool find_in_sys_dir, bt_bool find_in_static, + bt_bool fail_on_load_error, const bt_plugin **plugin) +{ + bt_plugin_find_status status; + + status = bt_plugin_find(plugin_name, find_in_std_env_var, + find_in_user_dir, find_in_sys_dir, find_in_static, + fail_on_load_error, plugin); + if (status != __BT_FUNC_STATUS_OK) { + *plugin = NULL; + } + + return status; +} + +bt_plugin_find_all_status bt_bt2_plugin_find_all(bt_bool find_in_std_env_var, + bt_bool find_in_user_dir, bt_bool find_in_sys_dir, + bt_bool find_in_static, bt_bool fail_on_load_error, + const bt_plugin_set **plugin_set) +{ + bt_plugin_find_all_status status; + + status = bt_plugin_find_all(find_in_std_env_var, + find_in_user_dir, find_in_sys_dir, find_in_static, + fail_on_load_error, plugin_set); + if (status != __BT_FUNC_STATUS_OK) { + *plugin_set = NULL; + } + + return status; +} + +bt_plugin_find_all_from_file_status bt_bt2_plugin_find_all_from_file( + const char *path, bt_bool fail_on_load_error, + const bt_plugin_set **plugin_set) +{ + bt_plugin_find_all_from_file_status status; + + status = bt_plugin_find_all_from_file(path, fail_on_load_error, + plugin_set); + if (status != __BT_FUNC_STATUS_OK) { + *plugin_set = NULL; + } + + return status; +} + +bt_plugin_find_all_from_dir_status bt_bt2_plugin_find_all_from_dir( + const char *path, bt_bool recurse, bt_bool fail_on_load_error, + const bt_plugin_set **plugin_set) +{ + bt_plugin_find_all_from_dir_status status; + + status = bt_plugin_find_all_from_dir(path, recurse, fail_on_load_error, + plugin_set); + if (status != __BT_FUNC_STATUS_OK) { + *plugin_set = NULL; + } + + return status; +} diff --git a/src/bindings/python/bt2/bt2/native_bt_trace.i b/src/bindings/python/bt2/bt2/native_bt_trace.i index f771ef45..5ecccf0c 100644 --- a/src/bindings/python/bt2/bt2/native_bt_trace.i +++ b/src/bindings/python/bt2/bt2/native_bt_trace.i @@ -26,46 +26,7 @@ %include %{ -static void -trace_destroyed_listener(const bt_trace *trace, void *py_callable) -{ - PyObject *py_trace_ptr = NULL; - PyObject *py_res = NULL; - - py_trace_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(trace), - SWIGTYPE_p_bt_trace, 0); - if (!py_trace_ptr) { - BT_LOGF_STR("Failed to create a SWIG pointer object."); - abort(); - } - - py_res = PyObject_CallFunction(py_callable, "(O)", py_trace_ptr); - if (py_res) { - BT_ASSERT(py_res == Py_None); - } else { - loge_exception("Trace's destruction listener (Python)", - BT_LOG_OUTPUT_LEVEL); - } - - Py_DECREF(py_trace_ptr); - Py_XDECREF(py_res); -} - -int bt_bt2_trace_add_destruction_listener(bt_trace *trace, - PyObject *py_callable, bt_listener_id *id) -{ - bt_trace_add_listener_status status; - - BT_ASSERT(trace); - BT_ASSERT(py_callable); - status = bt_trace_add_destruction_listener( - trace, trace_destroyed_listener, py_callable, id); - if (status == __BT_FUNC_STATUS_OK) { - Py_INCREF(py_callable); - } - - return status; -} +#include "native_bt_trace.i.h" %} int bt_bt2_trace_add_destruction_listener(bt_trace *trace, diff --git a/src/bindings/python/bt2/bt2/native_bt_trace.i.h b/src/bindings/python/bt2/bt2/native_bt_trace.i.h new file mode 100644 index 00000000..708142e6 --- /dev/null +++ b/src/bindings/python/bt2/bt2/native_bt_trace.i.h @@ -0,0 +1,65 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +static void +trace_destroyed_listener(const bt_trace *trace, void *py_callable) +{ + PyObject *py_trace_ptr = NULL; + PyObject *py_res = NULL; + + py_trace_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(trace), + SWIGTYPE_p_bt_trace, 0); + if (!py_trace_ptr) { + BT_LOGF_STR("Failed to create a SWIG pointer object."); + abort(); + } + + py_res = PyObject_CallFunction(py_callable, "(O)", py_trace_ptr); + if (py_res) { + BT_ASSERT(py_res == Py_None); + } else { + loge_exception("Trace's destruction listener (Python)", + BT_LOG_OUTPUT_LEVEL); + } + + Py_DECREF(py_trace_ptr); + Py_XDECREF(py_res); +} + +static +int bt_bt2_trace_add_destruction_listener(bt_trace *trace, + PyObject *py_callable, bt_listener_id *id) +{ + bt_trace_add_listener_status status; + + BT_ASSERT(trace); + BT_ASSERT(py_callable); + status = bt_trace_add_destruction_listener( + trace, trace_destroyed_listener, py_callable, id); + if (status == __BT_FUNC_STATUS_OK) { + Py_INCREF(py_callable); + } + + return status; +} diff --git a/src/bindings/python/bt2/bt2/native_bt_trace_class.i b/src/bindings/python/bt2/bt2/native_bt_trace_class.i index e0605664..cc079379 100644 --- a/src/bindings/python/bt2/bt2/native_bt_trace_class.i +++ b/src/bindings/python/bt2/bt2/native_bt_trace_class.i @@ -27,47 +27,7 @@ /* Helper functions for Python */ %{ -static void -trace_class_destroyed_listener(const bt_trace_class *trace_class, void *py_callable) -{ - PyObject *py_trace_class_ptr = NULL; - PyObject *py_res = NULL; - - py_trace_class_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(trace_class), - SWIGTYPE_p_bt_trace_class, 0); - if (!py_trace_class_ptr) { - BT_LOGF_STR("Failed to create a SWIG pointer object."); - abort(); - } - - py_res = PyObject_CallFunction(py_callable, "(O)", py_trace_class_ptr); - if (py_res) { - BT_ASSERT(py_res == Py_None); - } else { - loge_exception("Trace class's destruction listener (Python)", - BT_LOG_OUTPUT_LEVEL); - } - - Py_DECREF(py_trace_class_ptr); - Py_XDECREF(py_res); -} - -int bt_bt2_trace_class_add_destruction_listener( - bt_trace_class *trace_class, PyObject *py_callable, - bt_listener_id *id) -{ - bt_trace_class_add_listener_status status; - - BT_ASSERT(trace_class); - BT_ASSERT(py_callable); - status = bt_trace_class_add_destruction_listener( - trace_class, trace_class_destroyed_listener, py_callable, id); - if (status == __BT_FUNC_STATUS_OK) { - Py_INCREF(py_callable); - } - - return status; -} +#include "native_bt_trace_class.i.h" %} int bt_bt2_trace_class_add_destruction_listener( diff --git a/src/bindings/python/bt2/bt2/native_bt_trace_class.i.h b/src/bindings/python/bt2/bt2/native_bt_trace_class.i.h new file mode 100644 index 00000000..5e91a6c2 --- /dev/null +++ b/src/bindings/python/bt2/bt2/native_bt_trace_class.i.h @@ -0,0 +1,66 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +static void +trace_class_destroyed_listener(const bt_trace_class *trace_class, void *py_callable) +{ + PyObject *py_trace_class_ptr = NULL; + PyObject *py_res = NULL; + + py_trace_class_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(trace_class), + SWIGTYPE_p_bt_trace_class, 0); + if (!py_trace_class_ptr) { + BT_LOGF_STR("Failed to create a SWIG pointer object."); + abort(); + } + + py_res = PyObject_CallFunction(py_callable, "(O)", py_trace_class_ptr); + if (py_res) { + BT_ASSERT(py_res == Py_None); + } else { + loge_exception("Trace class's destruction listener (Python)", + BT_LOG_OUTPUT_LEVEL); + } + + Py_DECREF(py_trace_class_ptr); + Py_XDECREF(py_res); +} + +static +int bt_bt2_trace_class_add_destruction_listener( + bt_trace_class *trace_class, PyObject *py_callable, + bt_listener_id *id) +{ + bt_trace_class_add_listener_status status; + + BT_ASSERT(trace_class); + BT_ASSERT(py_callable); + status = bt_trace_class_add_destruction_listener( + trace_class, trace_class_destroyed_listener, py_callable, id); + if (status == __BT_FUNC_STATUS_OK) { + Py_INCREF(py_callable); + } + + return status; +} diff --git a/src/bindings/python/bt2/bt2/native_bt_value.i b/src/bindings/python/bt2/bt2/native_bt_value.i index e9eea043..f31a6d44 100644 --- a/src/bindings/python/bt2/bt2/native_bt_value.i +++ b/src/bindings/python/bt2/bt2/native_bt_value.i @@ -26,49 +26,7 @@ %include %{ -struct bt_value_map_get_keys_data { - struct bt_value *keys; -}; - -static int bt_value_map_get_keys_cb(const char *key, const struct bt_value *object, void *data) -{ - bt_value_array_append_element_status status; - struct bt_value_map_get_keys_data *priv_data = data; - - status = bt_value_array_append_string_element(priv_data->keys, key); - if (status != __BT_FUNC_STATUS_OK) { - return BT_FALSE; - } - - return BT_TRUE; -} - -static struct bt_value *bt_value_map_get_keys(const struct bt_value *map_obj) -{ - bt_value_map_foreach_entry_const_status status; - struct bt_value_map_get_keys_data data; - - data.keys = bt_value_array_create(); - if (!data.keys) { - return NULL; - } - - status = bt_value_map_foreach_entry_const(map_obj, bt_value_map_get_keys_cb, - &data); - if (status != __BT_FUNC_STATUS_OK) { - goto error; - } - - goto end; - -error: - if (data.keys) { - BT_VALUE_PUT_REF_AND_RESET(data.keys); - } - -end: - return data.keys; -} +#include "native_bt_value.i.h" %} struct bt_value *bt_value_map_get_keys(const struct bt_value *map_obj); diff --git a/src/bindings/python/bt2/bt2/native_bt_value.i.h b/src/bindings/python/bt2/bt2/native_bt_value.i.h new file mode 100644 index 00000000..94645414 --- /dev/null +++ b/src/bindings/python/bt2/bt2/native_bt_value.i.h @@ -0,0 +1,67 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016 Philippe Proulx + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +struct bt_value_map_get_keys_data { + struct bt_value *keys; +}; + +static int bt_value_map_get_keys_cb(const char *key, const struct bt_value *object, void *data) +{ + bt_value_array_append_element_status status; + struct bt_value_map_get_keys_data *priv_data = data; + + status = bt_value_array_append_string_element(priv_data->keys, key); + if (status != __BT_FUNC_STATUS_OK) { + return BT_FALSE; + } + + return BT_TRUE; +} + +static struct bt_value *bt_value_map_get_keys(const struct bt_value *map_obj) +{ + bt_value_map_foreach_entry_const_status status; + struct bt_value_map_get_keys_data data; + + data.keys = bt_value_array_create(); + if (!data.keys) { + return NULL; + } + + status = bt_value_map_foreach_entry_const(map_obj, bt_value_map_get_keys_cb, + &data); + if (status != __BT_FUNC_STATUS_OK) { + goto error; + } + + goto end; + +error: + if (data.keys) { + BT_VALUE_PUT_REF_AND_RESET(data.keys); + } + +end: + return data.keys; +} -- 2.34.1