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 "logging/comp-logging.h"
28 * This hash table associates a BT component class object address to a
29 * user-defined Python class (PyObject *). The keys and values are NOT
30 * owned by this hash table. The Python class objects are owned by the
31 * Python module, which should not be unloaded until it is not possible
32 * to create a user Python component anyway.
34 * This hash table is written to when a user-defined Python component
35 * class is created by one of the bt_bt2_component_class_*_create()
38 * This function is read from when a user calls bt_component_create()
39 * with a component class pointer created by one of the functions above.
40 * In this case, the original Python class needs to be found to
41 * instantiate it and associate the created Python component object with
42 * a BT component object instance.
45 static GHashTable
*bt_cc_ptr_to_py_cls
;
48 void register_cc_ptr_to_py_cls(struct bt_component_class
*bt_cc
,
51 if (!bt_cc_ptr_to_py_cls
) {
53 * Lazy-initializing this GHashTable because GLib
54 * might not be initialized yet and it needs to be
55 * before we call g_hash_table_new()
57 BT_LOGD_STR("Creating native component class to Python component class hash table.");
58 bt_cc_ptr_to_py_cls
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
59 BT_ASSERT(bt_cc_ptr_to_py_cls
);
62 g_hash_table_insert(bt_cc_ptr_to_py_cls
, (gpointer
) bt_cc
,
67 PyObject
*lookup_cc_ptr_to_py_cls(const bt_component_class
*bt_cc
)
69 if (!bt_cc_ptr_to_py_cls
) {
70 BT_LOGW("Cannot look up Python component class because hash table is NULL: "
71 "comp-cls-addr=%p", bt_cc
);
75 return (PyObject
*) g_hash_table_lookup(bt_cc_ptr_to_py_cls
,
76 (gconstpointer
) bt_cc
);
81 * Useful Python objects.
84 static PyObject
*py_mod_bt2
= NULL
;
85 static PyObject
*py_mod_bt2_exc_error_type
= NULL
;
86 static PyObject
*py_mod_bt2_exc_memory_error
= NULL
;
87 static PyObject
*py_mod_bt2_exc_try_again_type
= NULL
;
88 static PyObject
*py_mod_bt2_exc_stop_type
= NULL
;
89 static PyObject
*py_mod_bt2_exc_unknown_object_type
= NULL
;
92 void bt_bt2_cc_init_from_bt2(void)
95 * This is called once the bt2 package is loaded.
97 * Those modules and functions are needed while the package is
98 * used. Loading them here is safe because we know the bt2
99 * package is imported, and we know that the user cannot use the
100 * code here without importing bt2 first.
102 py_mod_bt2
= PyImport_ImportModule("bt2");
103 BT_ASSERT(py_mod_bt2
);
104 py_mod_bt2_exc_error_type
=
105 PyObject_GetAttrString(py_mod_bt2
, "_Error");
106 BT_ASSERT(py_mod_bt2_exc_error_type
);
107 py_mod_bt2_exc_memory_error
=
108 PyObject_GetAttrString(py_mod_bt2
, "_MemoryError");
109 BT_ASSERT(py_mod_bt2_exc_memory_error
);
110 py_mod_bt2_exc_try_again_type
=
111 PyObject_GetAttrString(py_mod_bt2
, "TryAgain");
112 BT_ASSERT(py_mod_bt2_exc_try_again_type
);
113 py_mod_bt2_exc_stop_type
=
114 PyObject_GetAttrString(py_mod_bt2
, "Stop");
115 BT_ASSERT(py_mod_bt2_exc_stop_type
);
116 py_mod_bt2_exc_unknown_object_type
=
117 PyObject_GetAttrString(py_mod_bt2
, "UnknownObject");
118 BT_ASSERT(py_mod_bt2_exc_unknown_object_type
);
122 void bt_bt2_cc_exit_handler(void)
125 * This is an exit handler (set by the bt2 package).
127 * We only give back the references that we took in
128 * bt_bt2_cc_init_from_bt2() here. The global variables continue
129 * to exist for the code of this file, but they are now borrowed
130 * references. If this code is executed, it means that somehow
131 * the modules are still loaded, so it should be safe to use
132 * them even without a strong reference.
134 * We cannot do this in the library's destructor because it
135 * gets executed once Python is already finalized.
137 Py_XDECREF(py_mod_bt2
);
138 Py_XDECREF(py_mod_bt2_exc_error_type
);
139 Py_XDECREF(py_mod_bt2_exc_try_again_type
);
140 Py_XDECREF(py_mod_bt2_exc_stop_type
);
141 Py_XDECREF(py_mod_bt2_exc_unknown_object_type
);
145 /* Library destructor */
147 __attribute__((destructor
))
149 void native_comp_class_dtor(void) {
150 /* Destroy component class association hash table */
151 if (bt_cc_ptr_to_py_cls
) {
152 BT_LOGD_STR("Destroying native component class to Python component class hash table.");
153 g_hash_table_destroy(bt_cc_ptr_to_py_cls
);
158 void restore_current_thread_error_and_append_exception_chain_recursive(
159 int active_log_level
, PyObject
*py_exc_value
,
160 bt_self_component_class
*self_component_class
,
161 bt_self_component
*self_component
,
162 bt_self_message_iterator
*self_message_iterator
,
163 const char *module_name
)
165 PyObject
*py_exc_cause_value
;
166 PyObject
*py_exc_type
= NULL
;
167 PyObject
*py_exc_tb
= NULL
;
168 GString
*gstr
= NULL
;
170 /* If this exception has a cause, handle that one first. */
171 py_exc_cause_value
= PyException_GetCause(py_exc_value
);
172 if (py_exc_cause_value
) {
173 restore_current_thread_error_and_append_exception_chain_recursive(
174 active_log_level
, py_exc_cause_value
,
175 self_component_class
, self_component
,
176 self_message_iterator
, module_name
);
180 * If the raised exception is a bt2._Error, restore the wrapped error.
182 if (PyErr_GivenExceptionMatches(py_exc_value
, py_mod_bt2_exc_error_type
)) {
183 PyObject
*py_error_swig_ptr
;
184 const bt_error
*error
;
188 * We never raise a bt2._Error with a cause: it should be the
191 BT_ASSERT(!py_exc_cause_value
);
194 * We steal the error object from the exception, to move
195 * it back as the current thread's error.
197 py_error_swig_ptr
= PyObject_GetAttrString(py_exc_value
, "_ptr");
198 BT_ASSERT(py_error_swig_ptr
);
200 ret
= PyObject_SetAttrString(py_exc_value
, "_ptr", Py_None
);
203 ret
= SWIG_ConvertPtr(py_error_swig_ptr
, (void **) &error
,
204 SWIGTYPE_p_bt_error
, 0);
207 BT_CURRENT_THREAD_MOVE_ERROR_AND_RESET(error
);
209 Py_DECREF(py_error_swig_ptr
);
212 py_exc_type
= PyObject_Type(py_exc_value
);
213 py_exc_tb
= PyException_GetTraceback(py_exc_value
);
215 gstr
= bt_py_common_format_exception(py_exc_type
, py_exc_value
,
216 py_exc_tb
, active_log_level
, false);
218 /* bt_py_common_format_exception has already warned. */
222 if (self_component_class
) {
223 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT_CLASS(
224 self_component_class
, "%s", gstr
->str
);
225 } else if (self_component
) {
226 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(
227 self_component
, "%s", gstr
->str
);
228 } else if (self_message_iterator
) {
229 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR(
230 self_message_iterator
, "%s", gstr
->str
);
232 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(
233 module_name
, "%s", gstr
->str
);
238 g_string_free(gstr
, TRUE
);
241 Py_XDECREF(py_exc_cause_value
);
242 Py_XDECREF(py_exc_type
);
243 Py_XDECREF(py_exc_tb
);
247 * If you have the following code:
251 * something_that_raises_bt2_error()
252 * except bt2._Error as e1:
253 * raise ValueError from e1
254 * except ValueError as e2:
255 * raise TypeError from e2
257 * We will have the following exception chain:
259 * TypeError -> ValueError -> bt2._Error
261 * Where the TypeError is the current exception (obtained from PyErr_Fetch).
263 * The bt2._Error contains a `struct bt_error *` that used to be the current
264 * thread's error, at the moment the exception was raised.
266 * This function gets to the bt2._Error and restores the wrapped
267 * `struct bt_error *` as the current thread's error.
269 * Then, for each exception in the chain, starting with the oldest one, it adds
270 * an error cause to the current thread's error.
273 void restore_bt_error_and_append_current_exception_chain(
274 int active_log_level
,
275 bt_self_component_class
*self_component_class
,
276 bt_self_component
*self_component
,
277 bt_self_message_iterator
*self_message_iterator
,
278 const char *module_name
)
280 BT_ASSERT(PyErr_Occurred());
282 /* Used to access and restore the current exception. */
283 PyObject
*py_exc_type
;
284 PyObject
*py_exc_value
;
287 /* Fetch and normalize the Python exception. */
288 PyErr_Fetch(&py_exc_type
, &py_exc_value
, &py_exc_tb
);
289 PyErr_NormalizeException(&py_exc_type
, &py_exc_value
, &py_exc_tb
);
290 BT_ASSERT(py_exc_type
);
291 BT_ASSERT(py_exc_value
);
292 BT_ASSERT(py_exc_tb
);
295 * Set the exception's traceback so it's possible to get it using
296 * PyException_GetTraceback in
297 * restore_current_thread_error_and_append_exception_chain_recursive.
299 PyException_SetTraceback(py_exc_value
, py_exc_tb
);
301 restore_current_thread_error_and_append_exception_chain_recursive(
302 active_log_level
, py_exc_value
, self_component_class
,
303 self_component
, self_message_iterator
, module_name
);
305 PyErr_Restore(py_exc_type
, py_exc_value
, py_exc_tb
);
309 void log_exception_and_maybe_append_error(int func_log_level
,
310 int active_log_level
, bool append_error
,
311 bt_self_component_class
*self_component_class
,
312 bt_self_component
*self_component
,
313 bt_self_message_iterator
*self_message_iterator
,
314 const char *module_name
)
318 BT_ASSERT(PyErr_Occurred());
319 gstr
= bt_py_common_format_current_exception(active_log_level
);
321 /* bt_py_common_format_current_exception() logs errors */
325 BT_COMP_LOG_CUR_LVL(func_log_level
, active_log_level
, self_component
,
329 restore_bt_error_and_append_current_exception_chain(
330 active_log_level
, self_component_class
, self_component
,
331 self_message_iterator
, module_name
);
337 g_string_free(gstr
, TRUE
);
342 bt_logging_level
get_self_component_log_level(bt_self_component
*self_comp
)
344 return bt_component_get_logging_level(
345 bt_self_component_as_component(self_comp
));
349 bt_logging_level
get_self_message_iterator_log_level(
350 bt_self_message_iterator
*self_msg_iter
)
352 bt_self_component
*self_comp
=
353 bt_self_message_iterator_borrow_component(self_msg_iter
);
355 return get_self_component_log_level(self_comp
);
359 void loge_exception(const char *module_name
, int active_log_level
)
361 log_exception_and_maybe_append_error(BT_LOG_ERROR
, active_log_level
,
362 true, NULL
, NULL
, NULL
, module_name
);
366 void loge_exception_message_iterator(
367 bt_self_message_iterator
*self_message_iterator
)
369 bt_logging_level log_level
= get_self_message_iterator_log_level(
370 self_message_iterator
);
372 log_exception_and_maybe_append_error(BT_LOG_ERROR
, log_level
,
373 true, NULL
, NULL
, self_message_iterator
, NULL
);
377 void logw_exception(int active_log_level
)
379 log_exception_and_maybe_append_error(BT_LOG_WARNING
, active_log_level
,
380 false, NULL
, NULL
, NULL
, NULL
);
384 int py_exc_to_status(bt_self_component_class
*self_component_class
,
385 bt_self_component
*self_component
,
386 bt_self_message_iterator
*self_message_iterator
,
387 const char *module_name
, int active_log_level
)
389 int status
= __BT_FUNC_STATUS_OK
;
390 PyObject
*exc
= PyErr_Occurred();
396 if (PyErr_GivenExceptionMatches(exc
,
397 py_mod_bt2_exc_try_again_type
)) {
398 status
= __BT_FUNC_STATUS_AGAIN
;
399 } else if (PyErr_GivenExceptionMatches(exc
,
400 py_mod_bt2_exc_stop_type
)) {
401 status
= __BT_FUNC_STATUS_END
;
402 } else if (PyErr_GivenExceptionMatches(exc
,
403 py_mod_bt2_exc_unknown_object_type
)) {
404 status
= __BT_FUNC_STATUS_UNKNOWN_OBJECT
;
407 * Unknown exception: convert to general error.
409 * Because we only want to fetch the log level when
410 * we actually get an exception, and not systematically
411 * when we call py_exc_to_status() (as py_exc_to_status()
412 * can return `__BT_FUNC_STATUS_OK`), we get it here
413 * depending on the actor's type.
415 if (self_component
) {
416 active_log_level
= get_self_component_log_level(
418 } else if (self_message_iterator
) {
419 active_log_level
= get_self_message_iterator_log_level(
420 self_message_iterator
);
423 BT_ASSERT(active_log_level
!= -1);
424 log_exception_and_maybe_append_error(BT_LOG_WARNING
,
425 active_log_level
, true,
426 self_component_class
, self_component
,
427 self_message_iterator
, module_name
);
429 if (PyErr_GivenExceptionMatches(exc
,
430 py_mod_bt2_exc_memory_error
)) {
431 status
= __BT_FUNC_STATUS_MEMORY_ERROR
;
433 status
= __BT_FUNC_STATUS_ERROR
;
443 int py_exc_to_status_component_class(
444 bt_self_component_class
*self_component_class
,
445 int active_log_level
)
447 return py_exc_to_status(self_component_class
, NULL
, NULL
, NULL
,
452 int py_exc_to_status_component(bt_self_component
*self_component
)
454 return py_exc_to_status(NULL
, self_component
, NULL
, NULL
, -1);
458 int py_exc_to_status_message_iterator(
459 bt_self_message_iterator
*self_message_iterator
)
461 return py_exc_to_status(NULL
, NULL
, self_message_iterator
, NULL
, -1);
464 /* Component class proxy methods (delegate to the attached Python object) */
467 bt_component_class_init_method_status
component_class_init(
468 bt_self_component
*self_component
,
469 void *self_component_v
,
470 swig_type_info
*self_comp_cls_type_swig_type
,
471 const bt_value
*params
,
472 void *init_method_data
)
474 const bt_component
*component
= bt_self_component_as_component(self_component
);
475 const bt_component_class
*component_class
= bt_component_borrow_class_const(component
);
476 bt_component_class_init_method_status status
= __BT_FUNC_STATUS_OK
;
477 PyObject
*py_cls
= NULL
;
478 PyObject
*py_comp
= NULL
;
479 PyObject
*py_params_ptr
= NULL
;
480 PyObject
*py_comp_ptr
= NULL
;
481 bt_logging_level log_level
= get_self_component_log_level(
484 (void) init_method_data
;
486 BT_ASSERT(self_component
);
487 BT_ASSERT(self_component_v
);
488 BT_ASSERT(self_comp_cls_type_swig_type
);
491 * Get the user-defined Python class which created this
492 * component's class in the first place (borrowed
495 py_cls
= lookup_cc_ptr_to_py_cls(component_class
);
497 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
498 "Cannot find Python class associated to native component class: "
499 "comp-cls-addr=%p", component_class
);
503 /* Parameters pointer -> SWIG pointer Python object */
504 py_params_ptr
= SWIG_NewPointerObj(SWIG_as_voidptr(params
),
505 SWIGTYPE_p_bt_value
, 0);
506 if (!py_params_ptr
) {
507 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
508 "Failed to create a SWIG pointer object.");
512 py_comp_ptr
= SWIG_NewPointerObj(SWIG_as_voidptr(self_component_v
),
513 self_comp_cls_type_swig_type
, 0);
515 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
516 "Failed to create a SWIG pointer object.");
521 * Do the equivalent of this:
523 * py_comp = py_cls._bt_init_from_native(py_comp_ptr, py_params_ptr)
525 * _UserComponentType._bt_init_from_native() calls the Python
526 * component object's __init__() function.
528 py_comp
= PyObject_CallMethod(py_cls
,
529 "_bt_init_from_native", "(OO)", py_comp_ptr
, py_params_ptr
);
531 BT_COMP_LOG_CUR_LVL(BT_LOG_WARNING
, log_level
, self_component
,
532 "Failed to call Python class's _bt_init_from_native() method: "
533 "py-cls-addr=%p", py_cls
);
534 status
= py_exc_to_status_component(self_component
);
539 * Our user Python component object is now fully created and
540 * initialized by the user. Since we just created it, this
541 * native component is its only (persistent) owner.
543 bt_self_component_set_data(self_component
, py_comp
);
548 status
= __BT_FUNC_STATUS_ERROR
;
551 * Clear any exception: we're returning a bad status anyway. If
552 * this call originated from Python (creation from a plugin's
553 * component class, for example), then the user gets an
554 * appropriate creation error.
560 Py_XDECREF(py_params_ptr
);
561 Py_XDECREF(py_comp_ptr
);
566 * Method of bt_component_class_source to initialize a bt_self_component_source
571 bt_component_class_init_method_status
component_class_source_init(
572 bt_self_component_source
*self_component_source
,
573 const bt_value
*params
, void *init_method_data
)
575 bt_self_component
*self_component
= bt_self_component_source_as_self_component(self_component_source
);
576 return component_class_init(
578 self_component_source
,
579 SWIGTYPE_p_bt_self_component_source
,
580 params
, init_method_data
);
584 bt_component_class_init_method_status
component_class_filter_init(
585 bt_self_component_filter
*self_component_filter
,
586 const bt_value
*params
, void *init_method_data
)
588 bt_self_component
*self_component
= bt_self_component_filter_as_self_component(self_component_filter
);
589 return component_class_init(
591 self_component_filter
,
592 SWIGTYPE_p_bt_self_component_filter
,
593 params
, init_method_data
);
597 bt_component_class_init_method_status
component_class_sink_init(
598 bt_self_component_sink
*self_component_sink
,
599 const bt_value
*params
, void *init_method_data
)
601 bt_self_component
*self_component
= bt_self_component_sink_as_self_component(self_component_sink
);
602 return component_class_init(
605 SWIGTYPE_p_bt_self_component_sink
,
606 params
, init_method_data
);
610 void component_class_finalize(bt_self_component
*self_component
)
612 PyObject
*py_comp
= bt_self_component_get_data(self_component
);
615 /* Call user's _user_finalize() method */
616 PyObject
*py_method_result
= PyObject_CallMethod(py_comp
,
617 "_user_finalize", NULL
);
619 if (PyErr_Occurred()) {
620 bt_logging_level log_level
= get_self_component_log_level(
623 BT_COMP_LOG_CUR_LVL(BT_LOG_WARNING
, log_level
, self_component
,
624 "User component's _user_finalize() method raised an exception: ignoring:");
625 logw_exception(log_level
);
629 * Ignore any exception raised by the _user_finalize() method
630 * because it won't change anything at this point: the component
631 * is being destroyed anyway.
634 Py_XDECREF(py_method_result
);
639 void component_class_source_finalize(bt_self_component_source
*self_component_source
)
641 bt_self_component
*self_component
= bt_self_component_source_as_self_component(self_component_source
);
642 component_class_finalize(self_component
);
646 void component_class_filter_finalize(bt_self_component_filter
*self_component_filter
)
648 bt_self_component
*self_component
= bt_self_component_filter_as_self_component(self_component_filter
);
649 component_class_finalize(self_component
);
653 void component_class_sink_finalize(bt_self_component_sink
*self_component_sink
)
655 bt_self_component
*self_component
= bt_self_component_sink_as_self_component(self_component_sink
);
656 component_class_finalize(self_component
);
660 bt_bool
component_class_can_seek_beginning(
661 bt_self_message_iterator
*self_message_iterator
)
664 PyObject
*py_result
= NULL
;
665 bt_bool can_seek_beginning
= false;
667 py_iter
= bt_self_message_iterator_get_data(self_message_iterator
);
670 py_result
= PyObject_GetAttrString(py_iter
, "_bt_can_seek_beginning_from_native");
672 BT_ASSERT(!py_result
|| PyBool_Check(py_result
));
675 can_seek_beginning
= PyObject_IsTrue(py_result
);
678 * Once can_seek_beginning can report errors, convert the
679 * exception to a status. For now, log and return false;
681 loge_exception_message_iterator(self_message_iterator
);
685 Py_XDECREF(py_result
);
687 return can_seek_beginning
;
691 bt_component_class_message_iterator_seek_beginning_method_status
692 component_class_seek_beginning(bt_self_message_iterator
*self_message_iterator
)
696 bt_component_class_message_iterator_seek_beginning_method_status status
;
698 py_iter
= bt_self_message_iterator_get_data(self_message_iterator
);
700 py_result
= PyObject_CallMethod(py_iter
, "_bt_seek_beginning_from_native",
702 BT_ASSERT(!py_result
|| py_result
== Py_None
);
703 status
= py_exc_to_status_message_iterator(self_message_iterator
);
704 Py_XDECREF(py_result
);
709 bt_component_class_port_connected_method_status
component_class_port_connected(
710 bt_self_component
*self_component
,
711 void *self_component_port
,
712 swig_type_info
*self_component_port_swig_type
,
713 bt_port_type self_component_port_type
,
714 const void *other_port
,
715 swig_type_info
*other_port_swig_type
)
717 bt_component_class_port_connected_method_status status
;
718 PyObject
*py_comp
= NULL
;
719 PyObject
*py_self_port_ptr
= NULL
;
720 PyObject
*py_other_port_ptr
= NULL
;
721 PyObject
*py_method_result
= NULL
;
722 bt_logging_level log_level
= get_self_component_log_level(
725 py_comp
= bt_self_component_get_data(self_component
);
727 py_self_port_ptr
= SWIG_NewPointerObj(SWIG_as_voidptr(self_component_port
),
728 self_component_port_swig_type
, 0);
729 if (!py_self_port_ptr
) {
730 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
731 "Failed to create a SWIG pointer object.");
732 status
= __BT_FUNC_STATUS_MEMORY_ERROR
;
736 py_other_port_ptr
= SWIG_NewPointerObj(SWIG_as_voidptr(other_port
),
737 other_port_swig_type
, 0);
738 if (!py_other_port_ptr
) {
739 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
740 "Failed to create a SWIG pointer object.");
741 status
= __BT_FUNC_STATUS_MEMORY_ERROR
;
744 py_method_result
= PyObject_CallMethod(py_comp
,
745 "_bt_port_connected_from_native", "(OiO)", py_self_port_ptr
,
746 self_component_port_type
, py_other_port_ptr
);
747 BT_ASSERT(!py_method_result
|| py_method_result
== Py_None
);
748 status
= py_exc_to_status_component(self_component
);
751 Py_XDECREF(py_self_port_ptr
);
752 Py_XDECREF(py_other_port_ptr
);
753 Py_XDECREF(py_method_result
);
758 bt_component_class_port_connected_method_status
759 component_class_source_output_port_connected(
760 bt_self_component_source
*self_component_source
,
761 bt_self_component_port_output
*self_component_port_output
,
762 const bt_port_input
*other_port_input
)
764 bt_self_component
*self_component
= bt_self_component_source_as_self_component(self_component_source
);
766 return component_class_port_connected(
768 self_component_port_output
,
769 SWIGTYPE_p_bt_self_component_port_output
,
772 SWIGTYPE_p_bt_port_input
);
776 bt_component_class_port_connected_method_status
777 component_class_filter_input_port_connected(
778 bt_self_component_filter
*self_component_filter
,
779 bt_self_component_port_input
*self_component_port_input
,
780 const bt_port_output
*other_port_output
)
782 bt_self_component
*self_component
= bt_self_component_filter_as_self_component(self_component_filter
);
784 return component_class_port_connected(
786 self_component_port_input
,
787 SWIGTYPE_p_bt_self_component_port_input
,
790 SWIGTYPE_p_bt_port_output
);
794 bt_component_class_port_connected_method_status
795 component_class_filter_output_port_connected(
796 bt_self_component_filter
*self_component_filter
,
797 bt_self_component_port_output
*self_component_port_output
,
798 const bt_port_input
*other_port_input
)
800 bt_self_component
*self_component
= bt_self_component_filter_as_self_component(self_component_filter
);
802 return component_class_port_connected(
804 self_component_port_output
,
805 SWIGTYPE_p_bt_self_component_port_output
,
808 SWIGTYPE_p_bt_port_input
);
812 bt_component_class_port_connected_method_status
813 component_class_sink_input_port_connected(
814 bt_self_component_sink
*self_component_sink
,
815 bt_self_component_port_input
*self_component_port_input
,
816 const bt_port_output
*other_port_output
)
818 bt_self_component
*self_component
= bt_self_component_sink_as_self_component(self_component_sink
);
820 return component_class_port_connected(
822 self_component_port_input
,
823 SWIGTYPE_p_bt_self_component_port_input
,
826 SWIGTYPE_p_bt_port_output
);
830 bt_component_class_sink_graph_is_configured_method_status
831 component_class_sink_graph_is_configured(
832 bt_self_component_sink
*self_component_sink
)
834 PyObject
*py_comp
= NULL
;
835 PyObject
*py_method_result
= NULL
;
836 bt_component_class_sink_graph_is_configured_method_status status
= __BT_FUNC_STATUS_OK
;
837 bt_self_component
*self_component
= bt_self_component_sink_as_self_component(self_component_sink
);
839 py_comp
= bt_self_component_get_data(self_component
);
840 py_method_result
= PyObject_CallMethod(py_comp
,
841 "_bt_graph_is_configured_from_native", NULL
);
842 BT_ASSERT(!py_method_result
|| py_method_result
== Py_None
);
843 status
= py_exc_to_status_component(self_component
);
844 Py_XDECREF(py_method_result
);
849 bt_component_class_query_method_status
component_class_query(
850 const bt_component_class
*component_class
,
851 bt_self_component_class
*self_component_class
,
852 bt_private_query_executor
*priv_query_executor
,
853 const char *object
, const bt_value
*params
,
854 const bt_value
**result
)
856 PyObject
*py_cls
= NULL
;
857 PyObject
*py_params_ptr
= NULL
;
858 PyObject
*py_priv_query_exec_ptr
= NULL
;
859 PyObject
*py_query_func
= NULL
;
860 PyObject
*py_object
= NULL
;
861 PyObject
*py_results_addr
= NULL
;
862 bt_component_class_query_method_status status
= __BT_FUNC_STATUS_OK
;
863 const bt_query_executor
*query_exec
=
864 bt_private_query_executor_as_query_executor_const(
865 priv_query_executor
);
866 bt_logging_level log_level
=
867 bt_query_executor_get_logging_level(query_exec
);
869 py_cls
= lookup_cc_ptr_to_py_cls(component_class
);
871 BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR
, log_level
, BT_LOG_TAG
,
872 "Cannot find Python class associated to native component class: "
873 "comp-cls-addr=%p", component_class
);
877 py_params_ptr
= SWIG_NewPointerObj(SWIG_as_voidptr(params
),
878 SWIGTYPE_p_bt_value
, 0);
879 if (!py_params_ptr
) {
880 BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR
, log_level
, BT_LOG_TAG
,
881 "Failed to create a SWIG pointer object.");
885 py_priv_query_exec_ptr
= SWIG_NewPointerObj(
886 SWIG_as_voidptr(priv_query_executor
),
887 SWIGTYPE_p_bt_private_query_executor
, 0);
888 if (!py_priv_query_exec_ptr
) {
889 BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR
, log_level
, BT_LOG_TAG
,
890 "Failed to create a SWIG pointer object.");
894 py_object
= SWIG_FromCharPtr(object
);
896 BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR
, log_level
, BT_LOG_TAG
,
897 "Failed to create a Python string.");
901 py_results_addr
= PyObject_CallMethod(py_cls
,
902 "_bt_query_from_native", "(OOO)", py_priv_query_exec_ptr
,
903 py_object
, py_params_ptr
);
904 if (!py_results_addr
) {
905 BT_LOG_WRITE_CUR_LVL(BT_LOG_WARNING
, log_level
, BT_LOG_TAG
,
906 "Failed to call Python class's _bt_query_from_native() method: "
907 "py-cls-addr=%p", py_cls
);
908 status
= py_exc_to_status_component_class(self_component_class
,
914 * The returned object, on success, is an integer object
915 * (PyLong) containing the address of a BT value object (new
918 *result
= PyLong_AsVoidPtr(py_results_addr
);
919 BT_ASSERT(!PyErr_Occurred());
925 status
= __BT_FUNC_STATUS_ERROR
;
928 Py_XDECREF(py_params_ptr
);
929 Py_XDECREF(py_priv_query_exec_ptr
);
930 Py_XDECREF(py_query_func
);
931 Py_XDECREF(py_object
);
932 Py_XDECREF(py_results_addr
);
937 bt_component_class_query_method_status
component_class_source_query(
938 bt_self_component_class_source
*self_component_class_source
,
939 bt_private_query_executor
*priv_query_executor
,
940 const char *object
, const bt_value
*params
,
941 const bt_value
**result
)
943 const bt_component_class_source
*component_class_source
= bt_self_component_class_source_as_component_class_source(self_component_class_source
);
944 const bt_component_class
*component_class
= bt_component_class_source_as_component_class_const(component_class_source
);
945 bt_self_component_class
*self_component_class
= bt_self_component_class_source_as_self_component_class(self_component_class_source
);
947 return component_class_query(component_class
, self_component_class
,
948 priv_query_executor
, object
, params
, result
);
952 bt_component_class_query_method_status
component_class_filter_query(
953 bt_self_component_class_filter
*self_component_class_filter
,
954 bt_private_query_executor
*priv_query_executor
,
955 const char *object
, const bt_value
*params
,
956 const bt_value
**result
)
958 const bt_component_class_filter
*component_class_filter
= bt_self_component_class_filter_as_component_class_filter(self_component_class_filter
);
959 const bt_component_class
*component_class
= bt_component_class_filter_as_component_class_const(component_class_filter
);
960 bt_self_component_class
*self_component_class
= bt_self_component_class_filter_as_self_component_class(self_component_class_filter
);
962 return component_class_query(component_class
, self_component_class
,
963 priv_query_executor
, object
, params
, result
);
967 bt_component_class_query_method_status
component_class_sink_query(
968 bt_self_component_class_sink
*self_component_class_sink
,
969 bt_private_query_executor
*priv_query_executor
,
970 const char *object
, const bt_value
*params
,
971 const bt_value
**result
)
973 const bt_component_class_sink
*component_class_sink
= bt_self_component_class_sink_as_component_class_sink(self_component_class_sink
);
974 const bt_component_class
*component_class
= bt_component_class_sink_as_component_class_const(component_class_sink
);
975 bt_self_component_class
*self_component_class
= bt_self_component_class_sink_as_self_component_class(self_component_class_sink
);
977 return component_class_query(component_class
, self_component_class
,
978 priv_query_executor
, object
, params
, result
);
982 bt_component_class_message_iterator_init_method_status
983 component_class_message_iterator_init(
984 bt_self_message_iterator
*self_message_iterator
,
985 bt_self_component
*self_component
,
986 bt_self_component_port_output
*self_component_port_output
)
988 bt_component_class_message_iterator_init_method_status status
= __BT_FUNC_STATUS_OK
;
989 PyObject
*py_comp_cls
= NULL
;
990 PyObject
*py_iter_cls
= NULL
;
991 PyObject
*py_iter_ptr
= NULL
;
992 PyObject
*py_component_port_output_ptr
= NULL
;
993 PyObject
*py_init_method_result
= NULL
;
994 PyObject
*py_iter
= NULL
;
996 bt_logging_level log_level
= get_self_component_log_level(
999 py_comp
= bt_self_component_get_data(self_component
);
1001 /* Find user's Python message iterator class */
1002 py_comp_cls
= PyObject_GetAttrString(py_comp
, "__class__");
1004 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
1005 "Cannot get Python object's `__class__` attribute.");
1009 py_iter_cls
= PyObject_GetAttrString(py_comp_cls
, "_iter_cls");
1011 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
1012 "Cannot get Python class's `_iter_cls` attribute.");
1016 py_iter_ptr
= SWIG_NewPointerObj(SWIG_as_voidptr(self_message_iterator
),
1017 SWIGTYPE_p_bt_self_message_iterator
, 0);
1019 const char *err
= "Failed to create a SWIG pointer object.";
1021 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
1023 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR(
1024 self_message_iterator
, err
);
1029 * Create object with borrowed native message iterator
1032 * py_iter = py_iter_cls.__new__(py_iter_cls, py_iter_ptr)
1034 py_iter
= PyObject_CallMethod(py_iter_cls
, "__new__",
1035 "(OO)", py_iter_cls
, py_iter_ptr
);
1037 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
1038 "Failed to call Python class's __new__() method: "
1039 "py-cls-addr=%p", py_iter_cls
);
1044 * Initialize object:
1046 * py_iter.__init__(self_output_port)
1048 * through the _init_for_native helper static method.
1050 * At this point, py_iter._ptr is set, so this initialization
1051 * function has access to self._component (which gives it the
1052 * user Python component object from which the iterator was
1055 py_component_port_output_ptr
= SWIG_NewPointerObj(
1056 SWIG_as_voidptr(self_component_port_output
),
1057 SWIGTYPE_p_bt_self_component_port_output
, 0);
1058 if (!py_component_port_output_ptr
) {
1059 const char *err
= "Failed to create a SWIG pointer object.";
1061 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
1063 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR(
1064 self_message_iterator
, err
);
1068 py_init_method_result
= PyObject_CallMethod(py_iter
,
1069 "_bt_init_from_native", "O", py_component_port_output_ptr
);
1070 if (!py_init_method_result
) {
1071 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
1072 "User's __init__() method failed:");
1077 * Since the Python code can never instantiate a user-defined
1078 * message iterator class, the native message iterator
1079 * object does NOT belong to a user Python message iterator
1080 * object (borrowed reference). However this Python object is
1081 * owned by this native message iterator object.
1083 * In the Python world, the lifetime of the native message
1084 * iterator is managed by a _GenericMessageIterator
1087 * _GenericMessageIterator instance:
1088 * owns a native bt_message_iterator object (iter)
1089 * owns a _UserMessageIterator instance (py_iter)
1090 * self._ptr is a borrowed reference to the
1091 * native bt_private_connection_private_message_iterator
1094 bt_self_message_iterator_set_data(self_message_iterator
, py_iter
);
1099 /* Handling of errors that cause a Python exception to be set. */
1100 status
= py_exc_to_status_message_iterator(self_message_iterator
);
1101 BT_ASSERT(status
!= __BT_FUNC_STATUS_OK
);
1105 /* Handling of errors that don't cause a Python exception to be set. */
1106 status
= __BT_FUNC_STATUS_ERROR
;
1109 BT_ASSERT(!PyErr_Occurred());
1111 Py_XDECREF(py_comp_cls
);
1112 Py_XDECREF(py_iter_cls
);
1113 Py_XDECREF(py_iter_ptr
);
1114 Py_XDECREF(py_component_port_output_ptr
);
1115 Py_XDECREF(py_init_method_result
);
1116 Py_XDECREF(py_iter
);
1121 bt_component_class_message_iterator_init_method_status
1122 component_class_source_message_iterator_init(
1123 bt_self_message_iterator
*self_message_iterator
,
1124 bt_self_component_source
*self_component_source
,
1125 bt_self_component_port_output
*self_component_port_output
)
1127 bt_self_component
*self_component
= bt_self_component_source_as_self_component(self_component_source
);
1129 return component_class_message_iterator_init(self_message_iterator
, self_component
, self_component_port_output
);
1133 bt_component_class_message_iterator_init_method_status
1134 component_class_filter_message_iterator_init(
1135 bt_self_message_iterator
*self_message_iterator
,
1136 bt_self_component_filter
*self_component_filter
,
1137 bt_self_component_port_output
*self_component_port_output
)
1139 bt_self_component
*self_component
= bt_self_component_filter_as_self_component(self_component_filter
);
1141 return component_class_message_iterator_init(self_message_iterator
, self_component
, self_component_port_output
);
1145 void component_class_message_iterator_finalize(
1146 bt_self_message_iterator
*message_iterator
)
1148 PyObject
*py_message_iter
= bt_self_message_iterator_get_data(
1150 PyObject
*py_method_result
= NULL
;
1152 BT_ASSERT(py_message_iter
);
1154 /* Call user's _user_finalize() method */
1155 py_method_result
= PyObject_CallMethod(py_message_iter
,
1156 "_user_finalize", NULL
);
1158 if (PyErr_Occurred()) {
1159 bt_self_component
*self_comp
=
1160 bt_self_message_iterator_borrow_component(
1162 bt_logging_level log_level
= get_self_component_log_level(
1165 BT_COMP_LOG_CUR_LVL(BT_LOG_WARNING
, log_level
, self_comp
,
1166 "User's _user_finalize() method raised an exception: ignoring:");
1167 logw_exception(get_self_message_iterator_log_level(
1172 * Ignore any exception raised by the _user_finalize() method
1173 * because it won't change anything at this point: the component
1174 * is being destroyed anyway.
1177 Py_XDECREF(py_method_result
);
1178 Py_DECREF(py_message_iter
);
1181 /* Valid for both sources and filters. */
1184 bt_component_class_message_iterator_next_method_status
1185 component_class_message_iterator_next(
1186 bt_self_message_iterator
*message_iterator
,
1187 bt_message_array_const msgs
, uint64_t capacity
,
1190 bt_component_class_message_iterator_next_method_status status
= __BT_FUNC_STATUS_OK
;
1191 PyObject
*py_message_iter
= bt_self_message_iterator_get_data(message_iterator
);
1192 PyObject
*py_method_result
= NULL
;
1194 BT_ASSERT(py_message_iter
);
1195 py_method_result
= PyObject_CallMethod(py_message_iter
,
1196 "_bt_next_from_native", NULL
);
1197 if (!py_method_result
) {
1198 status
= py_exc_to_status_message_iterator(message_iterator
);
1199 BT_ASSERT(status
!= __BT_FUNC_STATUS_OK
);
1204 * The returned object, on success, is an integer object
1205 * (PyLong) containing the address of a native message
1206 * object (which is now ours).
1208 msgs
[0] = PyLong_AsVoidPtr(py_method_result
);
1211 /* Clear potential overflow error; should never happen */
1212 BT_ASSERT(!PyErr_Occurred());
1216 Py_XDECREF(py_method_result
);
1221 bt_component_class_sink_consume_method_status
1222 component_class_sink_consume(bt_self_component_sink
*self_component_sink
)
1224 bt_self_component
*self_component
= bt_self_component_sink_as_self_component(self_component_sink
);
1225 PyObject
*py_comp
= bt_self_component_get_data(self_component
);
1226 PyObject
*py_method_result
= NULL
;
1227 bt_component_class_sink_consume_method_status status
;
1230 py_method_result
= PyObject_CallMethod(py_comp
,
1231 "_user_consume", NULL
);
1232 status
= py_exc_to_status_component(self_component
);
1233 BT_ASSERT(py_method_result
|| status
!= __BT_FUNC_STATUS_OK
);
1234 Py_XDECREF(py_method_result
);
1239 int component_class_set_help_and_desc(
1240 bt_component_class
*component_class
,
1241 const char *description
, const char *help
)
1246 ret
= bt_component_class_set_description(component_class
, description
);
1248 BT_LOGE("Cannot set component class's description: "
1249 "comp-cls-addr=%p", component_class
);
1255 ret
= bt_component_class_set_help(component_class
, help
);
1257 BT_LOGE("Cannot set component class's help text: "
1258 "comp-cls-addr=%p", component_class
);
1270 bt_component_class_source
*bt_bt2_component_class_source_create(
1271 PyObject
*py_cls
, const char *name
, const char *description
,
1274 bt_component_class_source
*component_class_source
;
1275 bt_component_class
*component_class
;
1279 component_class_source
= bt_component_class_source_create(name
,
1280 component_class_message_iterator_next
);
1281 if (!component_class_source
) {
1282 BT_LOGE_STR("Cannot create source component class.");
1286 component_class
= bt_component_class_source_as_component_class(component_class_source
);
1288 if (component_class_set_help_and_desc(component_class
, description
, help
)) {
1292 ret
= bt_component_class_source_set_init_method(component_class_source
, component_class_source_init
);
1293 BT_ASSERT(ret
== 0);
1294 ret
= bt_component_class_source_set_finalize_method(component_class_source
, component_class_source_finalize
);
1295 BT_ASSERT(ret
== 0);
1296 ret
= bt_component_class_source_set_message_iterator_can_seek_beginning_method(component_class_source
,
1297 component_class_can_seek_beginning
);
1298 BT_ASSERT(ret
== 0);
1299 ret
= bt_component_class_source_set_message_iterator_seek_beginning_method(component_class_source
,
1300 component_class_seek_beginning
);
1301 BT_ASSERT(ret
== 0);
1302 ret
= bt_component_class_source_set_output_port_connected_method(component_class_source
,
1303 component_class_source_output_port_connected
);
1304 BT_ASSERT(ret
== 0);
1305 ret
= bt_component_class_source_set_query_method(component_class_source
, component_class_source_query
);
1306 BT_ASSERT(ret
== 0);
1307 ret
= bt_component_class_source_set_message_iterator_init_method(
1308 component_class_source
, component_class_source_message_iterator_init
);
1309 BT_ASSERT(ret
== 0);
1310 ret
= bt_component_class_source_set_message_iterator_finalize_method(
1311 component_class_source
, component_class_message_iterator_finalize
);
1312 BT_ASSERT(ret
== 0);
1313 register_cc_ptr_to_py_cls(component_class
, py_cls
);
1316 return component_class_source
;
1320 bt_component_class_filter
*bt_bt2_component_class_filter_create(
1321 PyObject
*py_cls
, const char *name
, const char *description
,
1324 bt_component_class
*component_class
;
1325 bt_component_class_filter
*component_class_filter
;
1329 component_class_filter
= bt_component_class_filter_create(name
,
1330 component_class_message_iterator_next
);
1331 if (!component_class_filter
) {
1332 BT_LOGE_STR("Cannot create filter component class.");
1336 component_class
= bt_component_class_filter_as_component_class(component_class_filter
);
1338 if (component_class_set_help_and_desc(component_class
, description
, help
)) {
1342 ret
= bt_component_class_filter_set_init_method(component_class_filter
, component_class_filter_init
);
1343 BT_ASSERT(ret
== 0);
1344 ret
= bt_component_class_filter_set_finalize_method (component_class_filter
, component_class_filter_finalize
);
1345 BT_ASSERT(ret
== 0);
1346 ret
= bt_component_class_filter_set_message_iterator_can_seek_beginning_method(component_class_filter
,
1347 component_class_can_seek_beginning
);
1348 BT_ASSERT(ret
== 0);
1349 ret
= bt_component_class_filter_set_message_iterator_seek_beginning_method(component_class_filter
,
1350 component_class_seek_beginning
);
1351 BT_ASSERT(ret
== 0);
1352 ret
= bt_component_class_filter_set_input_port_connected_method(component_class_filter
,
1353 component_class_filter_input_port_connected
);
1354 BT_ASSERT(ret
== 0);
1355 ret
= bt_component_class_filter_set_output_port_connected_method(component_class_filter
,
1356 component_class_filter_output_port_connected
);
1357 BT_ASSERT(ret
== 0);
1358 ret
= bt_component_class_filter_set_query_method(component_class_filter
, component_class_filter_query
);
1359 BT_ASSERT(ret
== 0);
1360 ret
= bt_component_class_filter_set_message_iterator_init_method(
1361 component_class_filter
, component_class_filter_message_iterator_init
);
1362 BT_ASSERT(ret
== 0);
1363 ret
= bt_component_class_filter_set_message_iterator_finalize_method(
1364 component_class_filter
, component_class_message_iterator_finalize
);
1365 BT_ASSERT(ret
== 0);
1366 register_cc_ptr_to_py_cls(component_class
, py_cls
);
1369 return component_class_filter
;
1373 bt_component_class_sink
*bt_bt2_component_class_sink_create(
1374 PyObject
*py_cls
, const char *name
, const char *description
,
1377 bt_component_class_sink
*component_class_sink
;
1378 bt_component_class
*component_class
;
1382 component_class_sink
= bt_component_class_sink_create(name
, component_class_sink_consume
);
1384 if (!component_class_sink
) {
1385 BT_LOGE_STR("Cannot create sink component class.");
1389 component_class
= bt_component_class_sink_as_component_class(component_class_sink
);
1391 if (component_class_set_help_and_desc(component_class
, description
, help
)) {
1395 ret
= bt_component_class_sink_set_init_method(component_class_sink
, component_class_sink_init
);
1396 BT_ASSERT(ret
== 0);
1397 ret
= bt_component_class_sink_set_finalize_method(component_class_sink
, component_class_sink_finalize
);
1398 BT_ASSERT(ret
== 0);
1399 ret
= bt_component_class_sink_set_input_port_connected_method(component_class_sink
,
1400 component_class_sink_input_port_connected
);
1401 BT_ASSERT(ret
== 0);
1402 ret
= bt_component_class_sink_set_graph_is_configured_method(component_class_sink
,
1403 component_class_sink_graph_is_configured
);
1404 BT_ASSERT(ret
== 0);
1405 ret
= bt_component_class_sink_set_query_method(component_class_sink
, component_class_sink_query
);
1406 BT_ASSERT(ret
== 0);
1407 register_cc_ptr_to_py_cls(component_class
, py_cls
);
1410 return component_class_sink
;