void
_pygi_marshal_cleanup_from_py_interface_callback (PyGIInvokeState *state,
                                                  PyGIArgCache    *arg_cache,
                                                  PyObject        *py_arg,
                                                  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 (data);
    }
}
Exemple #2
0
static void
_pygi_destroy_notify_callback_closure (ffi_cif *cif,
                                       void *result,
                                       void **args,
                                       void *data)
{
    PyGICClosure *info = * (void**) (args[0]);

    g_assert (info);

    _pygi_invoke_closure_free (info);
}
Exemple #3
0
void
_pygi_closure_handle (ffi_cif *cif,
                      void    *result,
                      void   **args,
                      void    *data)
{
    PyGILState_STATE state;
    PyGICClosure *closure = data;
    gint n_args, i;
    GIArgInfo  *arg_info;
    GIDirection arg_direction;
    GITypeInfo *arg_type;
    GITransfer arg_transfer;
    GITypeTag  arg_tag;
    GITypeTag  return_tag;
    GITransfer return_transfer;
    GITypeInfo *return_type;
    PyObject *retval;
    PyObject *py_args;
    PyObject *pyarg;
    gint n_in_args, n_out_args;


    /* Lock the GIL as we are coming into this code without the lock and we
      may be executing python code */
    state = PyGILState_Ensure();

    return_type = g_callable_info_get_return_type(closure->info);
    return_tag = g_type_info_get_tag(return_type);
    return_transfer = g_callable_info_get_caller_owns(closure->info);

    n_args = g_callable_info_get_n_args (closure->info);

    py_args = PyTuple_New(n_args);
    if (py_args == NULL) {
        PyErr_Clear();
        goto end;
    }

    n_in_args = 0;

    for (i = 0; i < n_args; i++) {
        arg_info = g_callable_info_get_arg (closure->info, i);
        arg_type = g_arg_info_get_type (arg_info);
        arg_transfer = g_arg_info_get_ownership_transfer(arg_info);
        arg_tag = g_type_info_get_tag(arg_type);
        arg_direction = g_arg_info_get_direction(arg_info);
        switch (arg_tag) {
        case GI_TYPE_TAG_VOID:
        {
            if (g_type_info_is_pointer(arg_type)) {
                if (PyTuple_SetItem(py_args, n_in_args, closure->user_data) != 0) {
                    PyErr_Clear();
                    goto end;
                }
                n_in_args++;
                continue;
            }
        }
        case GI_TYPE_TAG_ERROR:
        {
            continue;
        }
        default:
        {
            pyarg = _pygi_argument_to_object (args[i],
                                              arg_type,
                                              arg_transfer);

            if(PyTuple_SetItem(py_args, n_in_args, pyarg) != 0) {
                PyErr_Clear();
                goto end;
            }
            n_in_args++;
            g_base_info_unref((GIBaseInfo*)arg_info);
            g_base_info_unref((GIBaseInfo*)arg_type);
        }
        }

    }

    if(_PyTuple_Resize (&py_args, n_in_args) != 0) {
        PyErr_Clear();
        goto end;
    }

    retval = PyObject_CallObject((PyObject *)closure->function, py_args);

    Py_DECREF(py_args);

    if (retval == NULL) {
        goto end;
    }

    *(GArgument*)result = _pygi_argument_from_object(retval, return_type, return_transfer);

end:
    g_base_info_unref((GIBaseInfo*)return_type);

    PyGILState_Release(state);

    if (closure->user_data)
        Py_XDECREF(closure->user_data);

    /* Now that the closure has finished we can make a decision about how
       to free it.  Scope call gets free'd now, scope notified will be freed
       when the notify is called and we can free async anytime we want
       once we return from this function */
    switch (closure->scope) {
    case GI_SCOPE_TYPE_CALL:
        _pygi_invoke_closure_free(closure);
        break;
    case GI_SCOPE_TYPE_NOTIFIED:
        break;
    case GI_SCOPE_TYPE_ASYNC:
        /* Append this PyGICClosure to a list of closure that we will free
           after we're done with this function invokation */
        async_free_list = g_slist_prepend(async_free_list, closure);
        break;
    default:
        g_assert_not_reached();
    }
}
Exemple #4
0
static gboolean
_pygi_marshal_from_py_interface_callback (PyGIInvokeState   *state,
                                          PyGICallableCache *callable_cache,
                                          PyGIArgCache      *arg_cache,
                                          PyObject          *py_arg,
                                          GIArgument        *arg,
                                          gpointer          *cleanup_data)
{
    GICallableInfo *callable_info;
    PyGICClosure *closure;
    PyGIArgCache *user_data_cache = NULL;
    PyGIArgCache *destroy_cache = NULL;
    PyGICallbackCache *callback_cache;
    PyObject *py_user_data = NULL;

    callback_cache = (PyGICallbackCache *)arg_cache;

    if (callback_cache->user_data_index > 0) {
        user_data_cache = _pygi_callable_cache_get_arg (callable_cache, callback_cache->user_data_index);
        if (user_data_cache->py_arg_index < state->n_py_in_args) {
            /* py_user_data is a borrowed reference. */
            py_user_data = PyTuple_GetItem (state->py_in_args, user_data_cache->py_arg_index);
            if (!py_user_data)
                return FALSE;
            /* NULL out user_data if it was not supplied and the default arg placeholder
             * was used instead.
             */
            if (py_user_data == _PyGIDefaultArgPlaceholder) {
                py_user_data = NULL;
            } else if (callable_cache->user_data_varargs_index < 0) {
                /* For non-variable length user data, place the user data in a
                 * single item tuple which is concatenated to the callbacks arguments.
                 * This allows callback input arg marshaling to always expect a
                 * tuple for user data. Note the
                 */
                py_user_data = Py_BuildValue("(O)", py_user_data, NULL);
            } else {
                /* increment the ref borrowed from PyTuple_GetItem above */
                Py_INCREF (py_user_data);
            }
        }
    }

    if (py_arg == Py_None) {
        return TRUE;
    }

    if (!PyCallable_Check (py_arg)) {
        PyErr_Format (PyExc_TypeError,
                      "Callback needs to be a function or method not %s",
                      py_arg->ob_type->tp_name);

        return FALSE;
    }

    callable_info = (GICallableInfo *)callback_cache->interface_info;

    closure = _pygi_make_native_closure (callable_info, callback_cache->scope, py_arg, py_user_data);
    arg->v_pointer = closure->closure;

    /* always decref the user data as _pygi_make_native_closure adds its own ref */
    Py_XDECREF (py_user_data);

    /* The PyGICClosure instance is used as user data passed into the C function.
     * The return trip to python will marshal this back and pull the python user data out.
     */
    if (user_data_cache != NULL) {
        state->args[user_data_cache->c_arg_index].arg_value.v_pointer = closure;
    }

    /* Setup a GDestroyNotify callback if this method supports it along with
     * a user data field. The user data field is a requirement in order
     * free resources and ref counts associated with this arguments closure.
     * In case a user data field is not available, show a warning giving
     * explicit information and setup a dummy notification to avoid a crash
     * later on in _pygi_destroy_notify_callback_closure.
     */
    if (callback_cache->destroy_notify_index > 0) {
        destroy_cache = _pygi_callable_cache_get_arg (callable_cache, callback_cache->destroy_notify_index);
    }

    if (destroy_cache) {
        if (user_data_cache != NULL) {
            state->args[destroy_cache->c_arg_index].arg_value.v_pointer = _pygi_invoke_closure_free;
        } else {
            char *full_name = pygi_callable_cache_get_full_name (callable_cache);
            gchar *msg = g_strdup_printf("Callables passed to %s will leak references because "
                                         "the method does not support a user_data argument. "
                                         "See: https://bugzilla.gnome.org/show_bug.cgi?id=685598",
                                         full_name);
            g_free (full_name);
            if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 2)) {
                g_free(msg);
                _pygi_invoke_closure_free(closure);
                return FALSE;
            }
            g_free(msg);
            state->args[destroy_cache->c_arg_index].arg_value.v_pointer = _pygi_destroy_notify_dummy;
        }
    }

    /* Use the PyGIClosure as data passed to cleanup for GI_SCOPE_TYPE_CALL. */
    *cleanup_data = closure;

    return TRUE;
}