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 bt_bt2_unregister_cc_ptr_to_py_cls(const bt_component_class
*comp_cls
)
52 if (!bt_cc_ptr_to_py_cls
) {
56 existed
= g_hash_table_remove(bt_cc_ptr_to_py_cls
, comp_cls
);
61 void register_cc_ptr_to_py_cls(struct bt_component_class
*bt_cc
,
64 if (!bt_cc_ptr_to_py_cls
) {
66 * Lazy-initializing this GHashTable because GLib
67 * might not be initialized yet and it needs to be
68 * before we call g_hash_table_new()
70 BT_LOGD_STR("Creating native component class to Python component class hash table.");
71 bt_cc_ptr_to_py_cls
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
72 BT_ASSERT(bt_cc_ptr_to_py_cls
);
75 g_hash_table_insert(bt_cc_ptr_to_py_cls
, (gpointer
) bt_cc
,
80 PyObject
*lookup_cc_ptr_to_py_cls(const bt_component_class
*bt_cc
)
82 if (!bt_cc_ptr_to_py_cls
) {
83 BT_LOGW("Cannot look up Python component class because hash table is NULL: "
84 "comp-cls-addr=%p", bt_cc
);
88 return (PyObject
*) g_hash_table_lookup(bt_cc_ptr_to_py_cls
,
89 (gconstpointer
) bt_cc
);
92 /* Library destructor */
94 __attribute__((destructor
))
96 void native_comp_class_dtor(void) {
97 /* Destroy component class association hash table */
98 if (bt_cc_ptr_to_py_cls
) {
99 BT_LOGD_STR("Destroying native component class to Python component class hash table.");
100 g_hash_table_destroy(bt_cc_ptr_to_py_cls
);
101 bt_cc_ptr_to_py_cls
= NULL
;
106 int py_exc_to_status(bt_self_component_class
*self_component_class
,
107 bt_self_component
*self_component
,
108 bt_self_message_iterator
*self_message_iterator
,
109 const char *module_name
, int active_log_level
)
111 int status
= __BT_FUNC_STATUS_OK
;
112 PyObject
*exc
= PyErr_Occurred();
118 if (PyErr_GivenExceptionMatches(exc
,
119 py_mod_bt2_exc_try_again_type
)) {
120 status
= __BT_FUNC_STATUS_AGAIN
;
121 } else if (PyErr_GivenExceptionMatches(exc
,
122 py_mod_bt2_exc_stop_type
)) {
123 status
= __BT_FUNC_STATUS_END
;
124 } else if (PyErr_GivenExceptionMatches(exc
,
125 py_mod_bt2_exc_unknown_object_type
)) {
126 status
= __BT_FUNC_STATUS_UNKNOWN_OBJECT
;
129 * Unknown exception: convert to general error.
131 * Because we only want to fetch the log level when
132 * we actually get an exception, and not systematically
133 * when we call py_exc_to_status() (as py_exc_to_status()
134 * can return `__BT_FUNC_STATUS_OK`), we get it here
135 * depending on the actor's type.
137 if (self_component
) {
138 active_log_level
= get_self_component_log_level(
140 } else if (self_message_iterator
) {
141 active_log_level
= get_self_message_iterator_log_level(
142 self_message_iterator
);
145 BT_ASSERT(active_log_level
!= -1);
146 log_exception_and_maybe_append_error(BT_LOG_WARNING
,
147 active_log_level
, true,
148 self_component_class
, self_component
,
149 self_message_iterator
, module_name
);
151 if (PyErr_GivenExceptionMatches(exc
,
152 py_mod_bt2_exc_memory_error
)) {
153 status
= __BT_FUNC_STATUS_MEMORY_ERROR
;
155 status
= __BT_FUNC_STATUS_ERROR
;
165 int py_exc_to_status_component_class(
166 bt_self_component_class
*self_component_class
,
167 int active_log_level
)
169 return py_exc_to_status(self_component_class
, NULL
, NULL
, NULL
,
174 int py_exc_to_status_component(bt_self_component
*self_component
)
176 return py_exc_to_status(NULL
, self_component
, NULL
, NULL
, -1);
180 int py_exc_to_status_message_iterator(
181 bt_self_message_iterator
*self_message_iterator
)
183 return py_exc_to_status(NULL
, NULL
, self_message_iterator
, NULL
, -1);
186 /* Component class proxy methods (delegate to the attached Python object) */
189 bt_component_class_init_method_status
component_class_init(
190 bt_self_component
*self_component
,
191 void *self_component_v
,
192 swig_type_info
*self_comp_cls_type_swig_type
,
193 const bt_value
*params
,
194 void *init_method_data
)
196 const bt_component
*component
= bt_self_component_as_component(self_component
);
197 const bt_component_class
*component_class
= bt_component_borrow_class_const(component
);
198 bt_component_class_init_method_status status
= __BT_FUNC_STATUS_OK
;
199 PyObject
*py_cls
= NULL
;
200 PyObject
*py_comp
= NULL
;
201 PyObject
*py_params_ptr
= NULL
;
202 PyObject
*py_comp_ptr
= NULL
;
203 bt_logging_level log_level
= get_self_component_log_level(
206 (void) init_method_data
;
208 BT_ASSERT(self_component
);
209 BT_ASSERT(self_component_v
);
210 BT_ASSERT(self_comp_cls_type_swig_type
);
213 * Get the user-defined Python class which created this
214 * component's class in the first place (borrowed
217 py_cls
= lookup_cc_ptr_to_py_cls(component_class
);
219 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
220 "Cannot find Python class associated to native component class: "
221 "comp-cls-addr=%p", component_class
);
225 /* Parameters pointer -> SWIG pointer Python object */
226 py_params_ptr
= SWIG_NewPointerObj(SWIG_as_voidptr(params
),
227 SWIGTYPE_p_bt_value
, 0);
228 if (!py_params_ptr
) {
229 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
230 "Failed to create a SWIG pointer object.");
234 py_comp_ptr
= SWIG_NewPointerObj(SWIG_as_voidptr(self_component_v
),
235 self_comp_cls_type_swig_type
, 0);
237 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
238 "Failed to create a SWIG pointer object.");
243 * Do the equivalent of this:
245 * py_comp = py_cls._bt_init_from_native(py_comp_ptr, py_params_ptr)
247 * _UserComponentType._bt_init_from_native() calls the Python
248 * component object's __init__() function.
250 py_comp
= PyObject_CallMethod(py_cls
,
251 "_bt_init_from_native", "(OO)", py_comp_ptr
, py_params_ptr
);
253 BT_COMP_LOG_CUR_LVL(BT_LOG_WARNING
, log_level
, self_component
,
254 "Failed to call Python class's _bt_init_from_native() method: "
255 "py-cls-addr=%p", py_cls
);
256 status
= py_exc_to_status_component(self_component
);
261 * Our user Python component object is now fully created and
262 * initialized by the user. Since we just created it, this
263 * native component is its only (persistent) owner.
265 bt_self_component_set_data(self_component
, py_comp
);
270 status
= __BT_FUNC_STATUS_ERROR
;
273 * Clear any exception: we're returning a bad status anyway. If
274 * this call originated from Python (creation from a plugin's
275 * component class, for example), then the user gets an
276 * appropriate creation error.
282 Py_XDECREF(py_params_ptr
);
283 Py_XDECREF(py_comp_ptr
);
288 * Method of bt_component_class_source to initialize a bt_self_component_source
293 bt_component_class_init_method_status
component_class_source_init(
294 bt_self_component_source
*self_component_source
,
295 const bt_value
*params
, void *init_method_data
)
297 bt_self_component
*self_component
= bt_self_component_source_as_self_component(self_component_source
);
298 return component_class_init(
300 self_component_source
,
301 SWIGTYPE_p_bt_self_component_source
,
302 params
, init_method_data
);
306 bt_component_class_init_method_status
component_class_filter_init(
307 bt_self_component_filter
*self_component_filter
,
308 const bt_value
*params
, void *init_method_data
)
310 bt_self_component
*self_component
= bt_self_component_filter_as_self_component(self_component_filter
);
311 return component_class_init(
313 self_component_filter
,
314 SWIGTYPE_p_bt_self_component_filter
,
315 params
, init_method_data
);
319 bt_component_class_init_method_status
component_class_sink_init(
320 bt_self_component_sink
*self_component_sink
,
321 const bt_value
*params
, void *init_method_data
)
323 bt_self_component
*self_component
= bt_self_component_sink_as_self_component(self_component_sink
);
324 return component_class_init(
327 SWIGTYPE_p_bt_self_component_sink
,
328 params
, init_method_data
);
332 void component_class_finalize(bt_self_component
*self_component
)
334 PyObject
*py_comp
= bt_self_component_get_data(self_component
);
337 /* Call user's _user_finalize() method */
338 PyObject
*py_method_result
= PyObject_CallMethod(py_comp
,
339 "_user_finalize", NULL
);
341 if (PyErr_Occurred()) {
342 bt_logging_level log_level
= get_self_component_log_level(
345 BT_COMP_LOG_CUR_LVL(BT_LOG_WARNING
, log_level
, self_component
,
346 "User component's _user_finalize() method raised an exception: ignoring:");
347 logw_exception(log_level
);
351 * Ignore any exception raised by the _user_finalize() method
352 * because it won't change anything at this point: the component
353 * is being destroyed anyway.
356 Py_XDECREF(py_method_result
);
361 void component_class_source_finalize(bt_self_component_source
*self_component_source
)
363 bt_self_component
*self_component
= bt_self_component_source_as_self_component(self_component_source
);
364 component_class_finalize(self_component
);
368 void component_class_filter_finalize(bt_self_component_filter
*self_component_filter
)
370 bt_self_component
*self_component
= bt_self_component_filter_as_self_component(self_component_filter
);
371 component_class_finalize(self_component
);
375 void component_class_sink_finalize(bt_self_component_sink
*self_component_sink
)
377 bt_self_component
*self_component
= bt_self_component_sink_as_self_component(self_component_sink
);
378 component_class_finalize(self_component
);
382 bt_bool
component_class_can_seek_beginning(
383 bt_self_message_iterator
*self_message_iterator
)
386 PyObject
*py_result
= NULL
;
387 bt_bool can_seek_beginning
= false;
389 py_iter
= bt_self_message_iterator_get_data(self_message_iterator
);
392 py_result
= PyObject_GetAttrString(py_iter
, "_bt_can_seek_beginning_from_native");
394 BT_ASSERT(!py_result
|| PyBool_Check(py_result
));
397 can_seek_beginning
= PyObject_IsTrue(py_result
);
400 * Once can_seek_beginning can report errors, convert the
401 * exception to a status. For now, log and return false;
403 loge_exception_message_iterator(self_message_iterator
);
407 Py_XDECREF(py_result
);
409 return can_seek_beginning
;
413 bt_component_class_message_iterator_seek_beginning_method_status
414 component_class_seek_beginning(bt_self_message_iterator
*self_message_iterator
)
418 bt_component_class_message_iterator_seek_beginning_method_status status
;
420 py_iter
= bt_self_message_iterator_get_data(self_message_iterator
);
422 py_result
= PyObject_CallMethod(py_iter
, "_bt_seek_beginning_from_native",
424 BT_ASSERT(!py_result
|| py_result
== Py_None
);
425 status
= py_exc_to_status_message_iterator(self_message_iterator
);
426 Py_XDECREF(py_result
);
431 bt_component_class_port_connected_method_status
component_class_port_connected(
432 bt_self_component
*self_component
,
433 void *self_component_port
,
434 swig_type_info
*self_component_port_swig_type
,
435 bt_port_type self_component_port_type
,
436 const void *other_port
,
437 swig_type_info
*other_port_swig_type
)
439 bt_component_class_port_connected_method_status status
;
440 PyObject
*py_comp
= NULL
;
441 PyObject
*py_self_port_ptr
= NULL
;
442 PyObject
*py_other_port_ptr
= NULL
;
443 PyObject
*py_method_result
= NULL
;
444 bt_logging_level log_level
= get_self_component_log_level(
447 py_comp
= bt_self_component_get_data(self_component
);
449 py_self_port_ptr
= SWIG_NewPointerObj(SWIG_as_voidptr(self_component_port
),
450 self_component_port_swig_type
, 0);
451 if (!py_self_port_ptr
) {
452 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
453 "Failed to create a SWIG pointer object.");
454 status
= __BT_FUNC_STATUS_MEMORY_ERROR
;
458 py_other_port_ptr
= SWIG_NewPointerObj(SWIG_as_voidptr(other_port
),
459 other_port_swig_type
, 0);
460 if (!py_other_port_ptr
) {
461 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
462 "Failed to create a SWIG pointer object.");
463 status
= __BT_FUNC_STATUS_MEMORY_ERROR
;
466 py_method_result
= PyObject_CallMethod(py_comp
,
467 "_bt_port_connected_from_native", "(OiO)", py_self_port_ptr
,
468 self_component_port_type
, py_other_port_ptr
);
469 BT_ASSERT(!py_method_result
|| py_method_result
== Py_None
);
470 status
= py_exc_to_status_component(self_component
);
473 Py_XDECREF(py_self_port_ptr
);
474 Py_XDECREF(py_other_port_ptr
);
475 Py_XDECREF(py_method_result
);
480 bt_component_class_port_connected_method_status
481 component_class_source_output_port_connected(
482 bt_self_component_source
*self_component_source
,
483 bt_self_component_port_output
*self_component_port_output
,
484 const bt_port_input
*other_port_input
)
486 bt_self_component
*self_component
= bt_self_component_source_as_self_component(self_component_source
);
488 return component_class_port_connected(
490 self_component_port_output
,
491 SWIGTYPE_p_bt_self_component_port_output
,
494 SWIGTYPE_p_bt_port_input
);
498 bt_component_class_port_connected_method_status
499 component_class_filter_input_port_connected(
500 bt_self_component_filter
*self_component_filter
,
501 bt_self_component_port_input
*self_component_port_input
,
502 const bt_port_output
*other_port_output
)
504 bt_self_component
*self_component
= bt_self_component_filter_as_self_component(self_component_filter
);
506 return component_class_port_connected(
508 self_component_port_input
,
509 SWIGTYPE_p_bt_self_component_port_input
,
512 SWIGTYPE_p_bt_port_output
);
516 bt_component_class_port_connected_method_status
517 component_class_filter_output_port_connected(
518 bt_self_component_filter
*self_component_filter
,
519 bt_self_component_port_output
*self_component_port_output
,
520 const bt_port_input
*other_port_input
)
522 bt_self_component
*self_component
= bt_self_component_filter_as_self_component(self_component_filter
);
524 return component_class_port_connected(
526 self_component_port_output
,
527 SWIGTYPE_p_bt_self_component_port_output
,
530 SWIGTYPE_p_bt_port_input
);
534 bt_component_class_port_connected_method_status
535 component_class_sink_input_port_connected(
536 bt_self_component_sink
*self_component_sink
,
537 bt_self_component_port_input
*self_component_port_input
,
538 const bt_port_output
*other_port_output
)
540 bt_self_component
*self_component
= bt_self_component_sink_as_self_component(self_component_sink
);
542 return component_class_port_connected(
544 self_component_port_input
,
545 SWIGTYPE_p_bt_self_component_port_input
,
548 SWIGTYPE_p_bt_port_output
);
552 bt_component_class_sink_graph_is_configured_method_status
553 component_class_sink_graph_is_configured(
554 bt_self_component_sink
*self_component_sink
)
556 PyObject
*py_comp
= NULL
;
557 PyObject
*py_method_result
= NULL
;
558 bt_component_class_sink_graph_is_configured_method_status status
= __BT_FUNC_STATUS_OK
;
559 bt_self_component
*self_component
= bt_self_component_sink_as_self_component(self_component_sink
);
561 py_comp
= bt_self_component_get_data(self_component
);
562 py_method_result
= PyObject_CallMethod(py_comp
,
563 "_bt_graph_is_configured_from_native", NULL
);
564 BT_ASSERT(!py_method_result
|| py_method_result
== Py_None
);
565 status
= py_exc_to_status_component(self_component
);
566 Py_XDECREF(py_method_result
);
571 bt_component_class_query_method_status
component_class_query(
572 const bt_component_class
*component_class
,
573 bt_self_component_class
*self_component_class
,
574 bt_private_query_executor
*priv_query_executor
,
575 const char *object
, const bt_value
*params
,
576 const bt_value
**result
)
578 PyObject
*py_cls
= NULL
;
579 PyObject
*py_params_ptr
= NULL
;
580 PyObject
*py_priv_query_exec_ptr
= NULL
;
581 PyObject
*py_query_func
= NULL
;
582 PyObject
*py_object
= NULL
;
583 PyObject
*py_results_addr
= NULL
;
584 bt_component_class_query_method_status status
= __BT_FUNC_STATUS_OK
;
585 const bt_query_executor
*query_exec
=
586 bt_private_query_executor_as_query_executor_const(
587 priv_query_executor
);
588 bt_logging_level log_level
=
589 bt_query_executor_get_logging_level(query_exec
);
591 py_cls
= lookup_cc_ptr_to_py_cls(component_class
);
593 BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR
, log_level
, BT_LOG_TAG
,
594 "Cannot find Python class associated to native component class: "
595 "comp-cls-addr=%p", component_class
);
599 py_params_ptr
= SWIG_NewPointerObj(SWIG_as_voidptr(params
),
600 SWIGTYPE_p_bt_value
, 0);
601 if (!py_params_ptr
) {
602 BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR
, log_level
, BT_LOG_TAG
,
603 "Failed to create a SWIG pointer object.");
607 py_priv_query_exec_ptr
= SWIG_NewPointerObj(
608 SWIG_as_voidptr(priv_query_executor
),
609 SWIGTYPE_p_bt_private_query_executor
, 0);
610 if (!py_priv_query_exec_ptr
) {
611 BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR
, log_level
, BT_LOG_TAG
,
612 "Failed to create a SWIG pointer object.");
616 py_object
= SWIG_FromCharPtr(object
);
618 BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR
, log_level
, BT_LOG_TAG
,
619 "Failed to create a Python string.");
623 py_results_addr
= PyObject_CallMethod(py_cls
,
624 "_bt_query_from_native", "(OOO)", py_priv_query_exec_ptr
,
625 py_object
, py_params_ptr
);
626 if (!py_results_addr
) {
627 BT_LOG_WRITE_CUR_LVL(BT_LOG_WARNING
, log_level
, BT_LOG_TAG
,
628 "Failed to call Python class's _bt_query_from_native() method: "
629 "py-cls-addr=%p", py_cls
);
630 status
= py_exc_to_status_component_class(self_component_class
,
636 * The returned object, on success, is an integer object
637 * (PyLong) containing the address of a BT value object (new
640 *result
= PyLong_AsVoidPtr(py_results_addr
);
641 BT_ASSERT(!PyErr_Occurred());
647 status
= __BT_FUNC_STATUS_ERROR
;
650 Py_XDECREF(py_params_ptr
);
651 Py_XDECREF(py_priv_query_exec_ptr
);
652 Py_XDECREF(py_query_func
);
653 Py_XDECREF(py_object
);
654 Py_XDECREF(py_results_addr
);
659 bt_component_class_query_method_status
component_class_source_query(
660 bt_self_component_class_source
*self_component_class_source
,
661 bt_private_query_executor
*priv_query_executor
,
662 const char *object
, const bt_value
*params
,
663 const bt_value
**result
)
665 const bt_component_class_source
*component_class_source
= bt_self_component_class_source_as_component_class_source(self_component_class_source
);
666 const bt_component_class
*component_class
= bt_component_class_source_as_component_class_const(component_class_source
);
667 bt_self_component_class
*self_component_class
= bt_self_component_class_source_as_self_component_class(self_component_class_source
);
669 return component_class_query(component_class
, self_component_class
,
670 priv_query_executor
, object
, params
, result
);
674 bt_component_class_query_method_status
component_class_filter_query(
675 bt_self_component_class_filter
*self_component_class_filter
,
676 bt_private_query_executor
*priv_query_executor
,
677 const char *object
, const bt_value
*params
,
678 const bt_value
**result
)
680 const bt_component_class_filter
*component_class_filter
= bt_self_component_class_filter_as_component_class_filter(self_component_class_filter
);
681 const bt_component_class
*component_class
= bt_component_class_filter_as_component_class_const(component_class_filter
);
682 bt_self_component_class
*self_component_class
= bt_self_component_class_filter_as_self_component_class(self_component_class_filter
);
684 return component_class_query(component_class
, self_component_class
,
685 priv_query_executor
, object
, params
, result
);
689 bt_component_class_query_method_status
component_class_sink_query(
690 bt_self_component_class_sink
*self_component_class_sink
,
691 bt_private_query_executor
*priv_query_executor
,
692 const char *object
, const bt_value
*params
,
693 const bt_value
**result
)
695 const bt_component_class_sink
*component_class_sink
= bt_self_component_class_sink_as_component_class_sink(self_component_class_sink
);
696 const bt_component_class
*component_class
= bt_component_class_sink_as_component_class_const(component_class_sink
);
697 bt_self_component_class
*self_component_class
= bt_self_component_class_sink_as_self_component_class(self_component_class_sink
);
699 return component_class_query(component_class
, self_component_class
,
700 priv_query_executor
, object
, params
, result
);
704 bt_component_class_message_iterator_init_method_status
705 component_class_message_iterator_init(
706 bt_self_message_iterator
*self_message_iterator
,
707 bt_self_component
*self_component
,
708 bt_self_component_port_output
*self_component_port_output
)
710 bt_component_class_message_iterator_init_method_status status
= __BT_FUNC_STATUS_OK
;
711 PyObject
*py_comp_cls
= NULL
;
712 PyObject
*py_iter_cls
= NULL
;
713 PyObject
*py_iter_ptr
= NULL
;
714 PyObject
*py_component_port_output_ptr
= NULL
;
715 PyObject
*py_init_method_result
= NULL
;
716 PyObject
*py_iter
= NULL
;
718 bt_logging_level log_level
= get_self_component_log_level(
721 py_comp
= bt_self_component_get_data(self_component
);
723 /* Find user's Python message iterator class */
724 py_comp_cls
= PyObject_GetAttrString(py_comp
, "__class__");
726 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
727 "Cannot get Python object's `__class__` attribute.");
731 py_iter_cls
= PyObject_GetAttrString(py_comp_cls
, "_iter_cls");
733 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
734 "Cannot get Python class's `_iter_cls` attribute.");
738 py_iter_ptr
= SWIG_NewPointerObj(SWIG_as_voidptr(self_message_iterator
),
739 SWIGTYPE_p_bt_self_message_iterator
, 0);
741 const char *err
= "Failed to create a SWIG pointer object.";
743 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
745 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR(
746 self_message_iterator
, err
);
751 * Create object with borrowed native message iterator
754 * py_iter = py_iter_cls.__new__(py_iter_cls, py_iter_ptr)
756 py_iter
= PyObject_CallMethod(py_iter_cls
, "__new__",
757 "(OO)", py_iter_cls
, py_iter_ptr
);
759 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
760 "Failed to call Python class's __new__() method: "
761 "py-cls-addr=%p", py_iter_cls
);
768 * py_iter.__init__(self_output_port)
770 * through the _init_for_native helper static method.
772 * At this point, py_iter._ptr is set, so this initialization
773 * function has access to self._component (which gives it the
774 * user Python component object from which the iterator was
777 py_component_port_output_ptr
= SWIG_NewPointerObj(
778 SWIG_as_voidptr(self_component_port_output
),
779 SWIGTYPE_p_bt_self_component_port_output
, 0);
780 if (!py_component_port_output_ptr
) {
781 const char *err
= "Failed to create a SWIG pointer object.";
783 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
785 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_MESSAGE_ITERATOR(
786 self_message_iterator
, err
);
790 py_init_method_result
= PyObject_CallMethod(py_iter
,
791 "_bt_init_from_native", "O", py_component_port_output_ptr
);
792 if (!py_init_method_result
) {
793 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR
, log_level
, self_component
,
794 "User's __init__() method failed:");
799 * Since the Python code can never instantiate a user-defined
800 * message iterator class, the native message iterator
801 * object does NOT belong to a user Python message iterator
802 * object (borrowed reference). However this Python object is
803 * owned by this native message iterator object.
805 * In the Python world, the lifetime of the native message
806 * iterator is managed by a _GenericMessageIterator
809 * _GenericMessageIterator instance:
810 * owns a native bt_message_iterator object (iter)
811 * owns a _UserMessageIterator instance (py_iter)
812 * self._ptr is a borrowed reference to the
813 * native bt_private_connection_private_message_iterator
816 bt_self_message_iterator_set_data(self_message_iterator
, py_iter
);
821 /* Handling of errors that cause a Python exception to be set. */
822 status
= py_exc_to_status_message_iterator(self_message_iterator
);
823 BT_ASSERT(status
!= __BT_FUNC_STATUS_OK
);
827 /* Handling of errors that don't cause a Python exception to be set. */
828 status
= __BT_FUNC_STATUS_ERROR
;
831 BT_ASSERT(!PyErr_Occurred());
833 Py_XDECREF(py_comp_cls
);
834 Py_XDECREF(py_iter_cls
);
835 Py_XDECREF(py_iter_ptr
);
836 Py_XDECREF(py_component_port_output_ptr
);
837 Py_XDECREF(py_init_method_result
);
843 bt_component_class_message_iterator_init_method_status
844 component_class_source_message_iterator_init(
845 bt_self_message_iterator
*self_message_iterator
,
846 bt_self_component_source
*self_component_source
,
847 bt_self_component_port_output
*self_component_port_output
)
849 bt_self_component
*self_component
= bt_self_component_source_as_self_component(self_component_source
);
851 return component_class_message_iterator_init(self_message_iterator
, self_component
, self_component_port_output
);
855 bt_component_class_message_iterator_init_method_status
856 component_class_filter_message_iterator_init(
857 bt_self_message_iterator
*self_message_iterator
,
858 bt_self_component_filter
*self_component_filter
,
859 bt_self_component_port_output
*self_component_port_output
)
861 bt_self_component
*self_component
= bt_self_component_filter_as_self_component(self_component_filter
);
863 return component_class_message_iterator_init(self_message_iterator
, self_component
, self_component_port_output
);
867 void component_class_message_iterator_finalize(
868 bt_self_message_iterator
*message_iterator
)
870 PyObject
*py_message_iter
= bt_self_message_iterator_get_data(
872 PyObject
*py_method_result
= NULL
;
874 BT_ASSERT(py_message_iter
);
876 /* Call user's _user_finalize() method */
877 py_method_result
= PyObject_CallMethod(py_message_iter
,
878 "_user_finalize", NULL
);
880 if (PyErr_Occurred()) {
881 bt_self_component
*self_comp
=
882 bt_self_message_iterator_borrow_component(
884 bt_logging_level log_level
= get_self_component_log_level(
887 BT_COMP_LOG_CUR_LVL(BT_LOG_WARNING
, log_level
, self_comp
,
888 "User's _user_finalize() method raised an exception: ignoring:");
889 logw_exception(get_self_message_iterator_log_level(
894 * Ignore any exception raised by the _user_finalize() method
895 * because it won't change anything at this point: the component
896 * is being destroyed anyway.
899 Py_XDECREF(py_method_result
);
900 Py_DECREF(py_message_iter
);
903 /* Valid for both sources and filters. */
906 bt_component_class_message_iterator_next_method_status
907 component_class_message_iterator_next(
908 bt_self_message_iterator
*message_iterator
,
909 bt_message_array_const msgs
, uint64_t capacity
,
912 bt_component_class_message_iterator_next_method_status status
= __BT_FUNC_STATUS_OK
;
913 PyObject
*py_message_iter
= bt_self_message_iterator_get_data(message_iterator
);
914 PyObject
*py_method_result
= NULL
;
916 BT_ASSERT(py_message_iter
);
917 py_method_result
= PyObject_CallMethod(py_message_iter
,
918 "_bt_next_from_native", NULL
);
919 if (!py_method_result
) {
920 status
= py_exc_to_status_message_iterator(message_iterator
);
921 BT_ASSERT(status
!= __BT_FUNC_STATUS_OK
);
926 * The returned object, on success, is an integer object
927 * (PyLong) containing the address of a native message
928 * object (which is now ours).
930 msgs
[0] = PyLong_AsVoidPtr(py_method_result
);
933 /* Clear potential overflow error; should never happen */
934 BT_ASSERT(!PyErr_Occurred());
938 Py_XDECREF(py_method_result
);
943 bt_component_class_sink_consume_method_status
944 component_class_sink_consume(bt_self_component_sink
*self_component_sink
)
946 bt_self_component
*self_component
= bt_self_component_sink_as_self_component(self_component_sink
);
947 PyObject
*py_comp
= bt_self_component_get_data(self_component
);
948 PyObject
*py_method_result
= NULL
;
949 bt_component_class_sink_consume_method_status status
;
952 py_method_result
= PyObject_CallMethod(py_comp
,
953 "_user_consume", NULL
);
954 status
= py_exc_to_status_component(self_component
);
955 BT_ASSERT(py_method_result
|| status
!= __BT_FUNC_STATUS_OK
);
956 Py_XDECREF(py_method_result
);
961 int component_class_set_help_and_desc(
962 bt_component_class
*component_class
,
963 const char *description
, const char *help
)
968 ret
= bt_component_class_set_description(component_class
, description
);
970 BT_LOGE("Cannot set component class's description: "
971 "comp-cls-addr=%p", component_class
);
977 ret
= bt_component_class_set_help(component_class
, help
);
979 BT_LOGE("Cannot set component class's help text: "
980 "comp-cls-addr=%p", component_class
);
992 bt_component_class_source
*bt_bt2_component_class_source_create(
993 PyObject
*py_cls
, const char *name
, const char *description
,
996 bt_component_class_source
*component_class_source
;
997 bt_component_class
*component_class
;
1001 component_class_source
= bt_component_class_source_create(name
,
1002 component_class_message_iterator_next
);
1003 if (!component_class_source
) {
1004 BT_LOGE_STR("Cannot create source component class.");
1008 component_class
= bt_component_class_source_as_component_class(component_class_source
);
1010 if (component_class_set_help_and_desc(component_class
, description
, help
)) {
1014 ret
= bt_component_class_source_set_init_method(component_class_source
, component_class_source_init
);
1015 BT_ASSERT(ret
== 0);
1016 ret
= bt_component_class_source_set_finalize_method(component_class_source
, component_class_source_finalize
);
1017 BT_ASSERT(ret
== 0);
1018 ret
= bt_component_class_source_set_message_iterator_can_seek_beginning_method(component_class_source
,
1019 component_class_can_seek_beginning
);
1020 BT_ASSERT(ret
== 0);
1021 ret
= bt_component_class_source_set_message_iterator_seek_beginning_method(component_class_source
,
1022 component_class_seek_beginning
);
1023 BT_ASSERT(ret
== 0);
1024 ret
= bt_component_class_source_set_output_port_connected_method(component_class_source
,
1025 component_class_source_output_port_connected
);
1026 BT_ASSERT(ret
== 0);
1027 ret
= bt_component_class_source_set_query_method(component_class_source
, component_class_source_query
);
1028 BT_ASSERT(ret
== 0);
1029 ret
= bt_component_class_source_set_message_iterator_init_method(
1030 component_class_source
, component_class_source_message_iterator_init
);
1031 BT_ASSERT(ret
== 0);
1032 ret
= bt_component_class_source_set_message_iterator_finalize_method(
1033 component_class_source
, component_class_message_iterator_finalize
);
1034 BT_ASSERT(ret
== 0);
1035 register_cc_ptr_to_py_cls(component_class
, py_cls
);
1038 return component_class_source
;
1042 bt_component_class_filter
*bt_bt2_component_class_filter_create(
1043 PyObject
*py_cls
, const char *name
, const char *description
,
1046 bt_component_class
*component_class
;
1047 bt_component_class_filter
*component_class_filter
;
1051 component_class_filter
= bt_component_class_filter_create(name
,
1052 component_class_message_iterator_next
);
1053 if (!component_class_filter
) {
1054 BT_LOGE_STR("Cannot create filter component class.");
1058 component_class
= bt_component_class_filter_as_component_class(component_class_filter
);
1060 if (component_class_set_help_and_desc(component_class
, description
, help
)) {
1064 ret
= bt_component_class_filter_set_init_method(component_class_filter
, component_class_filter_init
);
1065 BT_ASSERT(ret
== 0);
1066 ret
= bt_component_class_filter_set_finalize_method (component_class_filter
, component_class_filter_finalize
);
1067 BT_ASSERT(ret
== 0);
1068 ret
= bt_component_class_filter_set_message_iterator_can_seek_beginning_method(component_class_filter
,
1069 component_class_can_seek_beginning
);
1070 BT_ASSERT(ret
== 0);
1071 ret
= bt_component_class_filter_set_message_iterator_seek_beginning_method(component_class_filter
,
1072 component_class_seek_beginning
);
1073 BT_ASSERT(ret
== 0);
1074 ret
= bt_component_class_filter_set_input_port_connected_method(component_class_filter
,
1075 component_class_filter_input_port_connected
);
1076 BT_ASSERT(ret
== 0);
1077 ret
= bt_component_class_filter_set_output_port_connected_method(component_class_filter
,
1078 component_class_filter_output_port_connected
);
1079 BT_ASSERT(ret
== 0);
1080 ret
= bt_component_class_filter_set_query_method(component_class_filter
, component_class_filter_query
);
1081 BT_ASSERT(ret
== 0);
1082 ret
= bt_component_class_filter_set_message_iterator_init_method(
1083 component_class_filter
, component_class_filter_message_iterator_init
);
1084 BT_ASSERT(ret
== 0);
1085 ret
= bt_component_class_filter_set_message_iterator_finalize_method(
1086 component_class_filter
, component_class_message_iterator_finalize
);
1087 BT_ASSERT(ret
== 0);
1088 register_cc_ptr_to_py_cls(component_class
, py_cls
);
1091 return component_class_filter
;
1095 bt_component_class_sink
*bt_bt2_component_class_sink_create(
1096 PyObject
*py_cls
, const char *name
, const char *description
,
1099 bt_component_class_sink
*component_class_sink
;
1100 bt_component_class
*component_class
;
1104 component_class_sink
= bt_component_class_sink_create(name
, component_class_sink_consume
);
1106 if (!component_class_sink
) {
1107 BT_LOGE_STR("Cannot create sink component class.");
1111 component_class
= bt_component_class_sink_as_component_class(component_class_sink
);
1113 if (component_class_set_help_and_desc(component_class
, description
, help
)) {
1117 ret
= bt_component_class_sink_set_init_method(component_class_sink
, component_class_sink_init
);
1118 BT_ASSERT(ret
== 0);
1119 ret
= bt_component_class_sink_set_finalize_method(component_class_sink
, component_class_sink_finalize
);
1120 BT_ASSERT(ret
== 0);
1121 ret
= bt_component_class_sink_set_input_port_connected_method(component_class_sink
,
1122 component_class_sink_input_port_connected
);
1123 BT_ASSERT(ret
== 0);
1124 ret
= bt_component_class_sink_set_graph_is_configured_method(component_class_sink
,
1125 component_class_sink_graph_is_configured
);
1126 BT_ASSERT(ret
== 0);
1127 ret
= bt_component_class_sink_set_query_method(component_class_sink
, component_class_sink_query
);
1128 BT_ASSERT(ret
== 0);
1129 register_cc_ptr_to_py_cls(component_class
, py_cls
);
1132 return component_class_sink
;