1 /* -*- Mode: C; c-basic-offset: 4 -*-
2 * vim: tabstop=4 shiftwidth=4 expandtab
4 * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22 #include "pygi-marshal-cleanup.h"
25 _cleanup_caller_allocates (PyGIInvokeState *state,
29 PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)cache;
31 if (iface_cache->g_type == G_TYPE_BOXED) {
33 size = g_struct_info_get_size (iface_cache->interface_info);
34 g_slice_free1 (size, data);
35 } else if (iface_cache->g_type == G_TYPE_VALUE) {
36 g_slice_free (GValue, data);
37 } else if (iface_cache->is_foreign) {
38 pygi_struct_foreign_release ((GIBaseInfo *)iface_cache->interface_info,
46 * Cleanup during invoke can happen in multiple
47 * stages, each of which can be the result of a
48 * successful compleation of that stage or an error
49 * occured which requires partial cleanup.
51 * For the most part, either the C interface being
52 * invoked or the python object which wraps the
53 * parameters, handle their lifecycles but in some
54 * cases, where we have intermediate objects,
55 * or when we fail processing a parameter, we need
56 * to handle the clean up manually.
58 * There are two argument processing stages.
59 * They are the in stage, where we process python
60 * parameters into their C counterparts, and the out
61 * stage, where we process out C parameters back
62 * into python objects. The in stage also sets up
63 * temporary out structures for caller allocated
64 * parameters which need to be cleaned up either on
65 * in stage failure or at the completion of the out
66 * stage (either success or failure)
68 * The in stage must call one of these cleanup functions:
69 * - pygi_marshal_cleanup_args_from_py_marshal_success
70 * (continue to out stage)
71 * - pygi_marshal_cleanup_args_from_py_parameter_fail
72 * (final, exit from invoke)
74 * The out stage must call one of these cleanup functions which are all final:
75 * - pygi_marshal_cleanup_args_to_py_marshal_success
76 * - pygi_marshal_cleanup_args_return_fail
77 * - pygi_marshal_cleanup_args_to_py_parameter_fail
81 pygi_marshal_cleanup_args_from_py_marshal_success (PyGIInvokeState *state,
82 PyGICallableCache *cache)
86 /* For in success, call cleanup for all GI_DIRECTION_IN values only. */
87 for (i = 0; i < cache->n_args; i++) {
88 PyGIArgCache *arg_cache = cache->args_cache[i];
89 PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup;
92 arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON &&
93 state->args[i]->v_pointer != NULL)
94 cleanup_func (state, arg_cache, state->args[i]->v_pointer, TRUE);
99 pygi_marshal_cleanup_args_to_py_marshal_success (PyGIInvokeState *state,
100 PyGICallableCache *cache)
102 /* clean up the return if available */
103 if (cache->return_cache != NULL) {
104 PyGIMarshalCleanupFunc cleanup_func = cache->return_cache->to_py_cleanup;
105 if (cleanup_func && state->return_arg.v_pointer != NULL)
108 state->return_arg.v_pointer,
112 /* Now clean up args */
113 GSList *cache_item = cache->to_py_args;
115 PyGIArgCache *arg_cache = (PyGIArgCache *) cache_item->data;
116 PyGIMarshalCleanupFunc cleanup_func = arg_cache->to_py_cleanup;
117 gpointer data = state->args[arg_cache->c_arg_index]->v_pointer;
119 if (cleanup_func != NULL && data != NULL)
125 cache_item = cache_item->next;
130 pygi_marshal_cleanup_args_from_py_parameter_fail (PyGIInvokeState *state,
131 PyGICallableCache *cache,
132 gssize failed_arg_index)
136 state->failed = TRUE;
138 for (i = 0; i < cache->n_args && i <= failed_arg_index; i++) {
139 PyGIArgCache *arg_cache = cache->args_cache[i];
140 PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup;
141 gpointer data = state->args[i]->v_pointer;
144 arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON &&
149 i < failed_arg_index);
151 } else if (arg_cache->is_caller_allocates && data != NULL) {
152 _cleanup_caller_allocates (state,
160 pygi_marshal_cleanup_args_return_fail (PyGIInvokeState *state,
161 PyGICallableCache *cache)
163 state->failed = TRUE;
167 pygi_marshal_cleanup_args_to_py_parameter_fail (PyGIInvokeState *state,
168 PyGICallableCache *cache,
169 gssize failed_to_py_arg_index)
171 state->failed = TRUE;
175 _pygi_marshal_cleanup_from_py_utf8 (PyGIInvokeState *state,
176 PyGIArgCache *arg_cache,
178 gboolean was_processed)
180 /* We strdup strings so always free if we have processed this
181 parameter for input */
187 _pygi_marshal_cleanup_to_py_utf8 (PyGIInvokeState *state,
188 PyGIArgCache *arg_cache,
190 gboolean was_processed)
192 /* Python copies the string so we need to free it
193 if the interface is transfering ownership,
194 whether or not it has been processed yet */
195 if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
200 _pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state,
201 PyGIArgCache *arg_cache,
203 gboolean was_processed)
205 /* If we processed the parameter but fail before invoking the method,
206 we need to remove the ref we added */
207 if (was_processed && state->failed && data != NULL &&
208 arg_cache->transfer == GI_TRANSFER_EVERYTHING)
209 g_object_unref (G_OBJECT(data));
213 _pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state,
214 PyGIArgCache *arg_cache,
216 gboolean was_processed)
218 /* If we error out and the object is not marshalled into a PyGObject
219 we must take care of removing the ref */
220 if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
221 g_object_unref (G_OBJECT(data));
226 _pygi_marshal_cleanup_from_py_interface_callback (PyGIInvokeState *state,
227 PyGIArgCache *arg_cache,
229 gboolean was_processed)
231 PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
232 if (was_processed && callback_cache->scope == GI_SCOPE_TYPE_CALL) {
233 _pygi_invoke_closure_free (state->args_data[arg_cache->c_arg_index]);
234 state->args_data[arg_cache->c_arg_index] = NULL;
239 _pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state,
240 PyGIArgCache *arg_cache,
242 gboolean was_processed)
245 PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args,
246 arg_cache->py_arg_index);
247 GType py_object_type =
248 pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE);
250 if (py_object_type != G_TYPE_VALUE) {
251 g_value_unset ((GValue *) data);
252 g_slice_free (GValue, data);
258 _pygi_marshal_cleanup_from_py_interface_struct_foreign (PyGIInvokeState *state,
259 PyGIArgCache *arg_cache,
261 gboolean was_processed)
263 if (state->failed && was_processed)
264 pygi_struct_foreign_release (
265 ( (PyGIInterfaceCache *)arg_cache)->interface_info,
270 _pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state,
271 PyGIArgCache *arg_cache,
273 gboolean was_processed)
275 if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
276 pygi_struct_foreign_release (
277 ( (PyGIInterfaceCache *)arg_cache)->interface_info,
282 _wrap_c_array (PyGIInvokeState *state,
283 PyGISequenceCache *sequence_cache,
289 if (sequence_cache->fixed_size >= 0) {
290 len = sequence_cache->fixed_size;
291 } else if (sequence_cache->is_zero_terminated) {
292 len = g_strv_length ((gchar **)data);
293 } else if (sequence_cache->len_arg_index >= 0) {
294 GIArgument *len_arg = state->args[sequence_cache->len_arg_index];
295 len = len_arg->v_long;
298 array_ = g_array_new (FALSE,
300 sequence_cache->item_size);
305 g_free (array_->data);
313 _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
314 PyGIArgCache *arg_cache,
316 gboolean was_processed)
319 GArray *array_ = NULL;
320 GPtrArray *ptr_array_ = NULL;
321 PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
323 /* If this isn't a garray create one to help process variable sized
325 if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
326 array_ = _wrap_c_array (state, sequence_cache, data);
331 } else if (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
332 ptr_array_ = (GPtrArray *) data;
334 array_ = (GArray *) data;
337 /* clean up items first */
338 if (sequence_cache->item_cache->from_py_cleanup != NULL) {
340 guint len = (array_ != NULL) ? array_->len : ptr_array_->len;
341 PyGIMarshalCleanupFunc cleanup_func =
342 sequence_cache->item_cache->from_py_cleanup;
344 for (i = 0; i < len; i++) {
347 /* case 1: GPtrArray */
348 if (ptr_array_ != NULL)
349 item = g_ptr_array_index (ptr_array_, i);
350 /* case 2: C array or GArray with object pointers */
351 else if (sequence_cache->item_cache->is_pointer)
352 item = g_array_index (array_, gpointer, i);
353 /* case 3: C array or GArray with simple types or structs */
355 item = array_->data + i * sequence_cache->item_size;
357 cleanup_func (state, sequence_cache->item_cache, item, TRUE);
361 /* Only free the array when we didn't transfer ownership */
362 if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
363 g_array_free (array_, arg_cache->transfer == GI_TRANSFER_NOTHING);
364 } else if (state->failed ||
365 arg_cache->transfer == GI_TRANSFER_NOTHING) {
367 g_array_free (array_, TRUE);
369 g_ptr_array_free (ptr_array_, TRUE);
375 _pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state,
376 PyGIArgCache *arg_cache,
378 gboolean was_processed)
380 if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
381 arg_cache->transfer == GI_TRANSFER_CONTAINER) {
382 GArray *array_ = NULL;
383 GPtrArray *ptr_array_ = NULL;
384 PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
386 /* If this isn't a garray create one to help process variable sized
388 if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
389 array_ = _wrap_c_array (state, sequence_cache, data);
394 } else if (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
395 ptr_array_ = (GPtrArray *) data;
397 array_ = (GArray *) data;
400 if (sequence_cache->item_cache->to_py_cleanup != NULL) {
402 guint len = (array_ != NULL) ? array_->len : ptr_array_->len;
404 PyGIMarshalCleanupFunc cleanup_func = sequence_cache->item_cache->to_py_cleanup;
405 for (i = 0; i < len; i++) {
407 sequence_cache->item_cache,
408 (array_ != NULL) ? g_array_index (array_, gpointer, i) : g_ptr_array_index (ptr_array_, i),
414 g_array_free (array_, TRUE);
416 g_ptr_array_free (ptr_array_, TRUE);
421 _pygi_marshal_cleanup_from_py_glist (PyGIInvokeState *state,
422 PyGIArgCache *arg_cache,
424 gboolean was_processed)
428 PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
430 list_ = (GSList *)data;
432 /* clean up items first */
433 if (sequence_cache->item_cache->from_py_cleanup != NULL) {
434 PyGIMarshalCleanupFunc cleanup_func =
435 sequence_cache->item_cache->from_py_cleanup;
436 GSList *node = list_;
437 while (node != NULL) {
439 sequence_cache->item_cache,
447 arg_cache->transfer == GI_TRANSFER_NOTHING ||
448 arg_cache->transfer == GI_TRANSFER_CONTAINER) {
449 switch (arg_cache->type_tag) {
450 case GI_TYPE_TAG_GLIST:
451 g_list_free ( (GList *)list_);
453 case GI_TYPE_TAG_GSLIST:
454 g_slist_free (list_);
457 g_assert_not_reached();
464 _pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state,
465 PyGIArgCache *arg_cache,
467 gboolean was_processed)
469 PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
471 if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
472 arg_cache->transfer == GI_TRANSFER_CONTAINER) {
473 GSList *list_ = (GSList *)data;
475 if (sequence_cache->item_cache->to_py_cleanup != NULL) {
476 PyGIMarshalCleanupFunc cleanup_func =
477 sequence_cache->item_cache->to_py_cleanup;
478 GSList *node = list_;
480 while (node != NULL) {
482 sequence_cache->item_cache,
489 if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) {
490 switch (arg_cache->type_tag) {
491 case GI_TYPE_TAG_GLIST:
492 g_list_free ( (GList *)list_);
494 case GI_TYPE_TAG_GSLIST:
495 g_slist_free (list_);
498 g_assert_not_reached();
505 _pygi_marshal_cleanup_from_py_ghash (PyGIInvokeState *state,
506 PyGIArgCache *arg_cache,
508 gboolean was_processed)
515 PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;
517 hash_ = (GHashTable *)data;
519 /* clean up keys and values first */
520 if (hash_cache->key_cache->from_py_cleanup != NULL ||
521 hash_cache->value_cache->from_py_cleanup != NULL) {
522 GHashTableIter hiter;
526 PyGIMarshalCleanupFunc key_cleanup_func =
527 hash_cache->key_cache->from_py_cleanup;
528 PyGIMarshalCleanupFunc value_cleanup_func =
529 hash_cache->value_cache->from_py_cleanup;
531 g_hash_table_iter_init (&hiter, hash_);
532 while (g_hash_table_iter_next (&hiter, &key, &value)) {
533 if (key != NULL && key_cleanup_func != NULL)
534 key_cleanup_func (state,
535 hash_cache->key_cache,
538 if (value != NULL && value_cleanup_func != NULL)
539 value_cleanup_func (state,
540 hash_cache->value_cache,
547 arg_cache->transfer == GI_TRANSFER_NOTHING ||
548 arg_cache->transfer == GI_TRANSFER_CONTAINER)
549 g_hash_table_destroy (hash_);
555 _pygi_marshal_cleanup_to_py_ghash (PyGIInvokeState *state,
556 PyGIArgCache *arg_cache,
558 gboolean was_processed)
563 /* assume hashtable has boxed key and value */
564 if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
565 g_hash_table_destroy ( (GHashTable *)data);