pygi-marshal-cleanup.c 20.3 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
28
                           gpointer            data)
{
29
30
31
    PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)cache;

    if (iface_cache->g_type == G_TYPE_BOXED) {
32
        gsize size;
33
        size = g_struct_info_get_size (iface_cache->interface_info);
34
        g_slice_free1 (size, data);
35
36
    } else if (iface_cache->g_type == G_TYPE_VALUE) {
        g_slice_free (GValue, data);
37
38
    } else if (iface_cache->is_foreign) {
        pygi_struct_foreign_release ((GIBaseInfo *)iface_cache->interface_info,
39
40
41
42
43
                                     data);
    } else {
        g_free (data);
    }
}
44

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
 * 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:
69
 *    - pygi_marshal_cleanup_args_from_py_marshal_success
70
 *       (continue to out stage)
71
 *    - pygi_marshal_cleanup_args_from_py_parameter_fail
72
73
74
 *       (final, exit from invoke)
 *
 * 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
78
79
80
 *
 **/
void
81
82
pygi_marshal_cleanup_args_from_py_marshal_success (PyGIInvokeState   *state,
                                                   PyGICallableCache *cache)
83
{
84
    gssize i;
85

86
87
88
    /* For in success, call cleanup for all GI_DIRECTION_IN values only. */
    for (i = 0; i < cache->n_args; i++) {
        PyGIArgCache *arg_cache = cache->args_cache[i];
89
        PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup;
90

91
        if (cleanup_func &&
92
                arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON &&
93
                    state->args[i]->v_pointer != NULL)
94
95
            cleanup_func (state, arg_cache, state->args[i]->v_pointer, TRUE);
    }
96
97
98
}

void
99
100
pygi_marshal_cleanup_args_to_py_marshal_success (PyGIInvokeState   *state,
                                                 PyGICallableCache *cache)
101
{
102
103
    /* clean up the return if available */
    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)
106
107
108
109
110
            cleanup_func (state,
                          cache->return_cache,
                          state->return_arg.v_pointer,
                          TRUE);
    }
111

112
    /* Now clean up args */
113
    GSList *cache_item = cache->to_py_args;
114
115
    while (cache_item) {
        PyGIArgCache *arg_cache = (PyGIArgCache *) cache_item->data;
116
        PyGIMarshalCleanupFunc cleanup_func = arg_cache->to_py_cleanup;
117
118
119
        gpointer data = state->args[arg_cache->c_arg_index]->v_pointer;

        if (cleanup_func != NULL && data != NULL)
120
121
            cleanup_func (state,
                          arg_cache,
122
                          data,
123
124
125
126
                          TRUE);

        cache_item = cache_item->next;
    }
127
128
129
}

void
130
131
132
pygi_marshal_cleanup_args_from_py_parameter_fail (PyGIInvokeState   *state,
                                                  PyGICallableCache *cache,
                                                  gssize failed_arg_index)
133
{
134
    gssize i;
135

136
    state->failed = TRUE;
137

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;
142

143
        if (cleanup_func &&
144
                arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON &&
145
                    data != NULL) {
146
147
            cleanup_func (state,
                          arg_cache,
148
                          data,
149
                          i < failed_arg_index);
150
151

        } else if (arg_cache->is_caller_allocates && data != NULL) {
152
153
            _cleanup_caller_allocates (state,
                                       arg_cache,
154
                                       data);
155
156
        }
    }
157
158
159
160
161
162
}

void
pygi_marshal_cleanup_args_return_fail (PyGIInvokeState   *state,
                                       PyGICallableCache *cache)
{
163
    state->failed = TRUE;
164
165
166
}

void
167
pygi_marshal_cleanup_args_to_py_parameter_fail (PyGIInvokeState   *state,
168
                                              PyGICallableCache *cache,
169
                                              gssize failed_to_py_arg_index)
170
{
171
172
    state->failed = TRUE;
}
173

174
void
175
176
177
178
_pygi_marshal_cleanup_from_py_utf8 (PyGIInvokeState *state,
                                    PyGIArgCache    *arg_cache,
                                    gpointer         data,
                                    gboolean         was_processed)
179
{
180
181
182
183
    /* We strdup strings so always free if we have processed this
       parameter for input */
    if (was_processed)
        g_free (data);
184
185
}

186
void
187
188
189
190
_pygi_marshal_cleanup_to_py_utf8 (PyGIInvokeState *state,
                                  PyGIArgCache    *arg_cache,
                                  gpointer         data,
                                  gboolean         was_processed)
191
{
192
193
194
195
196
    /* Python copies the string so we need to free it
       if the interface is transfering ownership, 
       whether or not it has been processed yet */
    if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
        g_free (data);
197
198
}

199
void
200
201
202
203
_pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state,
                                                PyGIArgCache    *arg_cache,
                                                gpointer         data,
                                                gboolean         was_processed)
204
{
205
206
207
208
209
    /* 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));
210
}
211
212

void
213
214
215
216
_pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state,
                                              PyGIArgCache    *arg_cache,
                                              gpointer         data,
                                              gboolean         was_processed)
217
{
218
219
220
221
    /* 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));
222
223
}

224
225
226
227
228
229
230
231
232
233
234
235
236
237

void
_pygi_marshal_cleanup_from_py_interface_callback (PyGIInvokeState *state,
                                                  PyGIArgCache    *arg_cache,
                                                  gpointer         data,
                                                  gboolean         was_processed)
{
    PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
    if (was_processed && callback_cache->scope == GI_SCOPE_TYPE_CALL) {
        _pygi_invoke_closure_free (state->args_data[arg_cache->c_arg_index]);
        state->args_data[arg_cache->c_arg_index] = NULL;
    }
}

238
void 
239
240
241
242
_pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state,
                                                       PyGIArgCache    *arg_cache,
                                                       gpointer         data,
                                                       gboolean         was_processed)
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
{
    if (was_processed) {
        PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args,
                                             arg_cache->py_arg_index);
        GType py_object_type =
            pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE);

        if (py_object_type != G_TYPE_VALUE) {
            g_value_unset ((GValue *) data);
            g_slice_free (GValue, data);
        }
    }
}

void
258
259
260
261
_pygi_marshal_cleanup_from_py_interface_struct_foreign (PyGIInvokeState *state,
                                                        PyGIArgCache    *arg_cache,
                                                        gpointer         data,
                                                        gboolean         was_processed)
262
263
264
265
266
267
268
269
{
    if (state->failed && was_processed)
        pygi_struct_foreign_release (
            ( (PyGIInterfaceCache *)arg_cache)->interface_info,
            data);
}

void
270
271
272
273
_pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state,
                                                      PyGIArgCache    *arg_cache,
                                                      gpointer         data,
                                                      gboolean         was_processed)
274
{
275
276
277
278
    if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
        pygi_struct_foreign_release ( 
            ( (PyGIInterfaceCache *)arg_cache)->interface_info,
            data);
279
}
280

281
282
283
284
285
286
static GArray*
_wrap_c_array (PyGIInvokeState   *state,
               PyGISequenceCache *sequence_cache,
               gpointer           data)
{
    GArray *array_;
287
    gsize   len = 0;
288
289
290
291
292
  
    if (sequence_cache->fixed_size >= 0) {
        len = sequence_cache->fixed_size;
    } else if (sequence_cache->is_zero_terminated) {
        len = g_strv_length ((gchar **)data);
293
    } else if (sequence_cache->len_arg_index >= 0) {
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
        GIArgument *len_arg = state->args[sequence_cache->len_arg_index];
        len = len_arg->v_long;
    }

    array_ = g_array_new (FALSE,
                          FALSE,
                          sequence_cache->item_size);

    if (array_ == NULL)
        return NULL;

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

    return array_;
}

312
void
313
314
315
316
_pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
                                     PyGIArgCache    *arg_cache,
                                     gpointer         data,
                                     gboolean         was_processed)
317
318
{
    if (was_processed) {
319
320
        GArray *array_ = NULL;
        GPtrArray *ptr_array_ = NULL;
321
322
323
324
325
        PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;

        /* If this isn't a garray create one to help process variable sized
           array elements */
        if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
326
327
            array_ = _wrap_c_array (state, sequence_cache, data);
            
328
329
            if (array_ == NULL)
                return;
330
            
331
332
        } else if (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
            ptr_array_ = (GPtrArray *) data;
333
334
335
336
337
        } else {
            array_ = (GArray *) data;
        }

        /* clean up items first */
338
        if (sequence_cache->item_cache->from_py_cleanup != NULL) {
339
            gsize i;
340
            guint len = (array_ != NULL) ? array_->len : ptr_array_->len;
341
            PyGIMarshalCleanupFunc cleanup_func =
342
                sequence_cache->item_cache->from_py_cleanup;
343

344
345
346
347
348
349
350
351
352
353
354
355
356
357
            for (i = 0; i < len; i++) {
                gpointer item;

                /* 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 */
                else
                    item = array_->data + i * sequence_cache->item_size;

                cleanup_func (state, sequence_cache->item_cache, item, TRUE);
358
359
360
            }
        }

361
362
363
364
365
        /* Only free the array when we didn't transfer ownership */
        if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
            g_array_free (array_, arg_cache->transfer == GI_TRANSFER_NOTHING);
        } else if (state->failed ||
                   arg_cache->transfer == GI_TRANSFER_NOTHING) {
366
367
368
369
            if (array_ != NULL)
                g_array_free (array_, TRUE);
            else
                g_ptr_array_free (ptr_array_, TRUE);
370
371
372
373
374
        }
    }
}

void
375
376
377
378
_pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state,
                                   PyGIArgCache    *arg_cache,
                                   gpointer         data,
                                   gboolean         was_processed)
379
{
380
    if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
381
        arg_cache->transfer == GI_TRANSFER_CONTAINER) {
382
383
        GArray *array_ = NULL;
        GPtrArray *ptr_array_ = NULL;
384
        PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
385

386
387
        /* If this isn't a garray create one to help process variable sized
           array elements */
388
        if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
389
390
391
392
            array_ = _wrap_c_array (state, sequence_cache, data);
            
            if (array_ == NULL)
                return;
393
394
395

        } else if (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
            ptr_array_ = (GPtrArray *) data;
396
397
        } else {
            array_ = (GArray *) data;
398
399
        }

400
        if (sequence_cache->item_cache->to_py_cleanup != NULL) {
401
            gsize i;
402
            guint len = (array_ != NULL) ? array_->len : ptr_array_->len;
403

404
            PyGIMarshalCleanupFunc cleanup_func = sequence_cache->item_cache->to_py_cleanup;
405
            for (i = 0; i < len; i++) {
406
407
                cleanup_func (state,
                              sequence_cache->item_cache,
408
                              (array_ != NULL) ? g_array_index (array_, gpointer, i) : g_ptr_array_index (ptr_array_, i),
409
410
411
412
                              was_processed);
            }
        }

413
414
415
416
        if (array_ != NULL)
            g_array_free (array_, TRUE);
        else
            g_ptr_array_free (ptr_array_, TRUE);
417
    }
418
}
419
420

void
421
422
423
424
_pygi_marshal_cleanup_from_py_glist  (PyGIInvokeState *state,
                                      PyGIArgCache    *arg_cache,
                                      gpointer         data,
                                      gboolean         was_processed)
425
426
427
428
429
430
431
432
{
    if (was_processed) {
        GSList *list_;
        PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;

        list_ = (GSList *)data;

        /* 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
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
            GSList *node = list_;
            while (node != NULL) {
                cleanup_func (state,
                              sequence_cache->item_cache,
                              node->data,
                              TRUE);
                node = node->next;
            }
        }

        if (state->failed ||
               arg_cache->transfer == GI_TRANSFER_NOTHING ||
                  arg_cache->transfer == GI_TRANSFER_CONTAINER) {
            switch (arg_cache->type_tag) {
                case GI_TYPE_TAG_GLIST:
                    g_list_free ( (GList *)list_);
                    break;
                case GI_TYPE_TAG_GSLIST:
                    g_slist_free (list_);
                    break;
                default:
                    g_assert_not_reached();
            }
        }
    }
}

void
464
465
466
467
_pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state,
                                   PyGIArgCache    *arg_cache,
                                   gpointer         data,
                                   gboolean         was_processed)
468
469
470
471
472
473
474
{
    PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;

    if (arg_cache->transfer == GI_TRANSFER_EVERYTHING ||
            arg_cache->transfer == GI_TRANSFER_CONTAINER) {
        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
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
            GSList *node = list_;

            while (node != NULL) {
                cleanup_func (state,
                              sequence_cache->item_cache,
                              node->data,
                              was_processed);
                node = node->next;
            }
        }

        if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) {
            switch (arg_cache->type_tag) {
                case GI_TYPE_TAG_GLIST:
                    g_list_free ( (GList *)list_);
                    break;
                case GI_TYPE_TAG_GSLIST:
                    g_slist_free (list_);
                    break;
                default:
                    g_assert_not_reached();
            }
        }
    }
}
503
504

void
505
506
507
508
_pygi_marshal_cleanup_from_py_ghash  (PyGIInvokeState *state,
                                      PyGIArgCache    *arg_cache,
                                      gpointer         data,
                                      gboolean         was_processed)
509
510
511
512
513
514
515
516
517
518
519
{
    if (data == NULL)
        return;

    if (was_processed) {
        GHashTable *hash_;
        PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache;

        hash_ = (GHashTable *)data;

        /* clean up keys and values first */
520
521
        if (hash_cache->key_cache->from_py_cleanup != NULL ||
                hash_cache->value_cache->from_py_cleanup != NULL) {
522
523
524
525
526
            GHashTableIter hiter;
            gpointer key;
            gpointer value;

            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;
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554

            g_hash_table_iter_init (&hiter, hash_);
            while (g_hash_table_iter_next (&hiter, &key, &value)) {
                if (key != NULL && key_cleanup_func != NULL)
                    key_cleanup_func (state,
                                      hash_cache->key_cache,
                                      key,
                                      TRUE);
                if (value != NULL && value_cleanup_func != NULL)
                    value_cleanup_func (state,
                                        hash_cache->value_cache,
                                        value,
                                        TRUE);
            }
        }

        if (state->failed ||
               arg_cache->transfer == GI_TRANSFER_NOTHING ||
                  arg_cache->transfer == GI_TRANSFER_CONTAINER)
            g_hash_table_destroy (hash_);

    }
}

void
555
556
557
558
_pygi_marshal_cleanup_to_py_ghash (PyGIInvokeState *state,
                                   PyGIArgCache    *arg_cache,
                                   gpointer         data,
                                   gboolean         was_processed)
559
560
561
562
563
564
565
566
{
    if (data == NULL)
        return;

    /* assume hashtable has boxed key and value */
    if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
        g_hash_table_destroy ( (GHashTable *)data);
}