diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-07-12 08:42:37 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-07-12 08:42:41 +0900 |
commit | 87757999f26315ef84be29236bef8a1ba4e4af76 (patch) | |
tree | 716215f025890e99a84fe46b5431ee0399313ee5 /gi | |
parent | c20b00fa62305380031ec383e1d7f7c548cdfe44 (diff) | |
download | pygobject2-87757999f26315ef84be29236bef8a1ba4e4af76.tar.gz pygobject2-87757999f26315ef84be29236bef8a1ba4e4af76.tar.bz2 pygobject2-87757999f26315ef84be29236bef8a1ba4e4af76.zip |
Imported Upstream version 3.13.92
Change-Id: Ic195bab5260fd866ffc9d377f9efdcba5bffe014
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'gi')
-rw-r--r-- | gi/pygi-argument.c | 11 | ||||
-rw-r--r-- | gi/pygi-array.c | 1 | ||||
-rw-r--r-- | gi/pygi-boxed.c | 20 | ||||
-rw-r--r-- | gi/pygi-boxed.h | 2 | ||||
-rw-r--r-- | gi/pygi-marshal-cleanup.c | 13 | ||||
-rw-r--r-- | gi/pygi-signal-closure.c | 43 | ||||
-rw-r--r-- | gi/pygi-struct-marshal.c | 7 |
7 files changed, 81 insertions, 16 deletions
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c index 3d643fe..d63520d 100644 --- a/gi/pygi-argument.c +++ b/gi/pygi-argument.c @@ -1036,6 +1036,8 @@ array_success: { GType g_type; PyObject *py_type; + gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) && + (g_struct_info_is_foreign ((GIStructInfo *) info)); g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) info); @@ -1055,7 +1057,7 @@ array_success: py_type, transfer, FALSE, /*copy_reference*/ - g_struct_info_is_foreign (info), + is_foreign, g_type_info_is_pointer (type_info)); Py_DECREF (py_type); @@ -1382,6 +1384,8 @@ _pygi_argument_to_object (GIArgument *arg, { PyObject *py_type; GType g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); + gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) && + (g_struct_info_is_foreign ((GIStructInfo *) info)); /* Special case variant and none to force loading from py module. */ if (g_type == G_TYPE_VARIANT || g_type == G_TYPE_NONE) { @@ -1396,7 +1400,7 @@ _pygi_argument_to_object (GIArgument *arg, py_type, transfer, FALSE, /*is_allocated*/ - g_struct_info_is_foreign (info)); + is_foreign); Py_XDECREF (py_type); break; @@ -1703,7 +1707,8 @@ _pygi_argument_release (GIArgument *arg, if (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) { g_closure_unref (arg->v_pointer); } - } else if (g_struct_info_is_foreign ( (GIStructInfo*) info)) { + } else if (info_type == GI_INFO_TYPE_STRUCT && + g_struct_info_is_foreign ((GIStructInfo*) info)) { if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING) { pygi_struct_foreign_release (info, arg->v_pointer); } diff --git a/gi/pygi-array.c b/gi/pygi-array.c index 4cfbd17..e2598cd 100644 --- a/gi/pygi-array.c +++ b/gi/pygi-array.c @@ -803,6 +803,7 @@ pygi_arg_garray_len_arg_setup (PyGIArgCache *arg_cache, child_cache->direction = direction; child_cache->to_py_marshaller = _pygi_marshal_to_py_basic_type_cache_adapter; child_cache->from_py_marshaller = _pygi_marshal_from_py_basic_type_cache_adapter; + child_cache->py_arg_index = -1; /* ugly edge case code: * diff --git a/gi/pygi-boxed.c b/gi/pygi-boxed.c index a1494b6..d5faeb1 100644 --- a/gi/pygi-boxed.c +++ b/gi/pygi-boxed.c @@ -206,6 +206,26 @@ _pygi_boxed_get_free_on_dealloc(PyGIBoxed *self, void *closure) return PyBool_FromLong( ((PyGBoxed *)self)->free_on_dealloc ); } +/** + * _pygi_boxed_copy_in_place: + * + * Replace the boxed pointer held by this wrapper with a boxed copy + * freeing the previously held pointer (when free_on_dealloc is TRUE). + * This can be used in cases where Python is passed a reference which + * it does not own and the wrapper is held by the Python program + * longer than the duration of a callback it was passed to. + */ +void +_pygi_boxed_copy_in_place (PyGIBoxed *self) +{ + PyGBoxed *pygboxed = (PyGBoxed *)self; + gpointer copy = g_boxed_copy (pygboxed->gtype, pyg_boxed_get_ptr (self)); + + boxed_del (self); + pyg_boxed_set_ptr (pygboxed, copy); + pygboxed->free_on_dealloc = TRUE; +} + static PyGetSetDef pygi_boxed_getsets[] = { { "_free_on_dealloc", (getter)_pygi_boxed_get_free_on_dealloc, (setter)0 }, { NULL, 0, 0 } diff --git a/gi/pygi-boxed.h b/gi/pygi-boxed.h index 189a02c..c8f40b7 100644 --- a/gi/pygi-boxed.h +++ b/gi/pygi-boxed.h @@ -34,6 +34,8 @@ PyObject * _pygi_boxed_new (PyTypeObject *pytype, void * _pygi_boxed_alloc (GIBaseInfo *info, gsize *size); +void _pygi_boxed_copy_in_place (PyGIBoxed *self); + void _pygi_boxed_register_types (PyObject *m); G_END_DECLS diff --git a/gi/pygi-marshal-cleanup.c b/gi/pygi-marshal-cleanup.c index 4ba6159..b0ec05a 100644 --- a/gi/pygi-marshal-cleanup.c +++ b/gi/pygi-marshal-cleanup.c @@ -95,8 +95,6 @@ pygi_marshal_cleanup_args_from_py_marshal_success (PyGIInvokeState *state, for (i = 0; i < _pygi_callable_cache_args_len (cache); i++) { PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (cache, i); PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup; - PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args, - arg_cache->py_arg_index); gpointer cleanup_data = state->args_cleanup_data[i]; /* Only cleanup using args_cleanup_data when available. @@ -105,8 +103,9 @@ pygi_marshal_cleanup_args_from_py_marshal_success (PyGIInvokeState *state, * PyGIInvokeState.args_cleanup_data stores this data (via _invoke_marshal_in_args) * for the duration of the invoke up until this point. */ - if (cleanup_func && cleanup_data != NULL && + if (cleanup_func && cleanup_data != NULL && arg_cache->py_arg_index >= 0 && arg_cache->direction & PYGI_DIRECTION_FROM_PYTHON) { + PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args, arg_cache->py_arg_index); cleanup_func (state, arg_cache, py_arg, cleanup_data, TRUE); state->args_cleanup_data[i] = NULL; } @@ -167,8 +166,12 @@ pygi_marshal_cleanup_args_from_py_parameter_fail (PyGIInvokeState *state, PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (cache, i); PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup; gpointer cleanup_data = state->args_cleanup_data[i]; - PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args, - arg_cache->py_arg_index); + PyObject *py_arg = NULL; + + if (arg_cache->py_arg_index < 0) { + continue; + } + py_arg = PyTuple_GET_ITEM (state->py_in_args, arg_cache->py_arg_index); if (cleanup_func && cleanup_data != NULL && arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON) { diff --git a/gi/pygi-signal-closure.c b/gi/pygi-signal-closure.c index 3cf8486..652ac99 100644 --- a/gi/pygi-signal-closure.c +++ b/gi/pygi-signal-closure.c @@ -79,6 +79,8 @@ pygi_signal_closure_marshal(GClosure *closure, GISignalInfo *signal_info; gint n_sig_info_args; gint sig_info_highest_arg; + GSList *list_item = NULL; + GSList *pass_by_ref_structs = NULL; state = PyGILState_Ensure(); @@ -131,20 +133,28 @@ pygi_signal_closure_marshal(GClosure *closure, &free_array); } - /* Hack to ensure struct output args are passed-by-reference allowing + /* Hack to ensure struct arguments are passed-by-reference allowing * callback implementors to modify the struct values. This is needed * for keeping backwards compatibility and should be removed in future * versions which support signal output arguments as return values. * See: https://bugzilla.gnome.org/show_bug.cgi?id=735486 + * + * Note the logic here must match the logic path taken in _pygi_argument_to_object. */ - if (type_tag == GI_TYPE_TAG_INTERFACE && - g_arg_info_get_direction (&arg_info) == GI_DIRECTION_OUT) { + if (type_tag == GI_TYPE_TAG_INTERFACE) { GIBaseInfo *info = g_type_info_get_interface (&type_info); GIInfoType info_type = g_base_info_get_type (info); - if (info_type == GI_INFO_TYPE_STRUCT) { + if (info_type == GI_INFO_TYPE_STRUCT || + info_type == GI_INFO_TYPE_BOXED || + info_type == GI_INFO_TYPE_UNION) { + GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info); - if (g_type_is_a (gtype, G_TYPE_BOXED)) { + gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) && + (g_struct_info_is_foreign ((GIStructInfo *) info)); + + if (!is_foreign && !g_type_is_a (gtype, G_TYPE_VALUE) && + g_type_is_a (gtype, G_TYPE_BOXED)) { pass_struct_by_ref = TRUE; } } @@ -153,8 +163,12 @@ pygi_signal_closure_marshal(GClosure *closure, } if (pass_struct_by_ref) { + /* transfer everything will ensure the struct is not copied when wrapped. */ item = _pygi_argument_to_object (&arg, &type_info, GI_TRANSFER_EVERYTHING); - ((PyGBoxed *)item)->free_on_dealloc = FALSE; + if (item && PyObject_IsInstance (item, (PyObject *) &PyGIBoxed_Type)) { + ((PyGBoxed *)item)->free_on_dealloc = FALSE; + pass_by_ref_structs = g_slist_prepend (pass_by_ref_structs, item); + } } else { item = _pygi_argument_to_object (&arg, &type_info, GI_TRANSFER_NOTHING); @@ -196,7 +210,24 @@ pygi_signal_closure_marshal(GClosure *closure, } Py_DECREF(ret); + /* Run through the list of structs which have been passed by reference and + * check if they are being held longer than the duration of the callback + * execution. This is determined if the ref count is greater than 1. + * A single ref is held by the argument list and any more would mean the callback + * stored a ref somewhere else. In this case we make an internal copy of + * the boxed struct so Python can own the memory to it. + */ + list_item = pass_by_ref_structs; + while (list_item) { + PyObject *item = list_item->data; + if (item->ob_refcnt > 1) { + _pygi_boxed_copy_in_place ((PyGIBoxed *)item); + } + list_item = g_slist_next (list_item); + } + out: + g_slist_free (pass_by_ref_structs); Py_DECREF(params); PyGILState_Release(state); } diff --git a/gi/pygi-struct-marshal.c b/gi/pygi-struct-marshal.c index 5068064..9bf3b54 100644 --- a/gi/pygi-struct-marshal.c +++ b/gi/pygi-struct-marshal.c @@ -528,7 +528,6 @@ arg_struct_from_py_setup (PyGIArgCache *arg_cache, GITransfer transfer) { PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info); if (g_struct_info_is_gtype_struct ((GIStructInfo*)iface_info)) { arg_cache->from_py_marshaller = arg_type_class_from_py_marshal; @@ -560,7 +559,6 @@ arg_struct_to_py_setup (PyGIArgCache *arg_cache, GIArgInfo *arg_info) { PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info); /* HACK to force GtkTreeModel:iter_next() and iter_previous() vfunc implementations * to receive their Gtk.TreeIter argument as pass-by-reference. We create a new @@ -615,6 +613,7 @@ pygi_arg_struct_new_from_info (GITypeInfo *type_info, GIInterfaceInfo *iface_info) { PyGIArgCache *cache = NULL; + PyGIInterfaceCache *iface_cache; cache = pygi_arg_interface_new_from_info (type_info, arg_info, @@ -624,6 +623,10 @@ pygi_arg_struct_new_from_info (GITypeInfo *type_info, if (cache == NULL) return NULL; + iface_cache = (PyGIInterfaceCache *)cache; + iface_cache->is_foreign = (g_base_info_get_type ((GIBaseInfo *) iface_info) == GI_INFO_TYPE_STRUCT) && + (g_struct_info_is_foreign ((GIStructInfo*) iface_info)); + if (direction & PYGI_DIRECTION_FROM_PYTHON) { arg_struct_from_py_setup (cache, iface_info, transfer); } |