2 * The MIT License (MIT)
4 * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 %include <babeltrace2/graph/component-class.h>
26 %include <babeltrace2/graph/component-class-const.h>
27 %include <babeltrace2/graph/component-class-source-const.h>
28 %include <babeltrace2/graph/component-class-source.h>
29 %include <babeltrace2/graph/component-class-filter-const.h>
30 %include <babeltrace2/graph/component-class-filter.h>
31 %include <babeltrace2/graph/component-class-sink-const.h>
32 %include <babeltrace2/graph/component-class-sink.h>
33 %include <babeltrace2/graph/self-component-class-source.h>
34 %include <babeltrace2/graph/self-component-class-filter.h>
35 %include <babeltrace2/graph/self-component-class-sink.h>
39 * This hash table associates a BT component class object address to a
40 * user-defined Python class (PyObject *). The keys and values are NOT
41 * owned by this hash table. The Python class objects are owned by the
42 * Python module, which should not be unloaded until it is not possible
43 * to create a user Python component anyway.
45 * This hash table is written to when a user-defined Python component
46 * class is created by one of the bt_bt2_component_class_*_create()
49 * This function is read from when a user calls bt_component_create()
50 * with a component class pointer created by one of the functions above.
51 * In this case, the original Python class needs to be found to
52 * instantiate it and associate the created Python component object with
53 * a BT component object instance.
56 static GHashTable *bt_cc_ptr_to_py_cls;
59 void register_cc_ptr_to_py_cls(struct bt_component_class *bt_cc,
62 if (!bt_cc_ptr_to_py_cls) {
64 * Lazy-initializing this GHashTable because GLib
65 * might not be initialized yet and it needs to be
66 * before we call g_hash_table_new()
68 BT_LOGD_STR("Creating native component class to Python component class hash table.");
69 bt_cc_ptr_to_py_cls = g_hash_table_new(g_direct_hash, g_direct_equal);
70 BT_ASSERT(bt_cc_ptr_to_py_cls);
73 g_hash_table_insert(bt_cc_ptr_to_py_cls, (gpointer) bt_cc,
78 PyObject *lookup_cc_ptr_to_py_cls(const bt_component_class *bt_cc)
80 if (!bt_cc_ptr_to_py_cls) {
81 BT_LOGW("Cannot look up Python component class because hash table is NULL: "
82 "comp-cls-addr=%p", bt_cc);
86 return (PyObject *) g_hash_table_lookup(bt_cc_ptr_to_py_cls,
87 (gconstpointer) bt_cc);
92 * Useful Python objects.
95 static PyObject *py_mod_bt2 = NULL;
96 static PyObject *py_mod_bt2_exc_error_type = NULL;
97 static PyObject *py_mod_bt2_exc_memory_error = NULL;
98 static PyObject *py_mod_bt2_exc_try_again_type = NULL;
99 static PyObject *py_mod_bt2_exc_stop_type = NULL;
100 static PyObject *py_mod_bt2_exc_invalid_object_type = NULL;
103 void bt_bt2_cc_init_from_bt2(void)
106 * This is called once the bt2 package is loaded.
108 * Those modules and functions are needed while the package is
109 * used. Loading them here is safe because we know the bt2
110 * package is imported, and we know that the user cannot use the
111 * code here without importing bt2 first.
113 py_mod_bt2 = PyImport_ImportModule("bt2");
114 BT_ASSERT(py_mod_bt2);
115 py_mod_bt2_exc_error_type =
116 PyObject_GetAttrString(py_mod_bt2, "_Error");
117 BT_ASSERT(py_mod_bt2_exc_error_type);
118 py_mod_bt2_exc_memory_error =
119 PyObject_GetAttrString(py_mod_bt2, "_MemoryError");
120 BT_ASSERT(py_mod_bt2_exc_memory_error);
121 py_mod_bt2_exc_try_again_type =
122 PyObject_GetAttrString(py_mod_bt2, "TryAgain");
123 BT_ASSERT(py_mod_bt2_exc_try_again_type);
124 py_mod_bt2_exc_stop_type =
125 PyObject_GetAttrString(py_mod_bt2, "Stop");
126 BT_ASSERT(py_mod_bt2_exc_stop_type);
127 py_mod_bt2_exc_invalid_object_type =
128 PyObject_GetAttrString(py_mod_bt2, "InvalidObject");
129 BT_ASSERT(py_mod_bt2_exc_invalid_object_type);
133 void bt_bt2_cc_exit_handler(void)
136 * This is an exit handler (set by the bt2 package).
138 * We only give back the references that we took in
139 * bt_bt2_cc_init_from_bt2() here. The global variables continue
140 * to exist for the code of this file, but they are now borrowed
141 * references. If this code is executed, it means that somehow
142 * the modules are still loaded, so it should be safe to use
143 * them even without a strong reference.
145 * We cannot do this in the library's destructor because it
146 * gets executed once Python is already finalized.
148 Py_XDECREF(py_mod_bt2);
149 Py_XDECREF(py_mod_bt2_exc_error_type);
150 Py_XDECREF(py_mod_bt2_exc_try_again_type);
151 Py_XDECREF(py_mod_bt2_exc_stop_type);
152 Py_XDECREF(py_mod_bt2_exc_invalid_object_type);
156 /* Library destructor */
158 __attribute__((destructor))
160 void native_comp_class_dtor(void) {
161 /* Destroy component class association hash table */
162 if (bt_cc_ptr_to_py_cls) {
163 BT_LOGD_STR("Destroying native component class to Python component class hash table.");
164 g_hash_table_destroy(bt_cc_ptr_to_py_cls);
169 void restore_current_thread_error_and_append_exception_chain_recursive(
170 PyObject *py_exc_value,
171 bt_self_component_class *self_component_class,
172 bt_self_component *self_component,
173 bt_self_message_iterator *self_message_iterator,
174 const char *module_name)
176 PyObject *py_exc_cause_value;
177 PyObject *py_exc_type = NULL;
178 PyObject *py_exc_tb = NULL;
179 GString *gstr = NULL;
181 /* If this exception has a cause, handle that one first. */
182 py_exc_cause_value = PyException_GetCause(py_exc_value);
183 if (py_exc_cause_value) {
184 restore_current_thread_error_and_append_exception_chain_recursive(
185 py_exc_cause_value, self_component_class,
186 self_component, self_message_iterator, module_name);
190 * If the raised exception is a bt2._Error, restore the wrapped error.
192 if (PyErr_GivenExceptionMatches(py_exc_value, py_mod_bt2_exc_error_type)) {
193 PyObject *py_error_swig_ptr;
194 const bt_error *error;
198 * We never raise a bt2._Error with a cause: it should be the
201 BT_ASSERT(!py_exc_cause_value);
204 * We steal the error object from the exception, to move
205 * it back as the current thread's error.
207 py_error_swig_ptr = PyObject_GetAttrString(py_exc_value, "_ptr");
208 BT_ASSERT(py_error_swig_ptr);
210 ret = PyObject_SetAttrString(py_exc_value, "_ptr", Py_None);
213 ret = SWIG_ConvertPtr(py_error_swig_ptr, (void **) &error,
214 SWIGTYPE_p_bt_error, 0);
217 BT_CURRENT_THREAD_MOVE_ERROR_AND_RESET(error);
219 Py_DECREF(py_error_swig_ptr);
222 py_exc_type = PyObject_Type(py_exc_value);
223 py_exc_tb = PyException_GetTraceback(py_exc_value);
225 gstr = bt_py_common_format_exception(py_exc_type, py_exc_value,
226 py_exc_tb, BT_LOG_OUTPUT_LEVEL, false);
228 /* bt_py_common_format_exception has already warned. */
232 if (self_component_class) {
233 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT_CLASS(
234 self_component_class, "%s", gstr->str);
235 } else if (self_component) {
236 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
237 self_component, "%s", gstr->str);
238 } else if (self_message_iterator) {
239 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR(
240 self_message_iterator, "%s", gstr->str);
242 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(
243 module_name, "%s", gstr->str);
248 g_string_free(gstr, TRUE);
251 Py_XDECREF(py_exc_cause_value);
252 Py_XDECREF(py_exc_type);
253 Py_XDECREF(py_exc_tb);
257 * If you have the following code:
261 * something_that_raises_bt2_error()
262 * except bt2._Error as e1:
263 * raise ValueError from e1
264 * except ValueError as e2:
265 * raise TypeError from e2
267 * We will have the following exception chain:
269 * TypeError -> ValueError -> bt2._Error
271 * Where the TypeError is the current exception (obtained from PyErr_Fetch).
273 * The bt2._Error contains a `struct bt_error *` that used to be the current
274 * thread's error, at the moment the exception was raised.
276 * This function gets to the bt2._Error and restores the wrapped
277 * `struct bt_error *` as the current thread's error.
279 * Then, for each exception in the chain, starting with the oldest one, it adds
280 * an error cause to the current thread's error.
283 void restore_bt_error_and_append_current_exception_chain(
284 bt_self_component_class *self_component_class,
285 bt_self_component *self_component,
286 bt_self_message_iterator *self_message_iterator,
287 const char *module_name)
289 BT_ASSERT(PyErr_Occurred());
291 /* Used to access and restore the current exception. */
292 PyObject *py_exc_type;
293 PyObject *py_exc_value;
296 /* Fetch and normalize the Python exception. */
297 PyErr_Fetch(&py_exc_type, &py_exc_value, &py_exc_tb);
298 PyErr_NormalizeException(&py_exc_type, &py_exc_value, &py_exc_tb);
299 BT_ASSERT(py_exc_type);
300 BT_ASSERT(py_exc_value);
301 BT_ASSERT(py_exc_tb);
304 * Set the exception's traceback so it's possible to get it using
305 * PyException_GetTraceback in
306 * restore_current_thread_error_and_append_exception_chain_recursive.
308 PyException_SetTraceback(py_exc_value, py_exc_tb);
310 restore_current_thread_error_and_append_exception_chain_recursive(py_exc_value,
311 self_component_class, self_component, self_message_iterator,
314 PyErr_Restore(py_exc_type, py_exc_value, py_exc_tb);
318 void log_exception_and_maybe_append_error(int log_level,
320 bt_self_component_class *self_component_class,
321 bt_self_component *self_component,
322 bt_self_message_iterator *self_message_iterator,
323 const char *module_name)
327 BT_ASSERT(PyErr_Occurred());
328 gstr = bt_py_common_format_current_exception(BT_LOG_OUTPUT_LEVEL);
330 /* bt_py_common_format_current_exception() logs errors */
334 BT_LOG_WRITE(log_level, BT_LOG_TAG, "%s", gstr->str);
337 restore_bt_error_and_append_current_exception_chain(
338 self_component_class, self_component,
339 self_message_iterator, module_name);
345 g_string_free(gstr, TRUE);
350 void loge_exception(const char *module_name)
352 log_exception_and_maybe_append_error(BT_LOG_ERROR, true, NULL, NULL,
357 void loge_exception_message_iterator(
358 bt_self_message_iterator *self_message_iterator)
360 log_exception_and_maybe_append_error(BT_LOG_ERROR, true, NULL, NULL,
361 self_message_iterator, NULL);
365 void logw_exception(void)
367 log_exception_and_maybe_append_error(BT_LOG_WARNING, false, NULL, NULL,
372 int py_exc_to_status(bt_self_component_class *self_component_class,
373 bt_self_component *self_component,
374 bt_self_message_iterator *self_message_iterator,
375 const char *module_name)
377 int status = __BT_FUNC_STATUS_OK;
378 PyObject *exc = PyErr_Occurred();
384 if (PyErr_GivenExceptionMatches(exc,
385 py_mod_bt2_exc_try_again_type)) {
386 status = __BT_FUNC_STATUS_AGAIN;
387 } else if (PyErr_GivenExceptionMatches(exc,
388 py_mod_bt2_exc_stop_type)) {
389 status = __BT_FUNC_STATUS_END;
390 } else if (PyErr_GivenExceptionMatches(exc,
391 py_mod_bt2_exc_invalid_object_type)) {
392 status = __BT_FUNC_STATUS_INVALID_OBJECT;
394 /* Unknown exception: convert to general error */
395 log_exception_and_maybe_append_error(BT_LOG_WARNING, true,
396 self_component_class, self_component,
397 self_message_iterator, module_name);
399 if (PyErr_GivenExceptionMatches(exc,
400 py_mod_bt2_exc_memory_error)) {
401 status = __BT_FUNC_STATUS_MEMORY_ERROR;
403 status = __BT_FUNC_STATUS_ERROR;
413 int py_exc_to_status_component_class(bt_self_component_class *self_component_class)
415 return py_exc_to_status(self_component_class, NULL, NULL, NULL);
419 int py_exc_to_status_component(bt_self_component *self_component)
421 return py_exc_to_status(NULL, self_component, NULL, NULL);
425 int py_exc_to_status_message_iterator(
426 bt_self_message_iterator *self_message_iterator)
428 return py_exc_to_status(NULL, NULL, self_message_iterator, NULL);
431 /* Component class proxy methods (delegate to the attached Python object) */
434 bt_component_class_init_method_status component_class_init(
435 bt_self_component *self_component,
436 void *self_component_v,
437 swig_type_info *self_comp_cls_type_swig_type,
438 const bt_value *params,
439 void *init_method_data)
441 const bt_component *component = bt_self_component_as_component(self_component);
442 const bt_component_class *component_class = bt_component_borrow_class_const(component);
443 bt_component_class_init_method_status status = __BT_FUNC_STATUS_OK;
444 PyObject *py_cls = NULL;
445 PyObject *py_comp = NULL;
446 PyObject *py_params_ptr = NULL;
447 PyObject *py_comp_ptr = NULL;
449 (void) init_method_data;
451 BT_ASSERT(self_component);
452 BT_ASSERT(self_component_v);
453 BT_ASSERT(self_comp_cls_type_swig_type);
456 * Get the user-defined Python class which created this
457 * component's class in the first place (borrowed
460 py_cls = lookup_cc_ptr_to_py_cls(component_class);
462 BT_LOGE("Cannot find Python class associated to native component class: "
463 "comp-cls-addr=%p", component_class);
467 /* Parameters pointer -> SWIG pointer Python object */
468 py_params_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(params),
469 SWIGTYPE_p_bt_value, 0);
470 if (!py_params_ptr) {
471 BT_LOGE_STR("Failed to create a SWIG pointer object.");
475 py_comp_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_component_v),
476 self_comp_cls_type_swig_type, 0);
478 BT_LOGE_STR("Failed to create a SWIG pointer object.");
483 * Do the equivalent of this:
485 * py_comp = py_cls._bt_init_from_native(py_comp_ptr, py_params_ptr)
487 * _UserComponentType._bt_init_from_native() calls the Python
488 * component object's __init__() function.
490 py_comp = PyObject_CallMethod(py_cls,
491 "_bt_init_from_native", "(OO)", py_comp_ptr, py_params_ptr);
493 BT_LOGW("Failed to call Python class's _bt_init_from_native() method: "
494 "py-cls-addr=%p", py_cls);
495 status = py_exc_to_status_component(self_component);
500 * Our user Python component object is now fully created and
501 * initialized by the user. Since we just created it, this
502 * native component is its only (persistent) owner.
504 bt_self_component_set_data(self_component, py_comp);
509 status = __BT_FUNC_STATUS_ERROR;
512 * Clear any exception: we're returning a bad status anyway. If
513 * this call originated from Python (creation from a plugin's
514 * component class, for example), then the user gets an
515 * appropriate creation error.
521 Py_XDECREF(py_params_ptr);
522 Py_XDECREF(py_comp_ptr);
527 * Method of bt_component_class_source to initialize a bt_self_component_source
532 bt_component_class_init_method_status component_class_source_init(
533 bt_self_component_source *self_component_source,
534 const bt_value *params, void *init_method_data)
536 bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source);
537 return component_class_init(
539 self_component_source,
540 SWIGTYPE_p_bt_self_component_source,
541 params, init_method_data);
545 bt_component_class_init_method_status component_class_filter_init(
546 bt_self_component_filter *self_component_filter,
547 const bt_value *params, void *init_method_data)
549 bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
550 return component_class_init(
552 self_component_filter,
553 SWIGTYPE_p_bt_self_component_filter,
554 params, init_method_data);
558 bt_component_class_init_method_status component_class_sink_init(
559 bt_self_component_sink *self_component_sink,
560 const bt_value *params, void *init_method_data)
562 bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
563 return component_class_init(
566 SWIGTYPE_p_bt_self_component_sink,
567 params, init_method_data);
571 void component_class_finalize(bt_self_component *self_component)
573 PyObject *py_comp = bt_self_component_get_data(self_component);
576 /* Call user's _user_finalize() method */
577 PyObject *py_method_result = PyObject_CallMethod(py_comp,
578 "_user_finalize", NULL);
580 if (PyErr_Occurred()) {
581 BT_LOGW("User component's _user_finalize() method raised an exception: ignoring:");
586 * Ignore any exception raised by the _user_finalize() method
587 * because it won't change anything at this point: the component
588 * is being destroyed anyway.
591 Py_XDECREF(py_method_result);
596 void component_class_source_finalize(bt_self_component_source *self_component_source)
598 bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source);
599 component_class_finalize(self_component);
603 void component_class_filter_finalize(bt_self_component_filter *self_component_filter)
605 bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
606 component_class_finalize(self_component);
610 void component_class_sink_finalize(bt_self_component_sink *self_component_sink)
612 bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
613 component_class_finalize(self_component);
617 bt_bool component_class_can_seek_beginning(
618 bt_self_message_iterator *self_message_iterator)
621 PyObject *py_result = NULL;
622 bt_bool can_seek_beginning = false;
624 py_iter = bt_self_message_iterator_get_data(self_message_iterator);
627 py_result = PyObject_GetAttrString(py_iter, "_bt_can_seek_beginning_from_native");
629 BT_ASSERT(!py_result || PyBool_Check(py_result));
632 can_seek_beginning = PyObject_IsTrue(py_result);
635 * Once can_seek_beginning can report errors, convert the
636 * exception to a status. For now, log and return false;
638 loge_exception_message_iterator(self_message_iterator);
642 Py_XDECREF(py_result);
644 return can_seek_beginning;
648 bt_component_class_message_iterator_seek_beginning_method_status
649 component_class_seek_beginning(bt_self_message_iterator *self_message_iterator)
653 bt_component_class_message_iterator_seek_beginning_method_status status;
655 py_iter = bt_self_message_iterator_get_data(self_message_iterator);
657 py_result = PyObject_CallMethod(py_iter, "_bt_seek_beginning_from_native",
659 BT_ASSERT(!py_result || py_result == Py_None);
660 status = py_exc_to_status_message_iterator(self_message_iterator);
661 Py_XDECREF(py_result);
666 bt_component_class_port_connected_method_status component_class_port_connected(
667 bt_self_component *self_component,
668 void *self_component_port,
669 swig_type_info *self_component_port_swig_type,
670 bt_port_type self_component_port_type,
671 const void *other_port,
672 swig_type_info *other_port_swig_type)
674 bt_component_class_port_connected_method_status status;
675 PyObject *py_comp = NULL;
676 PyObject *py_self_port_ptr = NULL;
677 PyObject *py_other_port_ptr = NULL;
678 PyObject *py_method_result = NULL;
680 py_comp = bt_self_component_get_data(self_component);
682 py_self_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_component_port),
683 self_component_port_swig_type, 0);
684 if (!py_self_port_ptr) {
685 BT_LOGF_STR("Failed to create a SWIG pointer object.");
686 status = __BT_FUNC_STATUS_MEMORY_ERROR;
690 py_other_port_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(other_port),
691 other_port_swig_type, 0);
692 if (!py_other_port_ptr) {
693 BT_LOGF_STR("Failed to create a SWIG pointer object.");
694 status = __BT_FUNC_STATUS_MEMORY_ERROR;
697 py_method_result = PyObject_CallMethod(py_comp,
698 "_bt_port_connected_from_native", "(OiO)", py_self_port_ptr,
699 self_component_port_type, py_other_port_ptr);
700 BT_ASSERT(!py_method_result || py_method_result == Py_None);
701 status = py_exc_to_status_component(self_component);
704 Py_XDECREF(py_self_port_ptr);
705 Py_XDECREF(py_other_port_ptr);
706 Py_XDECREF(py_method_result);
711 bt_component_class_port_connected_method_status
712 component_class_source_output_port_connected(
713 bt_self_component_source *self_component_source,
714 bt_self_component_port_output *self_component_port_output,
715 const bt_port_input *other_port_input)
717 bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source);
719 return component_class_port_connected(
721 self_component_port_output,
722 SWIGTYPE_p_bt_self_component_port_output,
725 SWIGTYPE_p_bt_port_input);
729 bt_component_class_port_connected_method_status
730 component_class_filter_input_port_connected(
731 bt_self_component_filter *self_component_filter,
732 bt_self_component_port_input *self_component_port_input,
733 const bt_port_output *other_port_output)
735 bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
737 return component_class_port_connected(
739 self_component_port_input,
740 SWIGTYPE_p_bt_self_component_port_input,
743 SWIGTYPE_p_bt_port_output);
747 bt_component_class_port_connected_method_status
748 component_class_filter_output_port_connected(
749 bt_self_component_filter *self_component_filter,
750 bt_self_component_port_output *self_component_port_output,
751 const bt_port_input *other_port_input)
753 bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
755 return component_class_port_connected(
757 self_component_port_output,
758 SWIGTYPE_p_bt_self_component_port_output,
761 SWIGTYPE_p_bt_port_input);
765 bt_component_class_port_connected_method_status
766 component_class_sink_input_port_connected(
767 bt_self_component_sink *self_component_sink,
768 bt_self_component_port_input *self_component_port_input,
769 const bt_port_output *other_port_output)
771 bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
773 return component_class_port_connected(
775 self_component_port_input,
776 SWIGTYPE_p_bt_self_component_port_input,
779 SWIGTYPE_p_bt_port_output);
783 bt_component_class_sink_graph_is_configured_method_status
784 component_class_sink_graph_is_configured(
785 bt_self_component_sink *self_component_sink)
787 PyObject *py_comp = NULL;
788 PyObject *py_method_result = NULL;
789 bt_component_class_sink_graph_is_configured_method_status status = __BT_FUNC_STATUS_OK;
790 bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
792 py_comp = bt_self_component_get_data(self_component);
793 py_method_result = PyObject_CallMethod(py_comp,
794 "_bt_graph_is_configured_from_native", NULL);
795 BT_ASSERT(!py_method_result || py_method_result == Py_None);
796 status = py_exc_to_status_component(self_component);
797 Py_XDECREF(py_method_result);
802 bt_component_class_query_method_status component_class_query(
803 const bt_component_class *component_class,
804 bt_self_component_class *self_component_class,
805 const bt_query_executor *query_executor,
806 const char *object, const bt_value *params,
807 bt_logging_level log_level,
808 const bt_value **result)
810 PyObject *py_cls = NULL;
811 PyObject *py_params_ptr = NULL;
812 PyObject *py_query_exec_ptr = NULL;
813 PyObject *py_query_func = NULL;
814 PyObject *py_object = NULL;
815 PyObject *py_results_addr = NULL;
816 bt_component_class_query_method_status status = __BT_FUNC_STATUS_OK;
818 py_cls = lookup_cc_ptr_to_py_cls(component_class);
820 BT_LOGE("Cannot find Python class associated to native component class: "
821 "comp-cls-addr=%p", component_class);
825 py_params_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(params),
826 SWIGTYPE_p_bt_value, 0);
827 if (!py_params_ptr) {
828 BT_LOGE_STR("Failed to create a SWIG pointer object.");
832 py_query_exec_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(query_executor),
833 SWIGTYPE_p_bt_query_executor, 0);
834 if (!py_query_exec_ptr) {
835 BT_LOGE_STR("Failed to create a SWIG pointer object.");
839 py_object = SWIG_FromCharPtr(object);
841 BT_LOGE_STR("Failed to create a Python string.");
845 py_results_addr = PyObject_CallMethod(py_cls,
846 "_bt_query_from_native", "(OOOi)", py_query_exec_ptr,
847 py_object, py_params_ptr, (int) log_level);
848 if (!py_results_addr) {
849 BT_LOGW("Failed to call Python class's _bt_query_from_native() method: "
850 "py-cls-addr=%p", py_cls);
851 status = py_exc_to_status_component_class(self_component_class);
856 * The returned object, on success, is an integer object
857 * (PyLong) containing the address of a BT value object (new
860 *result = PyLong_AsVoidPtr(py_results_addr);
861 BT_ASSERT(!PyErr_Occurred());
867 status = __BT_FUNC_STATUS_ERROR;
870 Py_XDECREF(py_params_ptr);
871 Py_XDECREF(py_query_exec_ptr);
872 Py_XDECREF(py_query_func);
873 Py_XDECREF(py_object);
874 Py_XDECREF(py_results_addr);
879 bt_component_class_query_method_status component_class_source_query(
880 bt_self_component_class_source *self_component_class_source,
881 const bt_query_executor *query_executor,
882 const char *object, const bt_value *params,
883 bt_logging_level log_level,
884 const bt_value **result)
886 const bt_component_class_source *component_class_source = bt_self_component_class_source_as_component_class_source(self_component_class_source);
887 const bt_component_class *component_class = bt_component_class_source_as_component_class_const(component_class_source);
888 bt_self_component_class *self_component_class = bt_self_component_class_source_as_self_component_class(self_component_class_source);
890 return component_class_query(component_class, self_component_class, query_executor, object, params, log_level, result);
894 bt_component_class_query_method_status component_class_filter_query(
895 bt_self_component_class_filter *self_component_class_filter,
896 const bt_query_executor *query_executor,
897 const char *object, const bt_value *params,
898 bt_logging_level log_level,
899 const bt_value **result)
901 const bt_component_class_filter *component_class_filter = bt_self_component_class_filter_as_component_class_filter(self_component_class_filter);
902 const bt_component_class *component_class = bt_component_class_filter_as_component_class_const(component_class_filter);
903 bt_self_component_class *self_component_class = bt_self_component_class_filter_as_self_component_class(self_component_class_filter);
905 return component_class_query(component_class, self_component_class, query_executor, object, params, log_level, result);
909 bt_component_class_query_method_status component_class_sink_query(
910 bt_self_component_class_sink *self_component_class_sink,
911 const bt_query_executor *query_executor,
912 const char *object, const bt_value *params,
913 bt_logging_level log_level,
914 const bt_value **result)
916 const bt_component_class_sink *component_class_sink = bt_self_component_class_sink_as_component_class_sink(self_component_class_sink);
917 const bt_component_class *component_class = bt_component_class_sink_as_component_class_const(component_class_sink);
918 bt_self_component_class *self_component_class = bt_self_component_class_sink_as_self_component_class(self_component_class_sink);
920 return component_class_query(component_class, self_component_class, query_executor, object, params, log_level, result);
924 bt_component_class_message_iterator_init_method_status
925 component_class_message_iterator_init(
926 bt_self_message_iterator *self_message_iterator,
927 bt_self_component *self_component,
928 bt_self_component_port_output *self_component_port_output)
930 bt_component_class_message_iterator_init_method_status status = __BT_FUNC_STATUS_OK;
931 PyObject *py_comp_cls = NULL;
932 PyObject *py_iter_cls = NULL;
933 PyObject *py_iter_ptr = NULL;
934 PyObject *py_component_port_output_ptr = NULL;
935 PyObject *py_init_method_result = NULL;
936 PyObject *py_iter = NULL;
939 py_comp = bt_self_component_get_data(self_component);
941 /* Find user's Python message iterator class */
942 py_comp_cls = PyObject_GetAttrString(py_comp, "__class__");
944 BT_LOGE_STR("Cannot get Python object's `__class__` attribute.");
948 py_iter_cls = PyObject_GetAttrString(py_comp_cls, "_iter_cls");
950 BT_LOGE_STR("Cannot get Python class's `_iter_cls` attribute.");
954 py_iter_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(self_message_iterator),
955 SWIGTYPE_p_bt_self_message_iterator, 0);
957 const char *err = "Failed to create a SWIG pointer object.";
960 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR(
961 self_message_iterator, err);
966 * Create object with borrowed native message iterator
969 * py_iter = py_iter_cls.__new__(py_iter_cls, py_iter_ptr)
971 py_iter = PyObject_CallMethod(py_iter_cls, "__new__",
972 "(OO)", py_iter_cls, py_iter_ptr);
974 BT_LOGE("Failed to call Python class's __new__() method: "
975 "py-cls-addr=%p", py_iter_cls);
982 * py_iter.__init__(self_output_port)
984 * through the _init_for_native helper static method.
986 * At this point, py_iter._ptr is set, so this initialization
987 * function has access to self._component (which gives it the
988 * user Python component object from which the iterator was
991 py_component_port_output_ptr = SWIG_NewPointerObj(
992 SWIG_as_voidptr(self_component_port_output),
993 SWIGTYPE_p_bt_self_component_port_output, 0);
994 if (!py_component_port_output_ptr) {
995 const char *err = "Failed to create a SWIG pointer object.";
998 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR(
999 self_message_iterator, err);
1003 py_init_method_result = PyObject_CallMethod(py_iter,
1004 "_bt_init_from_native", "O", py_component_port_output_ptr);
1005 if (!py_init_method_result) {
1006 BT_LOGE_STR("User's __init__() method failed:");
1011 * Since the Python code can never instantiate a user-defined
1012 * message iterator class, the native message iterator
1013 * object does NOT belong to a user Python message iterator
1014 * object (borrowed reference). However this Python object is
1015 * owned by this native message iterator object.
1017 * In the Python world, the lifetime of the native message
1018 * iterator is managed by a _GenericMessageIterator
1021 * _GenericMessageIterator instance:
1022 * owns a native bt_message_iterator object (iter)
1023 * owns a _UserMessageIterator instance (py_iter)
1024 * self._ptr is a borrowed reference to the
1025 * native bt_private_connection_private_message_iterator
1028 bt_self_message_iterator_set_data(self_message_iterator, py_iter);
1033 /* Handling of errors that cause a Python exception to be set. */
1034 status = py_exc_to_status_message_iterator(self_message_iterator);
1035 BT_ASSERT(status != __BT_FUNC_STATUS_OK);
1039 /* Handling of errors that don't cause a Python exception to be set. */
1040 status = __BT_FUNC_STATUS_ERROR;
1043 BT_ASSERT(!PyErr_Occurred());
1045 Py_XDECREF(py_comp_cls);
1046 Py_XDECREF(py_iter_cls);
1047 Py_XDECREF(py_iter_ptr);
1048 Py_XDECREF(py_component_port_output_ptr);
1049 Py_XDECREF(py_init_method_result);
1050 Py_XDECREF(py_iter);
1055 bt_component_class_message_iterator_init_method_status
1056 component_class_source_message_iterator_init(
1057 bt_self_message_iterator *self_message_iterator,
1058 bt_self_component_source *self_component_source,
1059 bt_self_component_port_output *self_component_port_output)
1061 bt_self_component *self_component = bt_self_component_source_as_self_component(self_component_source);
1063 return component_class_message_iterator_init(self_message_iterator, self_component, self_component_port_output);
1067 bt_component_class_message_iterator_init_method_status
1068 component_class_filter_message_iterator_init(
1069 bt_self_message_iterator *self_message_iterator,
1070 bt_self_component_filter *self_component_filter,
1071 bt_self_component_port_output *self_component_port_output)
1073 bt_self_component *self_component = bt_self_component_filter_as_self_component(self_component_filter);
1075 return component_class_message_iterator_init(self_message_iterator, self_component, self_component_port_output);
1079 void component_class_message_iterator_finalize(
1080 bt_self_message_iterator *message_iterator)
1082 PyObject *py_message_iter = bt_self_message_iterator_get_data(message_iterator);
1083 PyObject *py_method_result = NULL;
1085 BT_ASSERT(py_message_iter);
1087 /* Call user's _user_finalize() method */
1088 py_method_result = PyObject_CallMethod(py_message_iter,
1089 "_user_finalize", NULL);
1091 if (PyErr_Occurred()) {
1092 BT_LOGW("User's _user_finalize() method raised an exception: ignoring:");
1097 * Ignore any exception raised by the _user_finalize() method
1098 * because it won't change anything at this point: the component
1099 * is being destroyed anyway.
1102 Py_XDECREF(py_method_result);
1103 Py_DECREF(py_message_iter);
1106 /* Valid for both sources and filters. */
1109 bt_component_class_message_iterator_next_method_status
1110 component_class_message_iterator_next(
1111 bt_self_message_iterator *message_iterator,
1112 bt_message_array_const msgs, uint64_t capacity,
1115 bt_component_class_message_iterator_next_method_status status = __BT_FUNC_STATUS_OK;
1116 PyObject *py_message_iter = bt_self_message_iterator_get_data(message_iterator);
1117 PyObject *py_method_result = NULL;
1119 BT_ASSERT(py_message_iter);
1120 py_method_result = PyObject_CallMethod(py_message_iter,
1121 "_bt_next_from_native", NULL);
1122 if (!py_method_result) {
1123 status = py_exc_to_status_message_iterator(message_iterator);
1124 BT_ASSERT(status != __BT_FUNC_STATUS_OK);
1129 * The returned object, on success, is an integer object
1130 * (PyLong) containing the address of a native message
1131 * object (which is now ours).
1133 msgs[0] = PyLong_AsVoidPtr(py_method_result);
1136 /* Clear potential overflow error; should never happen */
1137 BT_ASSERT(!PyErr_Occurred());
1141 Py_XDECREF(py_method_result);
1146 bt_component_class_sink_consume_method_status
1147 component_class_sink_consume(bt_self_component_sink *self_component_sink)
1149 bt_self_component *self_component = bt_self_component_sink_as_self_component(self_component_sink);
1150 PyObject *py_comp = bt_self_component_get_data(self_component);
1151 PyObject *py_method_result = NULL;
1152 bt_component_class_sink_consume_method_status status;
1155 py_method_result = PyObject_CallMethod(py_comp,
1156 "_user_consume", NULL);
1157 status = py_exc_to_status_component(self_component);
1158 if (!py_method_result && status == __BT_FUNC_STATUS_OK) {
1159 /* Pretty sure this should never happen, but just in case */
1160 BT_LOGE("User's _user_consume() method failed without raising an exception: "
1161 "status=%d", status);
1162 status = __BT_FUNC_STATUS_ERROR;
1165 Py_XDECREF(py_method_result);
1170 int component_class_set_help_and_desc(
1171 bt_component_class *component_class,
1172 const char *description, const char *help)
1177 ret = bt_component_class_set_description(component_class, description);
1179 BT_LOGE("Cannot set component class's description: "
1180 "comp-cls-addr=%p", component_class);
1186 ret = bt_component_class_set_help(component_class, help);
1188 BT_LOGE("Cannot set component class's help text: "
1189 "comp-cls-addr=%p", component_class);
1201 bt_component_class_source *bt_bt2_component_class_source_create(
1202 PyObject *py_cls, const char *name, const char *description,
1205 bt_component_class_source *component_class_source;
1206 bt_component_class *component_class;
1210 component_class_source = bt_component_class_source_create(name,
1211 component_class_message_iterator_next);
1212 if (!component_class_source) {
1213 BT_LOGE_STR("Cannot create source component class.");
1217 component_class = bt_component_class_source_as_component_class(component_class_source);
1219 if (component_class_set_help_and_desc(component_class, description, help)) {
1223 ret = bt_component_class_source_set_init_method(component_class_source, component_class_source_init);
1224 BT_ASSERT(ret == 0);
1225 ret = bt_component_class_source_set_finalize_method(component_class_source, component_class_source_finalize);
1226 BT_ASSERT(ret == 0);
1227 ret = bt_component_class_source_set_message_iterator_can_seek_beginning_method(component_class_source,
1228 component_class_can_seek_beginning);
1229 BT_ASSERT(ret == 0);
1230 ret = bt_component_class_source_set_message_iterator_seek_beginning_method(component_class_source,
1231 component_class_seek_beginning);
1232 BT_ASSERT(ret == 0);
1233 ret = bt_component_class_source_set_output_port_connected_method(component_class_source,
1234 component_class_source_output_port_connected);
1235 BT_ASSERT(ret == 0);
1236 ret = bt_component_class_source_set_query_method(component_class_source, component_class_source_query);
1237 BT_ASSERT(ret == 0);
1238 ret = bt_component_class_source_set_message_iterator_init_method(
1239 component_class_source, component_class_source_message_iterator_init);
1240 BT_ASSERT(ret == 0);
1241 ret = bt_component_class_source_set_message_iterator_finalize_method(
1242 component_class_source, component_class_message_iterator_finalize);
1243 BT_ASSERT(ret == 0);
1244 register_cc_ptr_to_py_cls(component_class, py_cls);
1247 return component_class_source;
1251 bt_component_class_filter *bt_bt2_component_class_filter_create(
1252 PyObject *py_cls, const char *name, const char *description,
1255 bt_component_class *component_class;
1256 bt_component_class_filter *component_class_filter;
1260 component_class_filter = bt_component_class_filter_create(name,
1261 component_class_message_iterator_next);
1262 if (!component_class_filter) {
1263 BT_LOGE_STR("Cannot create filter component class.");
1267 component_class = bt_component_class_filter_as_component_class(component_class_filter);
1269 if (component_class_set_help_and_desc(component_class, description, help)) {
1273 ret = bt_component_class_filter_set_init_method(component_class_filter, component_class_filter_init);
1274 BT_ASSERT(ret == 0);
1275 ret = bt_component_class_filter_set_finalize_method (component_class_filter, component_class_filter_finalize);
1276 BT_ASSERT(ret == 0);
1277 ret = bt_component_class_filter_set_message_iterator_can_seek_beginning_method(component_class_filter,
1278 component_class_can_seek_beginning);
1279 BT_ASSERT(ret == 0);
1280 ret = bt_component_class_filter_set_message_iterator_seek_beginning_method(component_class_filter,
1281 component_class_seek_beginning);
1282 BT_ASSERT(ret == 0);
1283 ret = bt_component_class_filter_set_input_port_connected_method(component_class_filter,
1284 component_class_filter_input_port_connected);
1285 BT_ASSERT(ret == 0);
1286 ret = bt_component_class_filter_set_output_port_connected_method(component_class_filter,
1287 component_class_filter_output_port_connected);
1288 BT_ASSERT(ret == 0);
1289 ret = bt_component_class_filter_set_query_method(component_class_filter, component_class_filter_query);
1290 BT_ASSERT(ret == 0);
1291 ret = bt_component_class_filter_set_message_iterator_init_method(
1292 component_class_filter, component_class_filter_message_iterator_init);
1293 BT_ASSERT(ret == 0);
1294 ret = bt_component_class_filter_set_message_iterator_finalize_method(
1295 component_class_filter, component_class_message_iterator_finalize);
1296 BT_ASSERT(ret == 0);
1297 register_cc_ptr_to_py_cls(component_class, py_cls);
1300 return component_class_filter;
1304 bt_component_class_sink *bt_bt2_component_class_sink_create(
1305 PyObject *py_cls, const char *name, const char *description,
1308 bt_component_class_sink *component_class_sink;
1309 bt_component_class *component_class;
1313 component_class_sink = bt_component_class_sink_create(name, component_class_sink_consume);
1315 if (!component_class_sink) {
1316 BT_LOGE_STR("Cannot create sink component class.");
1320 component_class = bt_component_class_sink_as_component_class(component_class_sink);
1322 if (component_class_set_help_and_desc(component_class, description, help)) {
1326 ret = bt_component_class_sink_set_init_method(component_class_sink, component_class_sink_init);
1327 BT_ASSERT(ret == 0);
1328 ret = bt_component_class_sink_set_finalize_method(component_class_sink, component_class_sink_finalize);
1329 BT_ASSERT(ret == 0);
1330 ret = bt_component_class_sink_set_input_port_connected_method(component_class_sink,
1331 component_class_sink_input_port_connected);
1332 BT_ASSERT(ret == 0);
1333 ret = bt_component_class_sink_set_graph_is_configured_method(component_class_sink,
1334 component_class_sink_graph_is_configured);
1335 BT_ASSERT(ret == 0);
1336 ret = bt_component_class_sink_set_query_method(component_class_sink, component_class_sink_query);
1337 BT_ASSERT(ret == 0);
1338 register_cc_ptr_to_py_cls(component_class, py_cls);
1341 return component_class_sink;
1345 struct bt_component_class_source *bt_bt2_component_class_source_create(
1346 PyObject *py_cls, const char *name, const char *description,
1348 struct bt_component_class_filter *bt_bt2_component_class_filter_create(
1349 PyObject *py_cls, const char *name, const char *description,
1351 struct bt_component_class_sink *bt_bt2_component_class_sink_create(
1352 PyObject *py_cls, const char *name, const char *description,
1354 void bt_bt2_cc_init_from_bt2(void);
1355 void bt_bt2_cc_exit_handler(void);