bt2: add support for comp. class help
[babeltrace.git] / bindings / python / bt2 / native_btcomponentclass.i
1 /*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
5 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
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
22 * THE SOFTWARE.
23 */
24
25 %{
26 #include <babeltrace/component/component-class.h>
27 #include <babeltrace/component/component-class-source.h>
28 #include <babeltrace/component/component-class-sink.h>
29 #include <babeltrace/component/component-class-filter.h>
30 #include <babeltrace/component/notification/iterator.h>
31 #include <babeltrace/component/notification/notification.h>
32 #include <assert.h>
33 #include <glib.h>
34 %}
35
36 /* Types */
37 struct bt_component_class;
38
39 /* Status */
40 enum bt_component_class_type {
41 BT_COMPONENT_CLASS_TYPE_UNKNOWN = -1,
42 BT_COMPONENT_CLASS_TYPE_SOURCE = 0,
43 BT_COMPONENT_CLASS_TYPE_SINK = 1,
44 BT_COMPONENT_CLASS_TYPE_FILTER = 2,
45 };
46
47 /* General functions */
48 const char *bt_component_class_get_name(
49 struct bt_component_class *component_class);
50 const char *bt_component_class_get_description(
51 struct bt_component_class *component_class);
52 const char *bt_component_class_get_help(
53 struct bt_component_class *component_class);
54 enum bt_component_class_type bt_component_class_get_type(
55 struct bt_component_class *component_class);
56
57 %{
58 /*
59 * This hash table associates a BT component class object address to a
60 * user-defined Python class (PyObject *). The keys and values are NOT
61 * owned by this hash table. The Python class objects are owned by the
62 * Python module, which should not be unloaded until it is not possible
63 * to create a user Python component anyway.
64 *
65 * This hash table is written to when a user-defined Python component
66 * class is created by one of the bt_py3_component_class_*_create()
67 * functions.
68 *
69 * This function is read from when a user calls bt_component_create()
70 * with a component class pointer created by one of the functions above.
71 * In this case, the original Python class needs to be found to
72 * instantiate it and associate the created Python component object with
73 * a BT component object instance.
74 */
75
76 static GHashTable *bt_cc_ptr_to_py_cls;
77
78 static void register_cc_ptr_to_py_cls(struct bt_component_class *bt_cc,
79 PyObject *py_cls)
80 {
81 g_hash_table_insert(bt_cc_ptr_to_py_cls, (gpointer) bt_cc,
82 (gpointer) py_cls);
83 }
84
85 static PyObject *lookup_cc_ptr_to_py_cls(struct bt_component_class *bt_cc)
86 {
87 return (PyObject *) g_hash_table_lookup(bt_cc_ptr_to_py_cls,
88 (gconstpointer) bt_cc);
89 }
90
91
92 /*
93 * Useful Python objects.
94 */
95
96 static PyObject *py_mod_bt2 = NULL;
97 static PyObject *py_mod_bt2_exc_error_type = NULL;
98 static PyObject *py_mod_bt2_exc_unsupported_feature_type = NULL;
99 static PyObject *py_mod_bt2_exc_try_again_type = NULL;
100 static PyObject *py_mod_bt2_exc_stop_type = NULL;
101 static PyObject *py_mod_bt2_values = NULL;
102 static PyObject *py_mod_bt2_values_create_from_ptr_func = NULL;
103
104 static void bt_py3_cc_init_from_bt2(void)
105 {
106 /*
107 * This is called once the bt2 package is loaded.
108 *
109 * Those modules and functions are needed while the package is
110 * used. Loading them here is safe because we know the bt2
111 * package is imported, and we know that the user cannot use the
112 * code here without importing bt2 first.
113 */
114 py_mod_bt2 = PyImport_ImportModule("bt2");
115 assert(py_mod_bt2);
116 py_mod_bt2_values = PyImport_ImportModule("bt2.values");
117 assert(py_mod_bt2_values);
118 py_mod_bt2_values_create_from_ptr_func =
119 PyObject_GetAttrString(py_mod_bt2_values,
120 "_create_from_ptr");
121 assert(py_mod_bt2_values_create_from_ptr_func);
122 py_mod_bt2_exc_error_type =
123 PyObject_GetAttrString(py_mod_bt2, "Error");
124 assert(py_mod_bt2_exc_error_type);
125 py_mod_bt2_exc_unsupported_feature_type =
126 PyObject_GetAttrString(py_mod_bt2, "UnsupportedFeature");
127 py_mod_bt2_exc_try_again_type =
128 PyObject_GetAttrString(py_mod_bt2, "TryAgain");
129 py_mod_bt2_exc_stop_type =
130 PyObject_GetAttrString(py_mod_bt2, "Stop");
131 assert(py_mod_bt2_exc_stop_type);
132 }
133
134 static void bt_py3_cc_exit_handler(void)
135 {
136 /*
137 * This is an exit handler (set by the bt2 package).
138 *
139 * We only give back the references that we took in
140 * bt_py3_cc_init_from_bt2() here. The global variables continue
141 * to exist for the code of this file, but they are now borrowed
142 * references. If this code is executed, it means that somehow
143 * to modules are still loaded, so it should be safe to use them
144 * even without a strong reference.
145 *
146 * We cannot do this in the library's destructor because it
147 * gets executed once Python is already finalized.
148 */
149 Py_XDECREF(py_mod_bt2_values_create_from_ptr_func);
150 Py_XDECREF(py_mod_bt2_values);
151 Py_XDECREF(py_mod_bt2);
152 Py_XDECREF(py_mod_bt2_exc_error_type);
153 Py_XDECREF(py_mod_bt2_exc_unsupported_feature_type);
154 Py_XDECREF(py_mod_bt2_exc_try_again_type);
155 Py_XDECREF(py_mod_bt2_exc_stop_type);
156 }
157
158
159 /* Library constructor and destructor */
160
161 __attribute__((constructor))
162 static void bt_py3_native_comp_class_ctor(void) {
163 /* Initialize component class association hash table */
164 bt_cc_ptr_to_py_cls = g_hash_table_new(g_direct_hash, g_direct_equal);
165 assert(bt_cc_ptr_to_py_cls);
166 }
167
168 __attribute__((destructor))
169 static void bt_py3_native_comp_class_dtor(void) {
170 /* Destroy component class association hash table */
171 if (bt_cc_ptr_to_py_cls) {
172 g_hash_table_destroy(bt_cc_ptr_to_py_cls);
173 }
174 }
175
176
177 /* Converts a BT value object to a bt2.values object */
178
179 static PyObject *bt_py3_bt_value_from_ptr(struct bt_value *value)
180 {
181 PyObject *py_create_from_ptr_func = NULL;
182 PyObject *py_value = NULL;
183 PyObject *py_ptr = NULL;
184
185 py_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(value),
186 SWIGTYPE_p_bt_value, 0);
187 py_value = PyObject_CallFunctionObjArgs(
188 py_mod_bt2_values_create_from_ptr_func, py_ptr, NULL);
189 if (!py_value) {
190 goto end;
191 }
192
193 /*
194 * _create_from_ptr() only wraps an existing reference. `value`
195 * is a borrowed reference here, so increment its reference
196 * count for this new owner.
197 */
198 bt_get(value);
199
200 end:
201 Py_XDECREF(py_ptr);
202 PyErr_Clear();
203 return py_value;
204 }
205
206
207 /* self.__init__(*args, **kwargs) */
208
209 static int bt_py3_call_self_init(PyObject *py_self, PyObject *py_args,
210 PyObject *py_kwargs)
211 {
212 int ret = 0;
213 size_t i;
214 PyObject *py_init_method_result = NULL;
215 PyObject *py_init_method = NULL;
216 PyObject *py_init_method_args = NULL;
217 PyObject *py_class = NULL;
218
219 py_class = PyObject_GetAttrString(py_self, "__class__");
220 if (!py_class) {
221 goto error;
222 }
223
224 py_init_method = PyObject_GetAttrString(py_class, "__init__");
225 if (!py_init_method) {
226 goto error;
227 }
228
229 /* Prepend py_self to the arguments (copy them to new tuple) */
230 py_init_method_args = PyTuple_New(PyTuple_Size(py_args) + 1);
231 if (!py_init_method_args) {
232 goto error;
233 }
234
235 Py_INCREF(py_self);
236 ret = PyTuple_SetItem(py_init_method_args, 0, py_self);
237 if (ret < 0) {
238 Py_DECREF(py_self);
239 goto error;
240 }
241
242 for (i = 0; i < PyTuple_Size(py_args); i++) {
243 PyObject *obj = PyTuple_GetItem(py_args, i);
244 if (!obj) {
245 goto error;
246 }
247
248 Py_INCREF(obj);
249 ret = PyTuple_SetItem(py_init_method_args, i + 1, obj);
250 if (ret < 0) {
251 Py_DECREF(obj);
252 goto error;
253 }
254 }
255
256 py_init_method_result = PyObject_Call(py_init_method,
257 py_init_method_args, py_kwargs);
258 if (!py_init_method_result) {
259 goto error;
260 }
261
262 goto end;
263
264 error:
265 ret = -1;
266
267 end:
268 Py_XDECREF(py_init_method_args);
269 Py_XDECREF(py_init_method_result);
270 Py_XDECREF(py_init_method);
271 Py_XDECREF(py_class);
272 return ret;
273 }
274
275
276 /* Component class proxy methods (delegate to the attached Python object) */
277
278 static enum bt_component_status bt_py3_cc_init(
279 struct bt_component *component, struct bt_value *params,
280 void *init_method_data)
281 {
282 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
283 int ret;
284
285 /*
286 * This function is either called from
287 * _UserComponentType.__call__() (when init_method_data contains
288 * the PyObject * currently creating this component) or from
289 * other code (init_method_data is NULL).
290 */
291 if (init_method_data) {
292 /*
293 * Called from _UserComponentType.__call__().
294 *
295 * The `params` argument is completely ignored here,
296 * because if the user creating the component object
297 * from the component class object wants parameters,
298 * they'll be in the keyword arguments anyway.
299 */
300 PyObject *py_comp = init_method_data;
301 PyObject *py_comp_ptr = NULL;
302 PyObject *py_init_args = NULL;
303 PyObject *py_init_kwargs = NULL;
304
305 /*
306 * No need to take a Python reference on py_comp here:
307 * we store it as a _borrowed_ reference. When all the
308 * Python references are dropped, the object's __del__()
309 * method is called. This method calls this side
310 * (bt_py3_component_on_del()) to swap the ownership:
311 * this BT component becomes the only owner of the
312 * Python object.
313 */
314 bt_component_set_private_data(component, py_comp);
315
316 /*
317 * Set this BT component pointer as py_comp._ptr, and
318 * take a reference on it (on success, at the end).
319 *
320 * This reference is put in the Python component
321 * object's __del__() method.
322 */
323 py_comp_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(component),
324 SWIGTYPE_p_bt_component, 0);
325 if (!py_comp_ptr) {
326 PyErr_Clear();
327 goto with_init_method_data_error;
328 }
329
330 ret = PyObject_SetAttrString(py_comp, "_ptr", py_comp_ptr);
331 if (ret < 0) {
332 PyErr_Clear();
333 goto with_init_method_data_error;
334 }
335
336 /*
337 * _UserComponentType.__call__() puts the arguments and
338 * keyword arguments to use for the py_comp.__init__()
339 * call in py_comp._init_args and py_comp._init_kwargs.
340 *
341 * We need to get them and remove them from py_comp before
342 * calling py_comp.__init__().
343 */
344 py_init_args = PyObject_GetAttrString(py_comp, "_init_args");
345 if (!py_init_args) {
346 PyErr_Clear();
347 goto with_init_method_data_error;
348 }
349
350 py_init_kwargs = PyObject_GetAttrString(py_comp, "_init_kwargs");
351 if (!py_init_kwargs) {
352 PyErr_Clear();
353 goto with_init_method_data_error;
354 }
355
356 ret = PyObject_DelAttrString(py_comp, "_init_args");
357 if (ret < 0) {
358 PyErr_Clear();
359 goto with_init_method_data_error;
360 }
361
362 ret = PyObject_DelAttrString(py_comp, "_init_kwargs");
363 if (ret < 0) {
364 PyErr_Clear();
365 goto with_init_method_data_error;
366 }
367
368 /* Ready to call py_comp.__init__() */
369 ret = bt_py3_call_self_init(py_comp, py_init_args,
370 py_init_kwargs);
371 if (ret) {
372 /*
373 * We do not clear any raised exception here
374 * so that the Python caller (the one who is
375 * instantiating the class) gets the exception
376 * from the __init__() method.
377 */
378 goto with_init_method_data_error;
379 }
380
381 /*
382 * py_comp.__init__() went well: get the native BT
383 * component object reference for the Python object.
384 */
385 bt_get(component);
386 goto with_init_method_data_end;
387
388 with_init_method_data_error:
389 status = BT_COMPONENT_STATUS_ERROR;
390
391 /*
392 * Reset py_comp._ptr to None to signal the error to
393 * _UserComponentType.__call__(). For exceptions raised
394 * from py_comp.__init__(), this is not important,
395 * because __call__() will also raise before even
396 * checking py_comp._ptr.
397 */
398 if (PyObject_HasAttrString(py_comp, "_ptr")) {
399 PyObject *py_err_type, *py_err_value, *py_err_traceback;
400 PyErr_Fetch(&py_err_type, &py_err_value,
401 &py_err_traceback);
402 Py_INCREF(Py_None);
403 PyObject_SetAttrString(py_comp, "_ptr", Py_None);
404 PyErr_Restore(py_err_type, py_err_value,
405 py_err_traceback);
406 }
407
408 /*
409 * Important: remove py_comp from our the BT component's
410 * private data. Since we're failing,
411 * bt_py3_cc_destroy() is about to be called: it must
412 * not consider py_comp. py_comp's __del__() method
413 * will be called (because the instance exists), but
414 * since py_comp._ptr is None, it won't do anything.
415 */
416 bt_component_set_private_data(component, NULL);
417
418 with_init_method_data_end:
419 Py_XDECREF(py_comp_ptr);
420 Py_XDECREF(py_init_args);
421 Py_XDECREF(py_init_kwargs);
422 } else {
423 /*
424 * Not called from _UserComponentType.__call__().
425 *
426 * In this case we need to instantiate the user-defined
427 * Python class. To do this we call the user-defined
428 * class manually with this already-created BT component
429 * object pointer as the __comp_ptr keyword argument.
430 *
431 * We keep a reference, the only existing one, to the
432 * created Python object. bt_py3_component_on_del() will
433 * never be called by the object's __del__() method
434 * because _UserComponentType.__call__() marks the
435 * object as owned by the native BT component object.
436 */
437 PyObject *py_cls = NULL;
438 PyObject *py_comp = NULL;
439 PyObject *py_params = NULL;
440 PyObject *py_comp_ptr = NULL;
441 PyObject *py_cls_ctor_args = NULL;
442 PyObject *py_cls_ctor_kwargs = NULL;
443
444 /*
445 * Get the user-defined Python class which created this
446 * component's class in the first place (borrowed
447 * reference).
448 */
449 py_cls = lookup_cc_ptr_to_py_cls(bt_component_get_class(component));
450 if (!py_cls) {
451 goto without_init_method_data_error;
452 }
453
454 /* BT value object -> Python bt2.values object */
455 py_params = bt_py3_bt_value_from_ptr(params);
456 if (!py_params) {
457 goto without_init_method_data_error;
458 }
459
460 /* Component pointer -> SWIG pointer Python object */
461 py_comp_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(component),
462 SWIGTYPE_p_bt_component, 0);
463 if (!py_comp_ptr) {
464 goto without_init_method_data_error;
465 }
466
467 /*
468 * Do the equivalent of this:
469 *
470 * py_comp = py_cls(__comp_ptr=py_comp_ptr, params=py_params)
471 *
472 * _UserComponentType.__call__() calls the Python
473 * component object's __init__() function itself in this
474 * case.
475 */
476 py_cls_ctor_args = PyTuple_New(0);
477 if (!py_cls_ctor_args) {
478 goto without_init_method_data_error;
479 }
480
481 py_cls_ctor_kwargs = PyDict_New();
482 if (!py_cls_ctor_kwargs) {
483 goto without_init_method_data_error;
484 }
485
486 ret = PyDict_SetItemString(py_cls_ctor_kwargs, "__comp_ptr",
487 py_comp_ptr);
488 if (ret < 0) {
489 goto without_init_method_data_error;
490 }
491
492 ret = PyDict_SetItemString(py_cls_ctor_kwargs, "params",
493 py_params);
494 if (ret < 0) {
495 goto without_init_method_data_error;
496 }
497
498 py_comp = PyObject_Call(py_cls, py_cls_ctor_args,
499 py_cls_ctor_kwargs);
500 if (!py_comp) {
501 goto without_init_method_data_error;
502 }
503
504 /*
505 * Our user Python component object is now fully created
506 * and initialized by the user. Since we just created
507 * it, this BT component is its only (persistent) owner.
508 */
509 bt_component_set_private_data(component, py_comp);
510 py_comp = NULL;
511 goto without_init_method_data_end;
512
513 without_init_method_data_error:
514 status = BT_COMPONENT_STATUS_ERROR;
515
516 /*
517 * Clear any exception: we're returning a bad status
518 * anyway. If this call originated from Python (creation
519 * from a plugin's component class, for example), then
520 * the user gets an appropriate creation error.
521 */
522 PyErr_Clear();
523
524 without_init_method_data_end:
525 Py_XDECREF(py_comp);
526 Py_XDECREF(py_params);
527 Py_XDECREF(py_comp_ptr);
528 Py_XDECREF(py_cls_ctor_args);
529 Py_XDECREF(py_cls_ctor_kwargs);
530 }
531
532 return status;
533 }
534
535 static void bt_py3_cc_destroy(struct bt_component *component)
536 {
537 PyObject *py_comp = bt_component_get_private_data(component);
538 PyObject *py_destroy_method_result = NULL;
539
540 if (py_comp) {
541 /*
542 * If we're here, this BT component is the only owner of
543 * its private user Python object. It is safe to
544 * decrement its reference count, and thus destroy it.
545 *
546 * We call its _destroy() method before doing so to notify
547 * the Python user.
548 */
549 py_destroy_method_result = PyObject_CallMethod(py_comp,
550 "_destroy", NULL);
551
552 /*
553 * Ignore any exception raised by the _destroy() method
554 * because it won't change anything at this point: the
555 * component is being destroyed anyway.
556 */
557 PyErr_Clear();
558 Py_XDECREF(py_destroy_method_result);
559 Py_DECREF(py_comp);
560 }
561 }
562
563 static enum bt_notification_iterator_status bt_py3_exc_to_notif_iter_status(void)
564 {
565 enum bt_notification_iterator_status status =
566 BT_NOTIFICATION_ITERATOR_STATUS_OK;
567 PyObject *exc = PyErr_Occurred();
568
569 if (!exc) {
570 goto end;
571 }
572
573 if (PyErr_GivenExceptionMatches(exc,
574 py_mod_bt2_exc_unsupported_feature_type)) {
575 status = BT_NOTIFICATION_ITERATOR_STATUS_UNSUPPORTED;
576 } else if (PyErr_GivenExceptionMatches(exc,
577 py_mod_bt2_exc_stop_type)) {
578 status = BT_NOTIFICATION_ITERATOR_STATUS_END;
579 } else {
580 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
581 }
582
583 end:
584 PyErr_Clear();
585 return status;
586 }
587
588 static enum bt_notification_iterator_status bt_py3_cc_notification_iterator_init(
589 struct bt_component *component,
590 struct bt_notification_iterator *iter, void *init_method_data)
591 {
592 enum bt_notification_iterator_status status =
593 BT_NOTIFICATION_ITERATOR_STATUS_OK;
594 PyObject *py_comp_cls = NULL;
595 PyObject *py_iter_cls = NULL;
596 PyObject *py_iter_ptr = NULL;
597 PyObject *py_init_method_result = NULL;
598 PyObject *py_iter = NULL;
599 PyObject *py_comp = bt_component_get_private_data(component);
600
601 /* Find user's Python notification iterator class */
602 py_comp_cls = PyObject_GetAttrString(py_comp, "__class__");
603 if (!py_comp_cls) {
604 goto error;
605 }
606
607 py_iter_cls = PyObject_GetAttrString(py_comp_cls, "_iter_cls");
608 if (!py_iter_cls) {
609 goto error;
610 }
611
612 /*
613 * Create object with borrowed BT notification iterator
614 * reference:
615 *
616 * py_iter = py_iter_cls.__new__(py_iter_cls, py_iter_ptr)
617 */
618 py_iter_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(iter),
619 SWIGTYPE_p_bt_notification_iterator, 0);
620 if (!py_iter_ptr) {
621 goto error;
622 }
623
624 py_iter = PyObject_CallMethod(py_iter_cls, "__new__",
625 "(OO)", py_iter_cls, py_iter_ptr);
626 if (!py_iter) {
627 goto error;
628 }
629
630 /*
631 * Initialize object:
632 *
633 * py_iter.__init__()
634 *
635 * At this point, py_iter._ptr is set, so this initialization
636 * function has access to the py_iter.component property (which
637 * gives it the user Python component object from which the
638 * iterator was created).
639 */
640 py_init_method_result = PyObject_CallMethod(py_iter, "__init__", NULL);
641 if (!py_init_method_result) {
642 goto error;
643 }
644
645 /*
646 * Since the Python code can never instantiate a user-defined
647 * notification iterator class, the BT notification iterator
648 * object does NOT belong to a user Python notification iterator
649 * object (borrowed reference). However this Python object is
650 * owned by this BT notification iterator object.
651 *
652 * In the Python world, the lifetime of the BT notification
653 * iterator is managed by a _GenericNotificationIterator
654 * instance:
655 *
656 * _GenericNotificationIterator instance:
657 * owns a native bt_notification_iterator object (iter)
658 * owns a UserNotificationIterator instance (py_iter)
659 * self._ptr is a borrowed reference to the
660 * native bt_notification_iterator object (iter)
661 */
662 bt_notification_iterator_set_private_data(iter, py_iter);
663 py_iter = NULL;
664 goto end;
665
666 error:
667 status = bt_py3_exc_to_notif_iter_status();
668 if (status == BT_NOTIFICATION_ITERATOR_STATUS_OK) {
669 /*
670 * Looks like there wasn't any exception from the Python
671 * side, but we're still in an error state here.
672 */
673 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
674 }
675
676 /*
677 * Clear any exception: we're returning a bad status anyway. If
678 * this call originated from Python, then the user gets an
679 * appropriate creation error.
680 */
681 PyErr_Clear();
682
683 end:
684 Py_XDECREF(py_comp_cls);
685 Py_XDECREF(py_iter_cls);
686 Py_XDECREF(py_iter_ptr);
687 Py_XDECREF(py_init_method_result);
688 Py_XDECREF(py_iter);
689 return status;
690 }
691
692 static void bt_py3_cc_notification_iterator_destroy(
693 struct bt_notification_iterator *iter)
694 {
695 PyObject *py_notif_iter =
696 bt_notification_iterator_get_private_data(iter);
697 PyObject *py_destroy_method_result = NULL;
698
699 assert(py_notif_iter);
700 py_destroy_method_result = PyObject_CallMethod(py_notif_iter,
701 "_destroy", NULL);
702
703 /*
704 * Ignore any exception raised by the _destroy() method because
705 * it won't change anything at this point. The notification
706 * iterator is being destroyed anyway.
707 */
708 PyErr_Clear();
709 Py_XDECREF(py_destroy_method_result);
710 Py_DECREF(py_notif_iter);
711 }
712
713 static struct bt_notification *bt_py3_cc_notification_iterator_get(
714 struct bt_notification_iterator *iter)
715 {
716 PyObject *py_notif_iter =
717 bt_notification_iterator_get_private_data(iter);
718 PyObject *py_get_method_result = NULL;
719 struct bt_notification *notif = NULL;
720
721 assert(py_notif_iter);
722 py_get_method_result = PyObject_CallMethod(py_notif_iter,
723 "_get_from_bt", NULL);
724 if (!py_get_method_result) {
725 goto error;
726 }
727
728 /*
729 * The returned object, on success, is an integer object
730 * (PyLong) containing the address of a BT notification
731 * object (which is not ours).
732 */
733 notif = (struct bt_notification *) PyLong_AsUnsignedLongLong(
734 py_get_method_result);
735
736 /* Clear potential overflow error; should never happen */
737 if (PyErr_Occurred()) {
738 goto error;
739 }
740
741 if (!notif) {
742 goto error;
743 }
744
745 goto end;
746
747 error:
748 BT_PUT(notif);
749
750 /*
751 * Clear any exception: we're returning NULL anyway. If this
752 * call originated from Python, then the user gets an
753 * appropriate error.
754 */
755 PyErr_Clear();
756
757 end:
758 Py_XDECREF(py_get_method_result);
759 return notif;
760 }
761
762 static enum bt_notification_iterator_status bt_py3_cc_notification_iterator_next(
763 struct bt_notification_iterator *iter)
764 {
765 enum bt_notification_iterator_status status;
766 PyObject *py_notif_iter =
767 bt_notification_iterator_get_private_data(iter);
768 PyObject *py_next_method_result = NULL;
769
770 assert(py_notif_iter);
771 py_next_method_result = PyObject_CallMethod(py_notif_iter,
772 "_next", NULL);
773 status = bt_py3_exc_to_notif_iter_status();
774 if (!py_next_method_result
775 && status == BT_NOTIFICATION_ITERATOR_STATUS_OK) {
776 /* Pretty sure this should never happen, but just in case */
777 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
778 }
779
780 Py_XDECREF(py_next_method_result);
781 return status;
782 }
783
784 static enum bt_notification_iterator_status bt_py3_cc_notification_iterator_seek_time(
785 struct bt_notification_iterator *iter, int64_t time)
786 {
787 enum bt_notification_iterator_status status;
788 PyObject *py_notif_iter =
789 bt_notification_iterator_get_private_data(iter);
790 PyObject *py_seek_to_time_method_result = NULL;
791
792 assert(py_notif_iter);
793 py_seek_to_time_method_result = PyObject_CallMethod(py_notif_iter,
794 "_seek_to_time", "(L)", time);
795 status = bt_py3_exc_to_notif_iter_status();
796 if (!py_seek_to_time_method_result
797 && status == BT_NOTIFICATION_ITERATOR_STATUS_OK) {
798 /* Pretty sure this should never happen, but just in case */
799 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
800 }
801
802 Py_XDECREF(py_seek_to_time_method_result);
803 return status;
804 }
805
806 static enum bt_component_status bt_py3_exc_to_component_status(void)
807 {
808 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
809 PyObject *exc = PyErr_Occurred();
810
811 if (!exc) {
812 goto end;
813 }
814
815 if (PyErr_GivenExceptionMatches(exc,
816 py_mod_bt2_exc_unsupported_feature_type)) {
817 status = BT_COMPONENT_STATUS_UNSUPPORTED;
818 } else if (PyErr_GivenExceptionMatches(exc,
819 py_mod_bt2_exc_try_again_type)) {
820 status = BT_COMPONENT_STATUS_AGAIN;
821 } else if (PyErr_GivenExceptionMatches(exc,
822 py_mod_bt2_exc_stop_type)) {
823 status = BT_COMPONENT_STATUS_END;
824 } else {
825 status = BT_COMPONENT_STATUS_ERROR;
826 }
827
828 end:
829 PyErr_Clear();
830 return status;
831 }
832
833 static enum bt_component_status bt_py3_cc_sink_consume(
834 struct bt_component *component)
835 {
836 PyObject *py_comp = bt_component_get_private_data(component);
837 PyObject *py_consume_method_result = NULL;
838 enum bt_component_status status;
839
840 py_consume_method_result = PyObject_CallMethod(py_comp,
841 "_consume", NULL);
842 status = bt_py3_exc_to_component_status();
843 if (!py_consume_method_result && status == BT_COMPONENT_STATUS_OK) {
844 /* Pretty sure this should never happen, but just in case */
845 status = BT_COMPONENT_STATUS_ERROR;
846 }
847
848 Py_XDECREF(py_consume_method_result);
849 return status;
850 }
851
852 static enum bt_component_status bt_py3_cc_sink_filter_add_iterator(
853 struct bt_component *component,
854 struct bt_notification_iterator *iter)
855 {
856 PyObject *py_comp = bt_component_get_private_data(component);
857 PyObject *py_add_iterator_method_result = NULL;
858 PyObject *py_notif_iter_ptr = NULL;
859 enum bt_component_status status;
860
861 py_notif_iter_ptr = SWIG_NewPointerObj(SWIG_as_voidptr(iter),
862 SWIGTYPE_p_bt_notification_iterator, 0);
863 if (!py_notif_iter_ptr) {
864 PyErr_Clear();
865 status = BT_COMPONENT_STATUS_ERROR;
866 goto end;
867 }
868
869 bt_get(iter);
870 py_add_iterator_method_result = PyObject_CallMethod(py_comp,
871 "_add_iterator_from_bt", "(O)", py_notif_iter_ptr);
872 status = bt_py3_exc_to_component_status();
873 if (!py_add_iterator_method_result
874 && status == BT_COMPONENT_STATUS_OK) {
875 /* Pretty sure this should never happen, but just in case */
876 status = BT_COMPONENT_STATUS_ERROR;
877 }
878
879 end:
880 Py_XDECREF(py_notif_iter_ptr);
881 Py_XDECREF(py_add_iterator_method_result);
882 return status;
883 }
884
885
886 /* Component class creation functions (called from Python module) */
887
888 static int bt_py3_cc_set_optional_attrs_methods(struct bt_component_class *cc,
889 const char *description, const char *help)
890 {
891 int ret = 0;
892
893 if (description) {
894 ret = bt_component_class_set_description(cc, description);
895 if (ret) {
896 goto end;
897 }
898 }
899
900 if (help) {
901 ret = bt_component_class_set_help(cc, help);
902 if (ret) {
903 goto end;
904 }
905 }
906
907 ret = bt_component_class_set_init_method(cc, bt_py3_cc_init);
908 if (ret) {
909 goto end;
910 }
911
912 ret = bt_component_class_set_destroy_method(cc, bt_py3_cc_destroy);
913 if (ret) {
914 goto end;
915 }
916
917 end:
918 return ret;
919 }
920
921 static int bt_py3_cc_set_optional_iter_methods(struct bt_component_class *cc,
922 bool has_seek_time,
923 int (*set_notif_iter_init_method)(struct bt_component_class *, bt_component_class_notification_iterator_init_method),
924 int (*set_notif_iter_destroy_method)(struct bt_component_class *, bt_component_class_notification_iterator_destroy_method),
925 int (*set_notif_iter_seek_time_method)(struct bt_component_class *, bt_component_class_notification_iterator_seek_time_method))
926 {
927 int ret;
928
929 ret = set_notif_iter_init_method(
930 cc, bt_py3_cc_notification_iterator_init);
931 if (ret) {
932 goto end;
933 }
934
935 ret = set_notif_iter_destroy_method(
936 cc, bt_py3_cc_notification_iterator_destroy);
937 if (ret) {
938 goto end;
939 }
940
941 if (has_seek_time) {
942 ret = set_notif_iter_seek_time_method(
943 cc, bt_py3_cc_notification_iterator_seek_time);
944 if (ret) {
945 goto end;
946 }
947 }
948
949 end:
950 return ret;
951 }
952
953 static struct bt_component_class *bt_py3_component_class_source_create(
954 PyObject *py_cls, const char *name, const char *description,
955 const char *help, bool has_seek_time)
956 {
957 struct bt_component_class *cc;
958 int ret;
959
960 assert(py_cls);
961 cc = bt_component_class_source_create(name,
962 bt_py3_cc_notification_iterator_get,
963 bt_py3_cc_notification_iterator_next);
964 if (!cc) {
965 goto end;
966 }
967
968 ret = bt_py3_cc_set_optional_attrs_methods(cc, description, help);
969 if (ret) {
970 BT_PUT(cc);
971 goto end;
972 }
973
974 ret = bt_py3_cc_set_optional_iter_methods(cc, has_seek_time,
975 bt_component_class_source_set_notification_iterator_init_method,
976 bt_component_class_source_set_notification_iterator_destroy_method,
977 bt_component_class_source_set_notification_iterator_seek_time_method);
978 if (ret) {
979 BT_PUT(cc);
980 goto end;
981 }
982
983 register_cc_ptr_to_py_cls(cc, py_cls);
984 bt_component_class_freeze(cc);
985
986 end:
987 return cc;
988 }
989
990 static struct bt_component_class *bt_py3_component_class_filter_create(
991 PyObject *py_cls, const char *name, const char *description,
992 const char *help, bool has_seek_time)
993 {
994 struct bt_component_class *cc;
995 int ret;
996
997 assert(py_cls);
998 cc = bt_component_class_filter_create(name,
999 bt_py3_cc_notification_iterator_get,
1000 bt_py3_cc_notification_iterator_next);
1001 if (!cc) {
1002 goto end;
1003 }
1004
1005 ret = bt_py3_cc_set_optional_attrs_methods(cc, description, help);
1006 if (ret) {
1007 BT_PUT(cc);
1008 goto end;
1009 }
1010
1011 ret = bt_py3_cc_set_optional_iter_methods(cc, has_seek_time,
1012 bt_component_class_filter_set_notification_iterator_init_method,
1013 bt_component_class_filter_set_notification_iterator_destroy_method,
1014 bt_component_class_filter_set_notification_iterator_seek_time_method);
1015 if (ret) {
1016 BT_PUT(cc);
1017 goto end;
1018 }
1019
1020 ret = bt_component_class_filter_set_add_iterator_method(cc,
1021 bt_py3_cc_sink_filter_add_iterator);
1022 if (ret) {
1023 BT_PUT(cc);
1024 goto end;
1025 }
1026
1027 register_cc_ptr_to_py_cls(cc, py_cls);
1028 bt_component_class_freeze(cc);
1029
1030 end:
1031 return cc;
1032 }
1033
1034 static struct bt_component_class *bt_py3_component_class_sink_create(
1035 PyObject *py_cls, const char *name, const char *description,
1036 const char *help)
1037 {
1038 struct bt_component_class *cc;
1039 int ret;
1040
1041 assert(py_cls);
1042 cc = bt_component_class_sink_create(name, bt_py3_cc_sink_consume);
1043 if (!cc) {
1044 goto end;
1045 }
1046
1047 ret = bt_py3_cc_set_optional_attrs_methods(cc, description, help);
1048 if (ret) {
1049 BT_PUT(cc);
1050 goto end;
1051 }
1052
1053 ret = bt_component_class_sink_set_add_iterator_method(cc,
1054 bt_py3_cc_sink_filter_add_iterator);
1055 if (ret) {
1056 BT_PUT(cc);
1057 goto end;
1058 }
1059
1060 register_cc_ptr_to_py_cls(cc, py_cls);
1061 bt_component_class_freeze(cc);
1062
1063 end:
1064 return cc;
1065 }
1066
1067
1068 /* Component creation function (called from Python module) */
1069
1070 static void bt_py3_component_create(
1071 struct bt_component_class *comp_class, PyObject *py_self,
1072 const char *name)
1073 {
1074 struct bt_component *component =
1075 bt_component_create_with_init_method_data(comp_class,
1076 name, NULL, py_self);
1077
1078 /*
1079 * Our component initialization function, bt_py3_cc_init(), sets
1080 * a new reference to the created component in the user's Python
1081 * object (py_self._ptr). This is where the reference is kept.
1082 * We don't need the returned component in this case (if any,
1083 * because it might be NULL if the creation failed, most
1084 * probably because py_self.__init__() raised something).
1085 */
1086 bt_put(component);
1087 }
1088
1089
1090 /* Component delete notification */
1091
1092 static void bt_py3_component_on_del(PyObject *py_comp)
1093 {
1094 /*
1095 * The Python component's __del__() function calls this to
1096 * indicate that there's no more reference on it from the
1097 * Python world.
1098 *
1099 * Since the BT component can continue to live once the Python
1100 * component object is deleted, we increment the Python
1101 * component's reference count so that it now only belong to the
1102 * BT component. We will decrement this reference count once
1103 * the BT component is destroyed in bt_py3_cc_destroy().
1104 */
1105 assert(py_comp);
1106 Py_INCREF(py_comp);
1107 }
1108 %}
1109
1110 %exception bt_py3_component_create {
1111 $action
1112 if (PyErr_Occurred()) {
1113 /* Exception is already set by bt_py3_component_create() */
1114 SWIG_fail;
1115 }
1116 }
1117
1118 struct bt_component_class *bt_py3_component_class_source_create(
1119 PyObject *py_cls, const char *name, const char *description,
1120 const char *help, bool has_seek_time);
1121 struct bt_component_class *bt_py3_component_class_filter_create(
1122 PyObject *py_cls, const char *name, const char *description,
1123 const char *help, bool has_seek_time);
1124 struct bt_component_class *bt_py3_component_class_sink_create(
1125 PyObject *py_cls, const char *name, const char *description,
1126 const char *help);
1127 void bt_py3_component_create(
1128 struct bt_component_class *comp_class, PyObject *py_self,
1129 const char *name);
1130 void bt_py3_component_on_del(PyObject *py_comp);
1131 void bt_py3_cc_init_from_bt2(void);
1132 void bt_py3_cc_exit_handler(void);
This page took 0.057425 seconds and 5 git commands to generate.