f6f5c512c59bd1713a94c885fc17a17cff2f5995
[platform/upstream/python-gobject.git] / gi / pygi-closure.c
1 /* -*- Mode: C; c-basic-offset: 4 -*-
2  * vim: tabstop=4 shiftwidth=4 expandtab
3  *
4  *   pygi-closure.c: PyGI C Closure functions
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, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19  * USA
20  */
21
22 #include "pygi-private.h"
23
24 /* This maintains a list of closures which can be free'd whenever
25    as they have been called.  We will free them on the next
26    library function call.
27  */
28 static GSList* async_free_list;
29
30 static void
31 _pygi_closure_assign_pyobj_to_retval (gpointer retval, PyObject *object,
32                                       GITypeInfo *type_info,
33                                       GITransfer transfer)
34 {
35     GIArgument arg = _pygi_argument_from_object (object, type_info, transfer);
36     GITypeTag type_tag = g_type_info_get_tag (type_info);
37
38     if (retval == NULL)
39         return;
40
41     switch (type_tag) {
42         case GI_TYPE_TAG_BOOLEAN:
43            *((ffi_sarg *) retval) = arg.v_boolean;
44            break;
45         case GI_TYPE_TAG_INT8:
46            *((ffi_sarg *) retval) = arg.v_int8;
47            break;
48         case GI_TYPE_TAG_UINT8:
49            *((ffi_arg *) retval) = arg.v_uint8;
50            break;
51         case GI_TYPE_TAG_INT16:
52            *((ffi_sarg *) retval) = arg.v_int16;
53            break;
54         case GI_TYPE_TAG_UINT16:
55            *((ffi_arg *) retval) = arg.v_uint16;
56            break;
57         case GI_TYPE_TAG_INT32:
58            *((ffi_sarg *) retval) = arg.v_int32;
59            break;
60         case GI_TYPE_TAG_UINT32:
61            *((ffi_arg *) retval) = arg.v_uint32;
62            break;
63         case GI_TYPE_TAG_INT64:
64            *((ffi_sarg *) retval) = arg.v_int64;
65            break;
66         case GI_TYPE_TAG_UINT64:
67            *((ffi_arg *) retval) = arg.v_uint64;
68            break;
69         case GI_TYPE_TAG_FLOAT:
70            *((gfloat *) retval) = arg.v_float;
71            break;
72         case GI_TYPE_TAG_DOUBLE:
73            *((gdouble *) retval) = arg.v_double;
74            break;
75         default:
76            *((GIArgument *) retval) = arg;
77            break;
78       }
79 }
80
81 static void
82 _pygi_closure_assign_pyobj_to_out_argument (gpointer out_arg, PyObject *object,
83                                             GITypeInfo *type_info,
84                                             GITransfer transfer)
85 {
86     GIArgument arg = _pygi_argument_from_object (object, type_info, transfer);
87     GITypeTag type_tag = g_type_info_get_tag (type_info);
88
89     if (out_arg == NULL)
90         return;
91
92     switch (type_tag) {
93         case GI_TYPE_TAG_BOOLEAN:
94            *((gboolean *) out_arg) = arg.v_boolean;
95            break;
96         case GI_TYPE_TAG_INT8:
97            *((gint8 *) out_arg) = arg.v_int8;
98            break;
99         case GI_TYPE_TAG_UINT8:
100            *((guint8 *) out_arg) = arg.v_uint8;
101            break;
102         case GI_TYPE_TAG_INT16:
103            *((gint16 *) out_arg) = arg.v_int16;
104            break;
105         case GI_TYPE_TAG_UINT16:
106            *((guint16 *) out_arg) = arg.v_uint16;
107            break;
108         case GI_TYPE_TAG_INT32:
109            *((gint32 *) out_arg) = arg.v_int32;
110            break;
111         case GI_TYPE_TAG_UINT32:
112            *((guint32 *) out_arg) = arg.v_uint32;
113            break;
114         case GI_TYPE_TAG_INT64:
115            *((gint64 *) out_arg) = arg.v_int64;
116            break;
117         case GI_TYPE_TAG_UINT64:
118            *((glong *) out_arg) = arg.v_uint64;
119            break;
120         case GI_TYPE_TAG_FLOAT:
121            *((gfloat *) out_arg) = arg.v_float;
122            break;
123         case GI_TYPE_TAG_DOUBLE:
124            *((gdouble *) out_arg) = arg.v_double;
125            break;
126         case GI_TYPE_TAG_INTERFACE:
127         {
128            GIBaseInfo *interface;
129            GIInfoType interface_type;
130
131            interface = g_type_info_get_interface (type_info);
132            interface_type = g_base_info_get_type (interface);
133
134            if (!g_type_info_is_pointer (type_info) &&
135                interface_type == GI_INFO_TYPE_STRUCT) {
136                if (object == Py_None) {
137                    arg.v_pointer = NULL;
138                } else {
139                    gsize item_size = _pygi_g_type_info_size (type_info);
140                    memcpy (out_arg, arg.v_pointer, item_size);
141                }
142                break;
143            }
144         }
145
146         /* Fall through */
147         default:
148            *((GIArgument *) out_arg) = arg;
149            break;
150       }
151 }
152
153 static GIArgument *
154 _pygi_closure_convert_ffi_arguments (GICallableInfo *callable_info, void **args)
155 {
156     gint num_args, i;
157     GIArgInfo *arg_info;
158     GITypeInfo *arg_type;
159     GITypeTag tag;
160     GIDirection direction;
161     GIArgument *g_args;
162
163     num_args = g_callable_info_get_n_args (callable_info);
164     g_args = g_new0 (GIArgument, num_args);
165
166     for (i = 0; i < num_args; i++) {
167         arg_info = g_callable_info_get_arg (callable_info, i);
168         arg_type = g_arg_info_get_type (arg_info);
169         tag = g_type_info_get_tag (arg_type);
170         direction = g_arg_info_get_direction (arg_info);
171
172         if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
173             g_args[i].v_pointer = * (gpointer *) args[i];
174         } else {
175             switch (tag) {
176                 case GI_TYPE_TAG_BOOLEAN:
177                     g_args[i].v_boolean = * (gboolean *) args[i];
178                     break;
179                 case GI_TYPE_TAG_INT8:
180                     g_args[i].v_int8 = * (gint8 *) args[i];
181                     break;
182                 case GI_TYPE_TAG_UINT8:
183                     g_args[i].v_uint8 = * (guint8 *) args[i];
184                     break;
185                 case GI_TYPE_TAG_INT16:
186                     g_args[i].v_int16 = * (gint16 *) args[i];
187                     break;
188                 case GI_TYPE_TAG_UINT16:
189                     g_args[i].v_uint16 = * (guint16 *) args[i];
190                     break;
191                 case GI_TYPE_TAG_INT32:
192                     g_args[i].v_int32 = * (gint32 *) args[i];
193                     break;
194                 case GI_TYPE_TAG_UINT32:
195                     g_args[i].v_uint32 = * (guint32 *) args[i];
196                     break;
197                 case GI_TYPE_TAG_INT64:
198                     g_args[i].v_int64 = * (glong *) args[i];
199                     break;
200                 case GI_TYPE_TAG_UINT64:
201                     g_args[i].v_uint64 = * (glong *) args[i];
202                     break;
203                 case GI_TYPE_TAG_FLOAT:
204                     g_args[i].v_float = * (gfloat *) args[i];
205                     break;
206                 case GI_TYPE_TAG_DOUBLE:
207                     g_args[i].v_double = * (gdouble *) args[i];
208                     break;
209                 case GI_TYPE_TAG_UTF8:
210                     g_args[i].v_string = * (gchar **) args[i];
211                     break;
212                 case GI_TYPE_TAG_INTERFACE:
213                 {
214                     GIBaseInfo *interface;
215                     GIInfoType interface_type;
216
217                     interface = g_type_info_get_interface (arg_type);
218                     interface_type = g_base_info_get_type (interface);
219
220                     if (interface_type == GI_INFO_TYPE_OBJECT ||
221                             interface_type == GI_INFO_TYPE_INTERFACE) {
222                         g_args[i].v_pointer = * (gpointer *) args[i];
223                         g_base_info_unref (interface);
224                         break;
225                     } else if (interface_type == GI_INFO_TYPE_ENUM ||
226                                interface_type == GI_INFO_TYPE_FLAGS) {
227                         g_args[i].v_double = * (double *) args[i];
228                         g_base_info_unref (interface);
229                         break;
230                     } else if (interface_type == GI_INFO_TYPE_STRUCT ||
231                                interface_type == GI_INFO_TYPE_CALLBACK) {
232                         g_args[i].v_pointer = * (gpointer *) args[i];
233                         g_base_info_unref (interface);
234                         break;
235                     }
236
237                     g_base_info_unref (interface);
238                 }
239                 case GI_TYPE_TAG_ERROR:
240                 case GI_TYPE_TAG_GHASH:
241                 case GI_TYPE_TAG_GLIST:
242                 case GI_TYPE_TAG_GSLIST:
243                 case GI_TYPE_TAG_ARRAY:
244                 case GI_TYPE_TAG_VOID:
245                     g_args[i].v_pointer = * (gpointer *) args[i];
246                     break;
247                 default:
248                     g_warning ("Unhandled type tag %s", g_type_tag_to_string (tag));
249                     g_args[i].v_pointer = 0;
250             }
251         }
252         g_base_info_unref ( (GIBaseInfo *) arg_info);
253         g_base_info_unref ( (GIBaseInfo *) arg_type);
254     }
255     return g_args;
256 }
257
258 static gboolean
259 _pygi_closure_convert_arguments (GICallableInfo *callable_info, void **args,
260                                  void *user_data, PyObject **py_args,
261                                  GIArgument **out_args)
262 {
263     int n_args = g_callable_info_get_n_args (callable_info);
264     int n_in_args = 0;
265     int n_out_args = 0;
266     int i;
267     int user_data_arg = -1;
268     int destroy_notify_arg = -1;
269
270     GIArgument *g_args = NULL;
271
272     *py_args = NULL;
273     *py_args = PyTuple_New (n_args);
274     if (*py_args == NULL)
275         goto error;
276
277     *out_args = NULL;
278     *out_args = g_new0 (GIArgument, n_args);
279     g_args = _pygi_closure_convert_ffi_arguments (callable_info, args);
280
281     for (i = 0; i < n_args; i++) {
282         /* Special case callbacks and skip over userdata and Destroy Notify */
283         if (i == user_data_arg || i == destroy_notify_arg)
284             continue;
285
286         GIArgInfo *arg_info = g_callable_info_get_arg (callable_info, i);
287         GIDirection direction = g_arg_info_get_direction (arg_info);
288
289         if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
290             GITypeInfo *arg_type = g_arg_info_get_type (arg_info);
291             GITypeTag arg_tag = g_type_info_get_tag (arg_type);
292             GITransfer transfer = g_arg_info_get_ownership_transfer (arg_info);
293             PyObject *value;
294             GIArgument *arg;
295             gboolean free_array = FALSE;
296
297             if (direction == GI_DIRECTION_IN && arg_tag == GI_TYPE_TAG_VOID &&
298                     g_type_info_is_pointer (arg_type)) {
299
300                 if (user_data == NULL) {
301                     Py_INCREF (Py_None);
302                     value = Py_None;
303                 } else {
304                     value = user_data;
305                     Py_INCREF (value);
306                 }
307             } else if (direction == GI_DIRECTION_IN &&
308                        arg_tag == GI_TYPE_TAG_INTERFACE) {
309                 /* Handle callbacks as a special case */
310                 GIBaseInfo *info;
311                 GIInfoType info_type;
312
313                 info = g_type_info_get_interface (arg_type);
314                 info_type = g_base_info_get_type (info);
315
316                 arg = (GIArgument*) &g_args[i];
317
318                 if (info_type == GI_INFO_TYPE_CALLBACK) {
319                     gpointer user_data = NULL;
320                     GDestroyNotify destroy_notify = NULL;
321                     GIScopeType scope = g_arg_info_get_scope(arg_info);
322
323                     user_data_arg = g_arg_info_get_closure(arg_info);
324                     destroy_notify_arg = g_arg_info_get_destroy(arg_info);
325
326                     if (user_data_arg != -1)
327                         user_data = g_args[user_data_arg].v_pointer;
328
329                     if (destroy_notify_arg != -1)
330                         user_data = (GDestroyNotify) g_args[destroy_notify_arg].v_pointer;
331
332                     value = _pygi_ccallback_new(arg->v_pointer,
333                                                 user_data,
334                                                 scope,
335                                                 (GIFunctionInfo *) info,
336                                                 destroy_notify);
337                 } else
338                     value = _pygi_argument_to_object (arg, arg_type, transfer);
339
340                 g_base_info_unref (info);
341                 if (value == NULL) {
342                     g_base_info_unref (arg_type);
343                     g_base_info_unref (arg_info);
344                     goto error;
345                 }
346             } else {
347                 if (direction == GI_DIRECTION_IN)
348                     arg = (GIArgument*) &g_args[i];
349                 else
350                     arg = (GIArgument*) g_args[i].v_pointer;
351                 
352                 if (g_type_info_get_tag (arg_type) == GI_TYPE_TAG_ARRAY)
353                     arg->v_pointer = _pygi_argument_to_array (arg, (GIArgument **) args, 
354                                                               callable_info, arg_type, &free_array);
355
356                 value = _pygi_argument_to_object (arg, arg_type, transfer);
357                 
358                 if (free_array)
359                     g_array_free (arg->v_pointer, FALSE);
360                 
361                 if (value == NULL) {
362                     g_base_info_unref (arg_type);
363                     g_base_info_unref (arg_info);
364                     goto error;
365                 }
366             }
367             PyTuple_SET_ITEM (*py_args, n_in_args, value);
368             n_in_args++;
369
370             g_base_info_unref (arg_type);
371         }
372
373         if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
374             (*out_args) [n_out_args] = g_args[i];
375             n_out_args++;
376         }
377
378         g_base_info_unref (arg_info);
379     }
380
381     if (_PyTuple_Resize (py_args, n_in_args) == -1)
382         goto error;
383
384     g_free (g_args);
385     return TRUE;
386
387 error:
388     Py_CLEAR (*py_args);
389     g_free (*out_args);
390     *out_args = NULL;
391     g_free (g_args);
392
393     return FALSE;
394 }
395
396 static void
397 _pygi_closure_set_out_arguments (GICallableInfo *callable_info,
398                                  PyObject *py_retval, GIArgument *out_args,
399                                  void *resp)
400 {
401     int n_args, i, i_py_retval, i_out_args;
402     GITypeInfo *return_type_info;
403     GITypeTag return_type_tag;
404
405     i_py_retval = 0;
406     return_type_info = g_callable_info_get_return_type (callable_info);
407     return_type_tag = g_type_info_get_tag (return_type_info);
408     if (return_type_tag != GI_TYPE_TAG_VOID) {
409         GITransfer transfer = g_callable_info_get_caller_owns (callable_info);
410         if (PyTuple_Check (py_retval)) {
411             PyObject *item = PyTuple_GET_ITEM (py_retval, 0);
412             _pygi_closure_assign_pyobj_to_retval (resp, item,
413                 return_type_info, transfer);
414         } else {
415             _pygi_closure_assign_pyobj_to_retval (resp, py_retval,
416                 return_type_info, transfer);
417         }
418         i_py_retval++;
419     }
420     g_base_info_unref (return_type_info);
421
422     i_out_args = 0;
423     n_args = g_callable_info_get_n_args (callable_info);
424     for (i = 1; i < n_args; i++) {
425         GIArgInfo *arg_info = g_callable_info_get_arg (callable_info, i);
426         GITypeInfo *type_info = g_arg_info_get_type (arg_info);
427         GIDirection direction = g_arg_info_get_direction (arg_info);
428
429         if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
430             GITransfer transfer = g_arg_info_get_ownership_transfer (arg_info);
431
432             if (g_type_info_get_tag (type_info) == GI_TYPE_TAG_ERROR) {
433                 /* TODO: check if an exception has been set and convert it to a GError */
434                 out_args[i_out_args].v_pointer = NULL;
435                 i_out_args++;
436                 continue;
437             }
438
439             if (PyTuple_Check (py_retval)) {
440                 PyObject *item = PyTuple_GET_ITEM (py_retval, i_py_retval);
441                 _pygi_closure_assign_pyobj_to_out_argument (
442                     out_args[i_out_args].v_pointer, item, type_info, transfer);
443             } else if (i_py_retval == 0) {
444                 _pygi_closure_assign_pyobj_to_out_argument (
445                     out_args[i_out_args].v_pointer, py_retval, type_info,
446                     transfer);
447             } else
448                 g_assert_not_reached();
449
450             i_out_args++;
451             i_py_retval++;
452         }
453         g_base_info_unref (type_info);
454         g_base_info_unref (arg_info);
455     }
456 }
457
458 void
459 _pygi_closure_handle (ffi_cif *cif,
460                       void    *result,
461                       void   **args,
462                       void    *data)
463 {
464     PyGILState_STATE state;
465     PyGICClosure *closure = data;
466     PyObject *retval;
467     PyObject *py_args;
468     GIArgument *out_args = NULL;
469
470     /* Lock the GIL as we are coming into this code without the lock and we
471       may be executing python code */
472     state = PyGILState_Ensure();
473
474     if (!_pygi_closure_convert_arguments ( (GICallableInfo *) closure->info, args,
475                                            closure->user_data,
476                                            &py_args, &out_args)) {
477         if (PyErr_Occurred ())
478             PyErr_Print();
479         goto end;
480     }
481
482     retval = PyObject_CallObject ( (PyObject *) closure->function, py_args);
483     Py_DECREF (py_args);
484
485     if (retval == NULL) {
486         PyErr_Print();
487         goto end;
488     }
489
490     _pygi_closure_set_out_arguments (closure->info, retval, out_args, result);
491
492 end:
493     g_free (out_args);
494
495     PyGILState_Release (state);
496
497     /* Now that the closure has finished we can make a decision about how
498        to free it.  Scope call gets free'd at the end of wrap_g_function_info_invoke
499        scope notified will be freed,  when the notify is called and we can free async
500        anytime we want as long as its after we return from this function (you can't free the closure
501        you are currently using!)
502     */
503     switch (closure->scope) {
504         case GI_SCOPE_TYPE_CALL:
505         case GI_SCOPE_TYPE_NOTIFIED:
506             break;
507         case GI_SCOPE_TYPE_ASYNC:
508             /* Append this PyGICClosure to a list of closure that we will free
509                after we're done with this function invokation */
510             async_free_list = g_slist_prepend (async_free_list, closure);
511             break;
512         default:
513             g_error ("Invalid scope reached inside %s.  Possibly a bad annotation?",
514                      g_base_info_get_name (closure->info));
515     }
516 }
517
518 void _pygi_invoke_closure_free (gpointer data)
519 {
520     PyGILState_STATE state;
521     PyGICClosure* invoke_closure = (PyGICClosure *) data;
522
523     state = PyGILState_Ensure();
524     Py_DECREF (invoke_closure->function);
525
526     g_callable_info_free_closure (invoke_closure->info,
527                                   invoke_closure->closure);
528
529     if (invoke_closure->info)
530         g_base_info_unref ( (GIBaseInfo*) invoke_closure->info);
531
532     Py_XDECREF (invoke_closure->user_data);
533     PyGILState_Release (state);
534
535     g_slice_free (PyGICClosure, invoke_closure);
536 }
537
538
539 PyGICClosure*
540 _pygi_make_native_closure (GICallableInfo* info,
541                            GIScopeType scope,
542                            PyObject *py_function,
543                            gpointer py_user_data)
544 {
545     PyGICClosure *closure;
546     ffi_closure *fficlosure;
547
548     /* Begin by cleaning up old async functions */
549     g_slist_free_full (async_free_list, (GDestroyNotify) _pygi_invoke_closure_free);
550     async_free_list = NULL;
551
552     /* Build the closure itself */
553     closure = g_slice_new0 (PyGICClosure);
554     closure->info = (GICallableInfo *) g_base_info_ref ( (GIBaseInfo *) info);
555     closure->function = py_function;
556     closure->user_data = py_user_data;
557
558     Py_INCREF (py_function);
559     if (closure->user_data)
560         Py_INCREF (closure->user_data);
561
562     fficlosure =
563         g_callable_info_prepare_closure (info, &closure->cif, _pygi_closure_handle,
564                                          closure);
565     closure->closure = fficlosure;
566
567     /* Give the closure the information it needs to determine when
568        to free itself later */
569     closure->scope = scope;
570
571     return closure;
572 }