pygi-marshal-cleanup.c 20 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/* -*- Mode: C; c-basic-offset: 4 -*-
 * vim: tabstop=4 shiftwidth=4 expandtab
 *
 * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 * USA
 */
 
 #include "pygi-marshal-cleanup.h"
 #include <glib.h>
24 25
static inline void
_cleanup_caller_allocates (PyGIInvokeState    *state,
26
                           PyGIArgCache       *cache,
27
                           PyObject           *py_obj,
28 29
                           gpointer            data,
                           gboolean            was_processed)
30
{
31 32
    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)cache;

33 34 35 36 37 38
    /* check GValue first because GValue is also a boxed sub-type */
    if (g_type_is_a (iface_cache->g_type, G_TYPE_VALUE)) {
        if (was_processed)
            g_value_unset (data);
        g_slice_free (GValue, data);
    } else if (g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) {
39
        gsize size;
40 41
        if (was_processed)
            return; /* will be cleaned up at deallocation */
42
        size = g_struct_info_get_size (iface_cache->interface_info);
43
        g_slice_free1 (size, data);
44
    } else if (iface_cache->is_foreign) {
45 46
        if (was_processed)
            return; /* will be cleaned up at deallocation */
47
        pygi_struct_foreign_release ((GIBaseInfo *)iface_cache->interface_info,
48 49
                                     data);
    } else {
50 51
        if (was_processed)
            return; /* will be cleaned up at deallocation */
52 53 54
        g_free (data);
    }
}
55

56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
/**
 * Cleanup during invoke can happen in multiple
 * stages, each of which can be the result of a
 * successful compleation of that stage or an error
 * occured which requires partial cleanup.
 *
 * For the most part, either the C interface being
 * invoked or the python object which wraps the
 * parameters, handle their lifecycles but in some
 * cases, where we have intermediate objects,
 * or when we fail processing a parameter, we need
 * to handle the clean up manually.
 *
 * There are two argument processing stages.
 * They are the in stage, where we process python
 * parameters into their C counterparts, and the out
 * stage, where we process out C parameters back
 * into python objects. The in stage also sets up
 * temporary out structures for caller allocated
 * parameters which need to be cleaned up either on
 * in stage failure or at the completion of the out
 * stage (either success or failure)
 *
 * The in stage must call one of these cleanup functions:
80
 *    - pygi_marshal_cleanup_args_from_py_marshal_success
81
 *       (continue to out stage)
82
 *    - pygi_marshal_cleanup_args_from_py_parameter_fail
83 84 85
 *       (final, exit from invoke)
 *
 * The out stage must call one of these cleanup functions which are all final:
86
 *    - pygi_marshal_cleanup_args_to_py_marshal_success
87
 *    - pygi_marshal_cleanup_args_return_fail
88
 *    - pygi_marshal_cleanup_args_to_py_parameter_fail
89 90 91
 *
 **/
void
92 93
pygi_marshal_cleanup_args_from_py_marshal_success (PyGIInvokeState   *state,
                                                   PyGICallableCache *cache)
94
{
95
    gssize i;
96

97 98
    for (i = 0; i < _pygi_callable_cache_args_len (cache); i++) {
        PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (cache, i);
99
        PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup;
100 101
        PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args,
                                             arg_cache->py_arg_index);
102
        gpointer cleanup_data = state->args_cleanup_data[i];
103

104 105 106 107 108 109 110 111 112 113
        /* Only cleanup using args_cleanup_data when available.
         * It is the responsibility of the various "from_py" marshalers to return
         * cleanup_data which is then passed into their respective cleanup function.
         * 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 &&
                arg_cache->direction & PYGI_DIRECTION_FROM_PYTHON) {
            cleanup_func (state, arg_cache, py_arg, cleanup_data, TRUE);
            state->args_cleanup_data[i] = NULL;
Martin Pitt's avatar
Martin Pitt committed
114
        }
115
    }
116 117 118
}

void
119 120
pygi_marshal_cleanup_args_to_py_marshal_success (PyGIInvokeState   *state,
                                                 PyGICallableCache *cache)
121
{
122
    GSList *cache_item;
123 124
    /* clean up the return if available */
    if (cache->return_cache != NULL) {
125
        PyGIMarshalCleanupFunc cleanup_func = cache->return_cache->to_py_cleanup;
126
        if (cleanup_func && state->return_arg.v_pointer != NULL)
127 128
            cleanup_func (state,
                          cache->return_cache,
129
                          NULL,
130 131 132
                          state->return_arg.v_pointer,
                          TRUE);
    }
133

134
    /* Now clean up args */
135
    cache_item = cache->to_py_args;
136 137
    while (cache_item) {
        PyGIArgCache *arg_cache = (PyGIArgCache *) cache_item->data;
138
        PyGIMarshalCleanupFunc cleanup_func = arg_cache->to_py_cleanup;
139 140 141
        gpointer data = state->args[arg_cache->c_arg_index]->v_pointer;

        if (cleanup_func != NULL && data != NULL)
142 143
            cleanup_func (state,
                          arg_cache,
144
                          NULL,
145
                          data,
146
                          TRUE);
147 148 149
        else if (arg_cache->is_caller_allocates && data != NULL) {
            _cleanup_caller_allocates (state,
                                       arg_cache,
150
                                       NULL,
151 152 153
                                       data,
                                       TRUE);
        }
154 155 156

        cache_item = cache_item->next;
    }
157 158 159
}

void
160 161 162
pygi_marshal_cleanup_args_from_py_parameter_fail (PyGIInvokeState   *state,
                                                  PyGICallableCache *cache,
                                                  gssize failed_arg_index)
163
{
164
    gssize i;
165

166
    state->failed = TRUE;
167

168 169
    for (i = 0; i < _pygi_callable_cache_args_len (cache)  && i <= failed_arg_index; i++) {
        PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (cache, i);
170
        PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup;
171
        gpointer data = state->args[i]->v_pointer;
172 173
        PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args,
                                             arg_cache->py_arg_index);
174

175
        if (cleanup_func &&
176
                arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON &&
177
                    data != NULL) {
178 179
            cleanup_func (state,
                          arg_cache,
180
                          py_arg,
181
                          data,
182
                          i < failed_arg_index);
183 184

        } else if (arg_cache->is_caller_allocates && data != NULL) {
185 186
            _cleanup_caller_allocates (state,
                                       arg_cache,
187
                                       py_arg,
188 189
                                       data,
                                       FALSE);
190 191
        }
    }
192 193 194 195 196 197
}

void
pygi_marshal_cleanup_args_return_fail (PyGIInvokeState   *state,
                                       PyGICallableCache *cache)
{
198
    state->failed = TRUE;
199 200 201
}

void
202
pygi_marshal_cleanup_args_to_py_parameter_fail (PyGIInvokeState   *state,
203
                                              PyGICallableCache *cache,
204
                                              gssize failed_to_py_arg_index)
205
{
206 207
    state->failed = TRUE;
}
208

209
void
210 211
_pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state,
                                                PyGIArgCache    *arg_cache,
212
                                                PyObject        *py_arg,
213 214
                                                gpointer         data,
                                                gboolean         was_processed)
215
{
216 217 218 219 220
    /* If we processed the parameter but fail before invoking the method,
       we need to remove the ref we added */
    if (was_processed && state->failed && data != NULL &&
            arg_cache->transfer == GI_TRANSFER_EVERYTHING)
        g_object_unref (G_OBJECT(data));
221
}
222 223

void
224 225
_pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state,
                                              PyGIArgCache    *arg_cache,
226
                                              PyObject        *dummy,
227 228
                                              gpointer         data,
                                              gboolean         was_processed)
229
{
230 231 232 233
    /* If we error out and the object is not marshalled into a PyGObject
       we must take care of removing the ref */
    if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
        g_object_unref (G_OBJECT(data));
234 235
}

236 237 238 239

void
_pygi_marshal_cleanup_from_py_interface_callback (PyGIInvokeState *state,
                                                  PyGIArgCache    *arg_cache,
240
                                                  PyObject        *py_arg,
241 242 243 244 245
                                                  gpointer         data,
                                                  gboolean         was_processed)
{
    PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
    if (was_processed && callback_cache->scope == GI_SCOPE_TYPE_CALL) {
246
        _pygi_invoke_closure_free (data);
247 248 249
    }
}

250
void 
251 252
_pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state,
                                                       PyGIArgCache    *arg_cache,
253
                                                       PyObject        *py_arg,
254 255
                                                       gpointer         data,
                                                       gboolean         was_processed)
256
{
257 258
    /* Note py_arg can be NULL for hash table which is a bug. */
    if (was_processed && py_arg != NULL) {
259 260 261
        GType py_object_type =
            pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE);

262 263 264
        /* When a GValue was not passed, it means the marshalers created a new
         * one to pass in, clean this up.
         */
265 266 267 268 269 270 271 272
        if (py_object_type != G_TYPE_VALUE) {
            g_value_unset ((GValue *) data);
            g_slice_free (GValue, data);
        }
    }
}

void
273 274
_pygi_marshal_cleanup_from_py_interface_struct_foreign (PyGIInvokeState *state,
                                                        PyGIArgCache    *arg_cache,
275
                                                        PyObject        *py_arg,
276 277
                                                        gpointer         data,
                                                        gboolean         was_processed)
278 279 280 281 282 283 284 285
{
    if (state->failed && was_processed)
        pygi_struct_foreign_release (
            ( (PyGIInterfaceCache *)arg_cache)->interface_info,
            data);
}

void
286 287
_pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state,
                                                      PyGIArgCache    *arg_cache,
288
                                                      PyObject        *dummy,
289 290
                                                      gpointer         data,
                                                      gboolean         was_processed)
291
{
292 293 294 295
    if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
        pygi_struct_foreign_release ( 
            ( (PyGIInterfaceCache *)arg_cache)->interface_info,
            data);
296
}
297

298 299
static GArray*
_wrap_c_array (PyGIInvokeState   *state,
300
               PyGIArgGArray     *array_cache,
301 302 303
               gpointer           data)
{
    GArray *array_;
304
    gsize   len = 0;
305
  
306 307 308
    if (array_cache->fixed_size >= 0) {
        len = array_cache->fixed_size;
    } else if (array_cache->is_zero_terminated) {
309
        len = g_strv_length ((gchar **)data);
310 311
    } else if (array_cache->len_arg_index >= 0) {
        GIArgument *len_arg = state->args[array_cache->len_arg_index];
312 313 314 315 316
        len = len_arg->v_long;
    }

    array_ = g_array_new (FALSE,
                          FALSE,
317
                          array_cache->item_size);
318 319 320 321 322 323 324 325 326 327 328

    if (array_ == NULL)
        return NULL;

    g_free (array_->data);
    array_->data = data;
    array_->len = len;

    return array_;
}

329
void
330 331
_pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
                                     PyGIArgCache    *arg_cache,
332
                                     PyObject        *py_arg,
333 334
                                     gpointer         data,
                                     gboolean         was_processed)
335 336
{
    if (was_processed) {
337 338
        GArray *array_ = NULL;
        GPtrArray *ptr_array_ = NULL;
339
        PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
340
        PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
341

342
        if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
343
            ptr_array_ = (GPtrArray *) data;
344 345 346 347 348
        } else {
            array_ = (GArray *) data;
        }

        /* clean up items first */
349
        if (sequence_cache->item_cache->from_py_cleanup != NULL) {
350
            gsize i;
351
            guint len = (array_ != NULL) ? array_->len : ptr_array_->len;
352
            PyGIMarshalCleanupFunc cleanup_func =
353
                sequence_cache->item_cache->from_py_cleanup;
354

355 356
            for (i = 0; i < len; i++) {
                gpointer item;
357
                PyObject *py_item = NULL;
358 359 360 361 362 363 364 365

                /* case 1: GPtrArray */
                if (ptr_array_ != NULL)
                    item = g_ptr_array_index (ptr_array_, i);
                /* case 2: C array or GArray with object pointers */
                else if (sequence_cache->item_cache->is_pointer)
                    item = g_array_index (array_, gpointer, i);
                /* case 3: C array or GArray with simple types or structs */
Martin Pitt's avatar
Martin Pitt committed
366
                else {
367
                    item = array_->data + i * array_cache->item_size;
Martin Pitt's avatar
Martin Pitt committed
368 369 370 371 372 373 374 375 376
                    /* special-case hack: GValue array items do not get slice
                     * allocated in _pygi_marshal_from_py_array(), so we must
                     * not try to deallocate it as a slice and thus
                     * short-circuit cleanup_func. */
                    if (cleanup_func == _pygi_marshal_cleanup_from_py_interface_struct_gvalue) {
                        g_value_unset ((GValue*) item);
                        continue;
                    }
                }
377

378 379 380
                py_item = PySequence_GetItem (py_arg, i);
                cleanup_func (state, sequence_cache->item_cache, py_item, item, TRUE);
                Py_XDECREF (py_item);
381 382 383
            }
        }

384
        /* Only free the array when we didn't transfer ownership */
385
        if (array_cache->array_type == GI_ARRAY_TYPE_C) {
386 387 388
            /* always free the GArray wrapper created in from_py marshaling and
             * passed back as cleanup_data
             */
389
            g_array_free (array_, arg_cache->transfer == GI_TRANSFER_NOTHING);
390
        } else {
391
            if (array_ != NULL)
392
                g_array_unref (array_);
393
            else
394
                g_ptr_array_unref (ptr_array_);
395 396 397 398 399
        }
    }
}

void
400 401
_pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state,
                                   PyGIArgCache    *arg_cache,
402
                                   PyObject        *dummy,
403 404
                                   gpointer         data,
                                   gboolean         was_processed)
405
{
406
    if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
407
        arg_cache->transfer == GI_TRANSFER_CONTAINER) {
408 409
        GArray *array_ = NULL;
        GPtrArray *ptr_array_ = NULL;
410
        PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
411
        PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
412

413 414
        /* If this isn't a garray create one to help process variable sized
           array elements */
415 416
        if (array_cache->array_type == GI_ARRAY_TYPE_C) {
            array_ = _wrap_c_array (state, array_cache, data);
417 418 419
            
            if (array_ == NULL)
                return;
420

421
        } else if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
422
            ptr_array_ = (GPtrArray *) data;
423 424
        } else {
            array_ = (GArray *) data;
425 426
        }

427
        if (sequence_cache->item_cache->to_py_cleanup != NULL) {
428
            gsize i;
429
            guint len = (array_ != NULL) ? array_->len : ptr_array_->len;
430

431
            PyGIMarshalCleanupFunc cleanup_func = sequence_cache->item_cache->to_py_cleanup;
432
            for (i = 0; i < len; i++) {
433 434
                cleanup_func (state,
                              sequence_cache->item_cache,
435
                              NULL,
436
                              (array_ != NULL) ? g_array_index (array_, gpointer, i) : g_ptr_array_index (ptr_array_, i),
437 438 439 440
                              was_processed);
            }
        }

441 442 443 444
        if (array_ != NULL)
            g_array_free (array_, TRUE);
        else
            g_ptr_array_free (ptr_array_, TRUE);
445
    }
446
}
447 448

void
449 450
_pygi_marshal_cleanup_from_py_glist  (PyGIInvokeState *state,
                                      PyGIArgCache    *arg_cache,
451
                                      PyObject        *py_arg,
452 453
                                      gpointer         data,
                                      gboolean         was_processed)
454 455 456 457 458 459 460 461
{
    if (was_processed) {
        GSList *list_;
        PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;

        list_ = (GSList *)data;

        /* clean up items first */
462
        if (sequence_cache->item_cache->from_py_cleanup != NULL) {
463
            PyGIMarshalCleanupFunc cleanup_func =
464
                sequence_cache->item_cache->from_py_cleanup;
465
            GSList *node = list_;
466
            gsize i = 0;
467
            while (node != NULL) {
468
                PyObject *py_item = PySequence_GetItem (py_arg, i);
469 470
                cleanup_func (state,
                              sequence_cache->item_cache,
471
                              py_item,
472 473
                              node->data,
                              TRUE);
474
                Py_XDECREF (py_item);
475
                node = node->next;
476
                i++;
477 478 479
            }
        }

480 481 482 483 484 485
        if (arg_cache->type_tag == GI_TYPE_TAG_GLIST) {
            g_list_free ( (GList *)list_);
        } else if (arg_cache->type_tag == GI_TYPE_TAG_GSLIST) {
            g_slist_free (list_);
        } else {
            g_assert_not_reached();
486 487 488 489 490
        }
    }
}

void
491 492
_pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state,
                                   PyGIArgCache    *arg_cache,
493
                                   PyObject        *dummy,
494 495
                                   gpointer         data,
                                   gboolean         was_processed)
496 497 498 499 500 501
{
    PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
    if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
            arg_cache->transfer == GI_TRANSFER_CONTAINER) {
        GSList *list_ = (GSList *)data;

502
        if (sequence_cache->item_cache->to_py_cleanup != NULL) {
503
            PyGIMarshalCleanupFunc cleanup_func =
504
                sequence_cache->item_cache->to_py_cleanup;
505 506 507 508 509
            GSList *node = list_;

            while (node != NULL) {
                cleanup_func (state,
                              sequence_cache->item_cache,
510
                              NULL,
511 512 513 514 515 516
                              node->data,
                              was_processed);
                node = node->next;
            }
        }

517 518 519 520 521 522
        if (arg_cache->type_tag == GI_TYPE_TAG_GLIST) {
            g_list_free ( (GList *)list_);
        } else if (arg_cache->type_tag == GI_TYPE_TAG_GSLIST) {
            g_slist_free (list_);
        } else {
            g_assert_not_reached();
523 524 525
        }
    }
}
526