/* * 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 #include #include #include #include #include #include #include %} /* Types */ struct bt_component_class; /* Status */ enum bt_component_class_type { BT_COMPONENT_CLASS_TYPE_UNKNOWN = -1, BT_COMPONENT_CLASS_TYPE_SOURCE = 0, BT_COMPONENT_CLASS_TYPE_SINK = 1, BT_COMPONENT_CLASS_TYPE_FILTER = 2, }; /* General functions */ const char *bt_component_class_get_name( struct bt_component_class *component_class); const char *bt_component_class_get_description( struct bt_component_class *component_class); const char *bt_component_class_get_help( struct bt_component_class *component_class); struct bt_value *bt_component_class_query_info( struct bt_component_class *component_class, const char *action, struct bt_value *params); enum bt_component_class_type bt_component_class_get_type( struct bt_component_class *component_class); %{ /* * 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_py3_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) { g_hash_table_insert(bt_cc_ptr_to_py_cls, (gpointer) bt_cc, (gpointer) py_cls); } static PyObject *lookup_cc_ptr_to_py_cls(struct bt_component_class *bt_cc) { 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_unsupported_feature_type = 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_values = NULL; static PyObject *py_mod_bt2_values_create_from_ptr_func = NULL; static void bt_py3_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"); assert(py_mod_bt2); py_mod_bt2_values = PyImport_ImportModule("bt2.values"); assert(py_mod_bt2_values); py_mod_bt2_values_create_from_ptr_func = PyObject_GetAttrString(py_mod_bt2_values, "_create_from_ptr"); assert(py_mod_bt2_values_create_from_ptr_func); py_mod_bt2_exc_error_type = PyObject_GetAttrString(py_mod_bt2, "Error"); assert(py_mod_bt2_exc_error_type); py_mod_bt2_exc_unsupported_feature_type = PyObject_GetAttrString(py_mod_bt2, "UnsupportedFeature"); py_mod_bt2_exc_try_again_type = PyObject_GetAttrString(py_mod_bt2, "TryAgain"); py_mod_bt2_exc_stop_type = PyObject_GetAttrString(py_mod_bt2, "Stop"); assert(py_mod_bt2_exc_stop_type); } static void bt_py3_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_py3_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 * to 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_values_create_from_ptr_func); Py_XDECREF(py_mod_bt2_values); Py_XDECREF(py_mod_bt2); Py_XDECREF(py_mod_bt2_exc_error_type); Py_XDECREF(py_mod_bt2_exc_unsupported_feature_type); Py_XDECREF(py_mod_bt2_exc_try_again_type); Py_XDECREF(py_mod_bt2_exc_stop_type); } /* Library constructor and destructor */ __attribute__((constructor)) static void bt_py3_native_comp_class_ctor(void) { /* Initialize component class association hash table */ bt_cc_ptr_to_py_cls = g_hash_table_new(g_direct_hash, g_direct_equal); assert(bt_cc_ptr_to_py_cls); } __attribute__((destructor)) static void bt_py3_native_comp_class_dtor(void) { /* Destroy component class association hash table */ if (bt_cc_ptr_to_py_cls) { g_hash_table_destroy(bt_cc_ptr_to_py_cls); } } /* Converts a BT value object to a bt2.values object */ static PyObject *bt_py3_bt_value_from_ptr(struct bt_value *value) { PyObject *py_create_from_ptr_func = NULL; PyObject *py_value = NULL; PyObject *py_ptr = NULL; py_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(value), SWIGTYPE_p_bt_value, 0); py_value = PyObject_CallFunctionObjArgs( py_mod_bt2_values_create_from_ptr_func, py_ptr, NULL); if (!py_value) { goto end; } /* * _create_from_ptr() only wraps an existing reference. `value` * is a borrowed reference here, so increment its reference * count for this new owner. */ bt_get(value); end: Py_XDECREF(py_ptr); PyErr_Clear(); return py_value; } /* self.__init__(*args, **kwargs) */ static int bt_py3_call_self_init(PyObject *py_self, PyObject *py_args, PyObject *py_kwargs) { int ret = 0; size_t i; PyObject *py_init_method_result = NULL; PyObject *py_init_method = NULL; PyObject *py_init_method_args = NULL; PyObject *py_class = NULL; py_class = PyObject_GetAttrString(py_self, "__class__"); if (!py_class) { goto error; } py_init_method = PyObject_GetAttrString(py_class, "__init__"); if (!py_init_method) { goto error; } /* Prepend py_self to the arguments (copy them to new tuple) */ py_init_method_args = PyTuple_New(PyTuple_Size(py_args) + 1); if (!py_init_method_args) { goto error; } Py_INCREF(py_self); ret = PyTuple_SetItem(py_init_method_args, 0, py_self); if (ret < 0) { Py_DECREF(py_self); goto error; } for (i = 0; i < PyTuple_Size(py_args); i++) { PyObject *obj = PyTuple_GetItem(py_args, i); if (!obj) { goto error; } Py_INCREF(obj); ret = PyTuple_SetItem(py_init_method_args, i + 1, obj); if (ret < 0) { Py_DECREF(obj); goto error; } } py_init_method_result = PyObject_Call(py_init_method, py_init_method_args, py_kwargs); if (!py_init_method_result) { goto error; } goto end; error: ret = -1; end: Py_XDECREF(py_init_method_args); Py_XDECREF(py_init_method_result); Py_XDECREF(py_init_method); Py_XDECREF(py_class); return ret; } /* Component class proxy methods (delegate to the attached Python object) */ static enum bt_component_status bt_py3_cc_init( struct bt_component *component, struct bt_value *params, void *init_method_data) { enum bt_component_status status = BT_COMPONENT_STATUS_OK; int ret; /* * This function is either called from * _UserComponentType.__call__() (when init_method_data contains * the PyObject * currently creating this component) or from * other code (init_method_data is NULL). */ if (init_method_data) { /* * Called from _UserComponentType.__call__(). * * The `params` argument is completely ignored here, * because if the user creating the component object * from the component class object wants parameters, * they'll be in the keyword arguments anyway. */ PyObject *py_comp = init_method_data; PyObject *py_comp_ptr = NULL; PyObject *py_init_args = NULL; PyObject *py_init_kwargs = NULL; /* * No need to take a Python reference on py_comp here: * we store it as a _borrowed_ reference. When all the * Python references are dropped, the object's __del__() * method is called. This method calls this side * (bt_py3_component_on_del()) to swap the ownership: * this BT component becomes the only owner of the * Python object. */ bt_component_set_private_data(component, py_comp); /* * Set this BT component pointer as py_comp._ptr, and * take a reference on it (on success, at the end). * * This reference is put in the Python component * object's __del__() method. */ py_comp_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(component), SWIGTYPE_p_bt_component, 0); if (!py_comp_ptr) { PyErr_Clear(); goto with_init_method_data_error; } ret = PyObject_SetAttrString(py_comp, "_ptr", py_comp_ptr); if (ret < 0) { PyErr_Clear(); goto with_init_method_data_error; } /* * _UserComponentType.__call__() puts the arguments and * keyword arguments to use for the py_comp.__init__() * call in py_comp._init_args and py_comp._init_kwargs. * * We need to get them and remove them from py_comp before * calling py_comp.__init__(). */ py_init_args = PyObject_GetAttrString(py_comp, "_init_args"); if (!py_init_args) { PyErr_Clear(); goto with_init_method_data_error; } py_init_kwargs = PyObject_GetAttrString(py_comp, "_init_kwargs"); if (!py_init_kwargs) { PyErr_Clear(); goto with_init_method_data_error; } ret = PyObject_DelAttrString(py_comp, "_init_args"); if (ret < 0) { PyErr_Clear(); goto with_init_method_data_error; } ret = PyObject_DelAttrString(py_comp, "_init_kwargs"); if (ret < 0) { PyErr_Clear(); goto with_init_method_data_error; } /* Ready to call py_comp.__init__() */ ret = bt_py3_call_self_init(py_comp, py_init_args, py_init_kwargs); if (ret) { /* * We do not clear any raised exception here * so that the Python caller (the one who is * instantiating the class) gets the exception * from the __init__() method. */ goto with_init_method_data_error; } /* * py_comp.__init__() went well: get the native BT * component object reference for the Python object. */ bt_get(component); goto with_init_method_data_end; with_init_method_data_error: status = BT_COMPONENT_STATUS_ERROR; /* * Reset py_comp._ptr to None to signal the error to * _UserComponentType.__call__(). For exceptions raised * from py_comp.__init__(), this is not important, * because __call__() will also raise before even * checking py_comp._ptr. */ if (PyObject_HasAttrString(py_comp, "_ptr")) { PyObject *py_err_type, *py_err_value, *py_err_traceback; PyErr_Fetch(&py_err_type, &py_err_value, &py_err_traceback); Py_INCREF(Py_None); PyObject_SetAttrString(py_comp, "_ptr", Py_None); PyErr_Restore(py_err_type, py_err_value, py_err_traceback); } /* * Important: remove py_comp from our the BT component's * private data. Since we're failing, * bt_py3_cc_destroy() is about to be called: it must * not consider py_comp. py_comp's __del__() method * will be called (because the instance exists), but * since py_comp._ptr is None, it won't do anything. */ bt_component_set_private_data(component, NULL); with_init_method_data_end: Py_XDECREF(py_comp_ptr); Py_XDECREF(py_init_args); Py_XDECREF(py_init_kwargs); } else { /* * Not called from _UserComponentType.__call__(). * * In this case we need to instantiate the user-defined * Python class. To do this we call the user-defined * class manually with this already-created BT component * object pointer as the __comp_ptr keyword argument. * * We keep a reference, the only existing one, to the * created Python object. bt_py3_component_on_del() will * never be called by the object's __del__() method * because _UserComponentType.__call__() marks the * object as owned by the native BT component object. */ PyObject *py_cls = NULL; PyObject *py_comp = NULL; PyObject *py_params = NULL; PyObject *py_comp_ptr = NULL; PyObject *py_cls_ctor_args = NULL; PyObject *py_cls_ctor_kwargs = NULL; /* * 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(bt_component_get_class(component)); if (!py_cls) { goto without_init_method_data_error; } /* BT value object -> Python bt2.values object */ py_params = bt_py3_bt_value_from_ptr(params); if (!py_params) { goto without_init_method_data_error; } /* Component pointer -> SWIG pointer Python object */ py_comp_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(component), SWIGTYPE_p_bt_component, 0); if (!py_comp_ptr) { goto without_init_method_data_error; } /* * Do the equivalent of this: * * py_comp = py_cls(__comp_ptr=py_comp_ptr, params=py_params) * * _UserComponentType.__call__() calls the Python * component object's __init__() function itself in this * case. */ py_cls_ctor_args = PyTuple_New(0); if (!py_cls_ctor_args) { goto without_init_method_data_error; } py_cls_ctor_kwargs = PyDict_New(); if (!py_cls_ctor_kwargs) { goto without_init_method_data_error; } ret = PyDict_SetItemString(py_cls_ctor_kwargs, "__comp_ptr", py_comp_ptr); if (ret < 0) { goto without_init_method_data_error; } ret = PyDict_SetItemString(py_cls_ctor_kwargs, "params", py_params); if (ret < 0) { goto without_init_method_data_error; } py_comp = PyObject_Call(py_cls, py_cls_ctor_args, py_cls_ctor_kwargs); if (!py_comp) { goto without_init_method_data_error; } /* * Our user Python component object is now fully created * and initialized by the user. Since we just created * it, this BT component is its only (persistent) owner. */ bt_component_set_private_data(component, py_comp); py_comp = NULL; goto without_init_method_data_end; without_init_method_data_error: status = BT_COMPONENT_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(); without_init_method_data_end: Py_XDECREF(py_comp); Py_XDECREF(py_params); Py_XDECREF(py_comp_ptr); Py_XDECREF(py_cls_ctor_args); Py_XDECREF(py_cls_ctor_kwargs); } return status; } static void bt_py3_cc_destroy(struct bt_component *component) { PyObject *py_comp = bt_component_get_private_data(component); PyObject *py_destroy_method_result = NULL; if (py_comp) { /* * If we're here, this BT component is the only owner of * its private user Python object. It is safe to * decrement its reference count, and thus destroy it. * * We call its _destroy() method before doing so to notify * the Python user. */ py_destroy_method_result = PyObject_CallMethod(py_comp, "_destroy", NULL); /* * Ignore any exception raised by the _destroy() method * because it won't change anything at this point: the * component is being destroyed anyway. */ PyErr_Clear(); Py_XDECREF(py_destroy_method_result); Py_DECREF(py_comp); } } static struct bt_value *bt_py3_cc_query_info( struct bt_component_class *component_class, const char *action, struct bt_value *params) { PyObject *py_cls = NULL; PyObject *py_params = NULL; PyObject *py_query_info_func = NULL; PyObject *py_action = NULL; PyObject *py_results_addr = NULL; struct bt_value *results = NULL; py_cls = lookup_cc_ptr_to_py_cls(component_class); if (!py_cls) { goto error; } py_params = bt_py3_bt_value_from_ptr(params); if (!py_params) { goto error; } py_action = SWIG_FromCharPtr(action); if (!py_action) { goto error; } py_results_addr = PyObject_CallMethod(py_cls, "_query_info_from_bt", "(OO)", py_action, py_params); if (!py_results_addr) { goto error; } /* * The returned object, on success, is an integer object * (PyLong) containing the address of a BT value object * (which is now ours). */ results = (struct bt_value *) PyLong_AsUnsignedLongLong( py_results_addr); /* Clear potential overflow error; should never happen */ if (PyErr_Occurred()) { results = NULL; goto error; } if (!results) { goto error; } goto end; error: BT_PUT(results); PyErr_Clear(); end: Py_XDECREF(py_params); Py_XDECREF(py_query_info_func); Py_XDECREF(py_action); Py_XDECREF(py_results_addr); return results; } static enum bt_notification_iterator_status bt_py3_exc_to_notif_iter_status(void) { enum bt_notification_iterator_status status = BT_NOTIFICATION_ITERATOR_STATUS_OK; PyObject *exc = PyErr_Occurred(); if (!exc) { goto end; } if (PyErr_GivenExceptionMatches(exc, py_mod_bt2_exc_unsupported_feature_type)) { status = BT_NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED; } else if (PyErr_GivenExceptionMatches(exc, py_mod_bt2_exc_stop_type)) { status = BT_NOTIFICATION_ITERATOR_STATUS_END; } else { status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; } end: PyErr_Clear(); return status; } static enum bt_notification_iterator_status bt_py3_cc_notification_iterator_init( struct bt_component *component, struct bt_notification_iterator *iter, void *init_method_data) { enum bt_notification_iterator_status status = BT_NOTIFICATION_ITERATOR_STATUS_OK; PyObject *py_comp_cls = NULL; PyObject *py_iter_cls = NULL; PyObject *py_iter_ptr = NULL; PyObject *py_init_method_result = NULL; PyObject *py_iter = NULL; PyObject *py_comp = bt_component_get_private_data(component); /* Find user's Python notification iterator class */ py_comp_cls = PyObject_GetAttrString(py_comp, "__class__"); if (!py_comp_cls) { goto error; } py_iter_cls = PyObject_GetAttrString(py_comp_cls, "_iter_cls"); if (!py_iter_cls) { goto error; } /* * Create object with borrowed BT notification iterator * reference: * * py_iter = py_iter_cls.__new__(py_iter_cls, py_iter_ptr) */ py_iter_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(iter), SWIGTYPE_p_bt_notification_iterator, 0); if (!py_iter_ptr) { goto error; } py_iter = PyObject_CallMethod(py_iter_cls, "__new__", "(OO)", py_iter_cls, py_iter_ptr); if (!py_iter) { goto error; } /* * Initialize object: * * py_iter.__init__() * * At this point, py_iter._ptr is set, so this initialization * function has access to the py_iter.component property (which * gives it the user Python component object from which the * iterator was created). */ py_init_method_result = PyObject_CallMethod(py_iter, "__init__", NULL); if (!py_init_method_result) { goto error; } /* * Since the Python code can never instantiate a user-defined * notification iterator class, the BT notification iterator * object does NOT belong to a user Python notification iterator * object (borrowed reference). However this Python object is * owned by this BT notification iterator object. * * In the Python world, the lifetime of the BT notification * iterator is managed by a _GenericNotificationIterator * instance: * * _GenericNotificationIterator instance: * owns a native bt_notification_iterator object (iter) * owns a UserNotificationIterator instance (py_iter) * self._ptr is a borrowed reference to the * native bt_notification_iterator object (iter) */ bt_notification_iterator_set_private_data(iter, py_iter); py_iter = NULL; goto end; error: status = bt_py3_exc_to_notif_iter_status(); if (status == BT_NOTIFICATION_ITERATOR_STATUS_OK) { /* * Looks like there wasn't any exception from the Python * side, but we're still in an error state here. */ status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; } /* * Clear any exception: we're returning a bad status anyway. If * this call originated from Python, then the user gets an * appropriate creation error. */ PyErr_Clear(); end: Py_XDECREF(py_comp_cls); Py_XDECREF(py_iter_cls); Py_XDECREF(py_iter_ptr); Py_XDECREF(py_init_method_result); Py_XDECREF(py_iter); return status; } static void bt_py3_cc_notification_iterator_destroy( struct bt_notification_iterator *iter) { PyObject *py_notif_iter = bt_notification_iterator_get_private_data(iter); PyObject *py_destroy_method_result = NULL; assert(py_notif_iter); py_destroy_method_result = PyObject_CallMethod(py_notif_iter, "_destroy", NULL); /* * Ignore any exception raised by the _destroy() method because * it won't change anything at this point. The notification * iterator is being destroyed anyway. */ PyErr_Clear(); Py_XDECREF(py_destroy_method_result); Py_DECREF(py_notif_iter); } static struct bt_notification *bt_py3_cc_notification_iterator_get( struct bt_notification_iterator *iter) { PyObject *py_notif_iter = bt_notification_iterator_get_private_data(iter); PyObject *py_get_method_result = NULL; struct bt_notification *notif = NULL; assert(py_notif_iter); py_get_method_result = PyObject_CallMethod(py_notif_iter, "_get_from_bt", NULL); if (!py_get_method_result) { goto error; } /* * The returned object, on success, is an integer object * (PyLong) containing the address of a BT notification * object (which is now ours). */ notif = (struct bt_notification *) PyLong_AsUnsignedLongLong( py_get_method_result); /* Clear potential overflow error; should never happen */ if (PyErr_Occurred()) { notif = NULL; goto error; } if (!notif) { goto error; } goto end; error: BT_PUT(notif); /* * Clear any exception: we're returning NULL anyway. If this * call originated from Python, then the user gets an * appropriate error. */ PyErr_Clear(); end: Py_XDECREF(py_get_method_result); return notif; } static enum bt_notification_iterator_status bt_py3_cc_notification_iterator_next( struct bt_notification_iterator *iter) { enum bt_notification_iterator_status status; PyObject *py_notif_iter = bt_notification_iterator_get_private_data(iter); PyObject *py_next_method_result = NULL; assert(py_notif_iter); py_next_method_result = PyObject_CallMethod(py_notif_iter, "_next", NULL); status = bt_py3_exc_to_notif_iter_status(); if (!py_next_method_result && status == BT_NOTIFICATION_ITERATOR_STATUS_OK) { /* Pretty sure this should never happen, but just in case */ status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; } Py_XDECREF(py_next_method_result); return status; } static enum bt_notification_iterator_status bt_py3_cc_notification_iterator_seek_time( struct bt_notification_iterator *iter, int64_t time) { enum bt_notification_iterator_status status; PyObject *py_notif_iter = bt_notification_iterator_get_private_data(iter); PyObject *py_seek_to_time_method_result = NULL; assert(py_notif_iter); py_seek_to_time_method_result = PyObject_CallMethod(py_notif_iter, "_seek_to_time", "(L)", time); status = bt_py3_exc_to_notif_iter_status(); if (!py_seek_to_time_method_result && status == BT_NOTIFICATION_ITERATOR_STATUS_OK) { /* Pretty sure this should never happen, but just in case */ status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR; } Py_XDECREF(py_seek_to_time_method_result); return status; } static enum bt_component_status bt_py3_exc_to_component_status(void) { enum bt_component_status status = BT_COMPONENT_STATUS_OK; PyObject *exc = PyErr_Occurred(); if (!exc) { goto end; } if (PyErr_GivenExceptionMatches(exc, py_mod_bt2_exc_unsupported_feature_type)) { status = BT_COMPONENT_STATUS_UNSUPPORTED; } else if (PyErr_GivenExceptionMatches(exc, py_mod_bt2_exc_try_again_type)) { status = BT_COMPONENT_STATUS_AGAIN; } else if (PyErr_GivenExceptionMatches(exc, py_mod_bt2_exc_stop_type)) { status = BT_COMPONENT_STATUS_END; } else { status = BT_COMPONENT_STATUS_ERROR; } end: PyErr_Clear(); return status; } static enum bt_component_status bt_py3_cc_sink_consume( struct bt_component *component) { PyObject *py_comp = bt_component_get_private_data(component); PyObject *py_consume_method_result = NULL; enum bt_component_status status; py_consume_method_result = PyObject_CallMethod(py_comp, "_consume", NULL); status = bt_py3_exc_to_component_status(); if (!py_consume_method_result && status == BT_COMPONENT_STATUS_OK) { /* Pretty sure this should never happen, but just in case */ status = BT_COMPONENT_STATUS_ERROR; } Py_XDECREF(py_consume_method_result); return status; } static enum bt_component_status bt_py3_cc_sink_filter_add_iterator( struct bt_component *component, struct bt_notification_iterator *iter) { PyObject *py_comp = bt_component_get_private_data(component); PyObject *py_add_iterator_method_result = NULL; PyObject *py_notif_iter_ptr = NULL; enum bt_component_status status; py_notif_iter_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(iter), SWIGTYPE_p_bt_notification_iterator, 0); if (!py_notif_iter_ptr) { PyErr_Clear(); status = BT_COMPONENT_STATUS_ERROR; goto end; } bt_get(iter); py_add_iterator_method_result = PyObject_CallMethod(py_comp, "_add_iterator_from_bt", "(O)", py_notif_iter_ptr); status = bt_py3_exc_to_component_status(); if (!py_add_iterator_method_result && status == BT_COMPONENT_STATUS_OK) { /* Pretty sure this should never happen, but just in case */ status = BT_COMPONENT_STATUS_ERROR; } end: Py_XDECREF(py_notif_iter_ptr); Py_XDECREF(py_add_iterator_method_result); return status; } /* Component class creation functions (called from Python module) */ static int bt_py3_cc_set_optional_attrs_methods(struct bt_component_class *cc, const char *description, const char *help) { int ret = 0; if (description) { ret = bt_component_class_set_description(cc, description); if (ret) { goto end; } } if (help) { ret = bt_component_class_set_help(cc, help); if (ret) { goto end; } } ret = bt_component_class_set_init_method(cc, bt_py3_cc_init); if (ret) { goto end; } ret = bt_component_class_set_destroy_method(cc, bt_py3_cc_destroy); if (ret) { goto end; } ret = bt_component_class_set_query_info_method(cc, bt_py3_cc_query_info); if (ret) { goto end; } end: return ret; } static int bt_py3_cc_set_optional_iter_methods(struct bt_component_class *cc, bool has_seek_time, int (*set_notif_iter_init_method)(struct bt_component_class *, bt_component_class_notification_iterator_init_method), int (*set_notif_iter_destroy_method)(struct bt_component_class *, bt_component_class_notification_iterator_destroy_method), int (*set_notif_iter_seek_time_method)(struct bt_component_class *, bt_component_class_notification_iterator_seek_time_method)) { int ret; ret = set_notif_iter_init_method( cc, bt_py3_cc_notification_iterator_init); if (ret) { goto end; } ret = set_notif_iter_destroy_method( cc, bt_py3_cc_notification_iterator_destroy); if (ret) { goto end; } if (has_seek_time) { ret = set_notif_iter_seek_time_method( cc, bt_py3_cc_notification_iterator_seek_time); if (ret) { goto end; } } end: return ret; } static struct bt_component_class *bt_py3_component_class_source_create( PyObject *py_cls, const char *name, const char *description, const char *help, bool has_seek_time) { struct bt_component_class *cc; int ret; assert(py_cls); cc = bt_component_class_source_create(name, bt_py3_cc_notification_iterator_get, bt_py3_cc_notification_iterator_next); if (!cc) { goto end; } ret = bt_py3_cc_set_optional_attrs_methods(cc, description, help); if (ret) { BT_PUT(cc); goto end; } ret = bt_py3_cc_set_optional_iter_methods(cc, has_seek_time, bt_component_class_source_set_notification_iterator_init_method, bt_component_class_source_set_notification_iterator_destroy_method, bt_component_class_source_set_notification_iterator_seek_time_method); if (ret) { BT_PUT(cc); goto end; } register_cc_ptr_to_py_cls(cc, py_cls); bt_component_class_freeze(cc); end: return cc; } static struct bt_component_class *bt_py3_component_class_filter_create( PyObject *py_cls, const char *name, const char *description, const char *help, bool has_seek_time) { struct bt_component_class *cc; int ret; assert(py_cls); cc = bt_component_class_filter_create(name, bt_py3_cc_notification_iterator_get, bt_py3_cc_notification_iterator_next); if (!cc) { goto end; } ret = bt_py3_cc_set_optional_attrs_methods(cc, description, help); if (ret) { BT_PUT(cc); goto end; } ret = bt_py3_cc_set_optional_iter_methods(cc, has_seek_time, bt_component_class_filter_set_notification_iterator_init_method, bt_component_class_filter_set_notification_iterator_destroy_method, bt_component_class_filter_set_notification_iterator_seek_time_method); if (ret) { BT_PUT(cc); goto end; } ret = bt_component_class_filter_set_add_iterator_method(cc, bt_py3_cc_sink_filter_add_iterator); if (ret) { BT_PUT(cc); goto end; } register_cc_ptr_to_py_cls(cc, py_cls); bt_component_class_freeze(cc); end: return cc; } static struct bt_component_class *bt_py3_component_class_sink_create( PyObject *py_cls, const char *name, const char *description, const char *help) { struct bt_component_class *cc; int ret; assert(py_cls); cc = bt_component_class_sink_create(name, bt_py3_cc_sink_consume); if (!cc) { goto end; } ret = bt_py3_cc_set_optional_attrs_methods(cc, description, help); if (ret) { BT_PUT(cc); goto end; } ret = bt_component_class_sink_set_add_iterator_method(cc, bt_py3_cc_sink_filter_add_iterator); if (ret) { BT_PUT(cc); goto end; } register_cc_ptr_to_py_cls(cc, py_cls); bt_component_class_freeze(cc); end: return cc; } /* Component creation function (called from Python module) */ static void bt_py3_component_create( struct bt_component_class *comp_class, PyObject *py_self, const char *name) { struct bt_component *component = bt_component_create_with_init_method_data(comp_class, name, NULL, py_self); /* * Our component initialization function, bt_py3_cc_init(), sets * a new reference to the created component in the user's Python * object (py_self._ptr). This is where the reference is kept. * We don't need the returned component in this case (if any, * because it might be NULL if the creation failed, most * probably because py_self.__init__() raised something). */ bt_put(component); } /* Component delete notification */ static void bt_py3_component_on_del(PyObject *py_comp) { /* * The Python component's __del__() function calls this to * indicate that there's no more reference on it from the * Python world. * * Since the BT component can continue to live once the Python * component object is deleted, we increment the Python * component's reference count so that it now only belong to the * BT component. We will decrement this reference count once * the BT component is destroyed in bt_py3_cc_destroy(). */ assert(py_comp); Py_INCREF(py_comp); } %} %exception bt_py3_component_create { $action if (PyErr_Occurred()) { /* Exception is already set by bt_py3_component_create() */ SWIG_fail; } } struct bt_component_class *bt_py3_component_class_source_create( PyObject *py_cls, const char *name, const char *description, const char *help, bool has_seek_time); struct bt_component_class *bt_py3_component_class_filter_create( PyObject *py_cls, const char *name, const char *description, const char *help, bool has_seek_time); struct bt_component_class *bt_py3_component_class_sink_create( PyObject *py_cls, const char *name, const char *description, const char *help); void bt_py3_component_create( struct bt_component_class *comp_class, PyObject *py_self, const char *name); void bt_py3_component_on_del(PyObject *py_comp); void bt_py3_cc_init_from_bt2(void); void bt_py3_cc_exit_handler(void);