Imported Upstream version 3.13.92
[platform/upstream/pygobject2.git] / gi / pygi-marshal-cleanup.c
1 /* -*- Mode: C; c-basic-offset: 4 -*-
2  * vim: tabstop=4 shiftwidth=4 expandtab
3  *
4  * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc.
5  *
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.
10  *
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.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19  
20  #include "pygi-marshal-cleanup.h"
21  #include <glib.h>
22 static inline void
23 _cleanup_caller_allocates (PyGIInvokeState    *state,
24                            PyGIArgCache       *cache,
25                            PyObject           *py_obj,
26                            gpointer            data,
27                            gboolean            was_processed)
28 {
29     PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)cache;
30
31     /* check GValue first because GValue is also a boxed sub-type */
32     if (g_type_is_a (iface_cache->g_type, G_TYPE_VALUE)) {
33         if (was_processed)
34             g_value_unset (data);
35         g_slice_free (GValue, data);
36     } else if (g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) {
37         gsize size;
38         if (was_processed)
39             return; /* will be cleaned up at deallocation */
40         size = g_struct_info_get_size (iface_cache->interface_info);
41         g_slice_free1 (size, data);
42     } else if (iface_cache->is_foreign) {
43         if (was_processed)
44             return; /* will be cleaned up at deallocation */
45         pygi_struct_foreign_release ((GIBaseInfo *)iface_cache->interface_info,
46                                      data);
47     } else {
48         if (was_processed)
49             return; /* will be cleaned up at deallocation */
50         g_free (data);
51     }
52 }
53
54 /**
55  * Cleanup during invoke can happen in multiple
56  * stages, each of which can be the result of a
57  * successful compleation of that stage or an error
58  * occured which requires partial cleanup.
59  *
60  * For the most part, either the C interface being
61  * invoked or the python object which wraps the
62  * parameters, handle their lifecycles but in some
63  * cases, where we have intermediate objects,
64  * or when we fail processing a parameter, we need
65  * to handle the clean up manually.
66  *
67  * There are two argument processing stages.
68  * They are the in stage, where we process python
69  * parameters into their C counterparts, and the out
70  * stage, where we process out C parameters back
71  * into python objects. The in stage also sets up
72  * temporary out structures for caller allocated
73  * parameters which need to be cleaned up either on
74  * in stage failure or at the completion of the out
75  * stage (either success or failure)
76  *
77  * The in stage must call one of these cleanup functions:
78  *    - pygi_marshal_cleanup_args_from_py_marshal_success
79  *       (continue to out stage)
80  *    - pygi_marshal_cleanup_args_from_py_parameter_fail
81  *       (final, exit from invoke)
82  *
83  * The out stage must call one of these cleanup functions which are all final:
84  *    - pygi_marshal_cleanup_args_to_py_marshal_success
85  *    - pygi_marshal_cleanup_args_return_fail
86  *    - pygi_marshal_cleanup_args_to_py_parameter_fail
87  *
88  **/
89 void
90 pygi_marshal_cleanup_args_from_py_marshal_success (PyGIInvokeState   *state,
91                                                    PyGICallableCache *cache)
92 {
93     gssize i;
94
95     for (i = 0; i < _pygi_callable_cache_args_len (cache); i++) {
96         PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (cache, i);
97         PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup;
98         gpointer cleanup_data = state->args_cleanup_data[i];
99
100         /* Only cleanup using args_cleanup_data when available.
101          * It is the responsibility of the various "from_py" marshalers to return
102          * cleanup_data which is then passed into their respective cleanup function.
103          * PyGIInvokeState.args_cleanup_data stores this data (via _invoke_marshal_in_args)
104          * for the duration of the invoke up until this point.
105          */
106         if (cleanup_func && cleanup_data != NULL && arg_cache->py_arg_index >= 0 &&
107                 arg_cache->direction & PYGI_DIRECTION_FROM_PYTHON) {
108             PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args, arg_cache->py_arg_index);
109             cleanup_func (state, arg_cache, py_arg, cleanup_data, TRUE);
110             state->args_cleanup_data[i] = NULL;
111         }
112     }
113 }
114
115 void
116 pygi_marshal_cleanup_args_to_py_marshal_success (PyGIInvokeState   *state,
117                                                  PyGICallableCache *cache)
118 {
119     GSList *cache_item;
120     /* clean up the return if available */
121     if (cache->return_cache != NULL) {
122         PyGIMarshalCleanupFunc cleanup_func = cache->return_cache->to_py_cleanup;
123         if (cleanup_func && state->return_arg.v_pointer != NULL)
124             cleanup_func (state,
125                           cache->return_cache,
126                           NULL,
127                           state->return_arg.v_pointer,
128                           TRUE);
129     }
130
131     /* Now clean up args */
132     cache_item = cache->to_py_args;
133     while (cache_item) {
134         PyGIArgCache *arg_cache = (PyGIArgCache *) cache_item->data;
135         PyGIMarshalCleanupFunc cleanup_func = arg_cache->to_py_cleanup;
136         gpointer data = state->arg_values[arg_cache->c_arg_index].v_pointer;
137
138         if (cleanup_func != NULL && data != NULL)
139             cleanup_func (state,
140                           arg_cache,
141                           NULL,
142                           data,
143                           TRUE);
144         else if (arg_cache->is_caller_allocates && data != NULL) {
145             _cleanup_caller_allocates (state,
146                                        arg_cache,
147                                        NULL,
148                                        data,
149                                        TRUE);
150         }
151
152         cache_item = cache_item->next;
153     }
154 }
155
156 void
157 pygi_marshal_cleanup_args_from_py_parameter_fail (PyGIInvokeState   *state,
158                                                   PyGICallableCache *cache,
159                                                   gssize failed_arg_index)
160 {
161     gssize i;
162
163     state->failed = TRUE;
164
165     for (i = 0; i < _pygi_callable_cache_args_len (cache)  && i <= failed_arg_index; i++) {
166         PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (cache, i);
167         PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup;
168         gpointer cleanup_data = state->args_cleanup_data[i];
169         PyObject *py_arg = NULL;
170
171         if (arg_cache->py_arg_index < 0) {
172             continue;
173         }
174         py_arg = PyTuple_GET_ITEM (state->py_in_args, arg_cache->py_arg_index);
175
176         if (cleanup_func && cleanup_data != NULL &&
177                 arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON) {
178             cleanup_func (state,
179                           arg_cache,
180                           py_arg,
181                           cleanup_data,
182                           i < failed_arg_index);
183
184         } else if (arg_cache->is_caller_allocates && cleanup_data != NULL) {
185             _cleanup_caller_allocates (state,
186                                        arg_cache,
187                                        py_arg,
188                                        cleanup_data,
189                                        FALSE);
190         }
191         state->args_cleanup_data[i] = NULL;
192     }
193 }
194
195 void
196 pygi_marshal_cleanup_args_return_fail (PyGIInvokeState   *state,
197                                        PyGICallableCache *cache)
198 {
199     state->failed = TRUE;
200 }
201
202 void
203 pygi_marshal_cleanup_args_to_py_parameter_fail (PyGIInvokeState   *state,
204                                               PyGICallableCache *cache,
205                                               gssize failed_to_py_arg_index)
206 {
207     state->failed = TRUE;
208 }