PyObject * pygi_invoke_c_callable (PyGIFunctionCache *function_cache, PyGIInvokeState *state, PyObject *py_args, PyObject *py_kwargs) { PyGICallableCache *cache = (PyGICallableCache *) function_cache; GIFFIReturnValue ffi_return_value = {0}; PyObject *ret = NULL; if (!_invoke_state_init_from_cache (state, function_cache, py_args, py_kwargs)) goto err; if (!_invoke_marshal_in_args (state, function_cache)) goto err; Py_BEGIN_ALLOW_THREADS; ffi_call (&function_cache->invoker.cif, state->function_ptr, (void *) &ffi_return_value, (void **) state->ffi_args); Py_END_ALLOW_THREADS; /* If the callable throws, the address of state->error will be bound into * the state->args as the last value. When the callee sets an error using * the state->args passed, it will have the side effect of setting * state->error allowing for easy checking here. */ if (state->error != NULL) { if (pygi_error_check (&state->error)) { /* even though we errored out, the call itself was successful, so we assume the call processed all of the parameters */ pygi_marshal_cleanup_args_from_py_marshal_success (state, cache); goto err; } } if (cache->return_cache) { gi_type_info_extract_ffi_return_value (cache->return_cache->type_info, &ffi_return_value, &state->return_arg); } ret = _invoke_marshal_out_args (state, function_cache); pygi_marshal_cleanup_args_from_py_marshal_success (state, cache); if (ret != NULL) pygi_marshal_cleanup_args_to_py_marshal_success (state, cache); err: _invoke_state_clear (state, function_cache); return ret; }
/** * g_callable_info_invoke: * @info: TODO * @function: TODO * @in_args: TODO * @n_in_args: TODO * @out_args: TODO * @n_out_args: TODO * @return_value: TODO * @is_method: TODO * @throws: TODO * @error: TODO * * TODO */ gboolean g_callable_info_invoke (GIFunctionInfo *info, gpointer function, const GIArgument *in_args, int n_in_args, const GIArgument *out_args, int n_out_args, GIArgument *return_value, gboolean is_method, gboolean throws, GError **error) { ffi_cif cif; ffi_type *rtype; ffi_type **atypes; GITypeInfo *tinfo; GITypeInfo *rinfo; GITypeTag rtag; GIArgInfo *ainfo; gint n_args, n_invoke_args, in_pos, out_pos, i; gpointer *args; gboolean success = FALSE; GError *local_error = NULL; gpointer error_address = &local_error; GIFFIReturnValue ffi_return_value; gpointer return_value_p; /* Will point inside the union return_value */ rinfo = g_callable_info_get_return_type ((GICallableInfo *)info); rtype = g_type_info_get_ffi_type (rinfo); rtag = g_type_info_get_tag(rinfo); in_pos = 0; out_pos = 0; n_args = g_callable_info_get_n_args ((GICallableInfo *)info); if (is_method) { if (n_in_args == 0) { g_set_error (error, G_INVOKE_ERROR, G_INVOKE_ERROR_ARGUMENT_MISMATCH, "Too few \"in\" arguments (handling this)"); goto out; } n_invoke_args = n_args+1; in_pos++; } else n_invoke_args = n_args; if (throws) /* Add an argument for the GError */ n_invoke_args ++; atypes = g_alloca (sizeof (ffi_type*) * n_invoke_args); args = g_alloca (sizeof (gpointer) * n_invoke_args); if (is_method) { atypes[0] = &ffi_type_pointer; args[0] = (gpointer) &in_args[0]; } for (i = 0; i < n_args; i++) { int offset = (is_method ? 1 : 0); ainfo = g_callable_info_get_arg ((GICallableInfo *)info, i); switch (g_arg_info_get_direction (ainfo)) { case GI_DIRECTION_IN: tinfo = g_arg_info_get_type (ainfo); atypes[i+offset] = g_type_info_get_ffi_type (tinfo); g_base_info_unref ((GIBaseInfo *)tinfo); if (in_pos >= n_in_args) { g_set_error (error, G_INVOKE_ERROR, G_INVOKE_ERROR_ARGUMENT_MISMATCH, "Too few \"in\" arguments (handling in)"); goto out; } args[i+offset] = (gpointer)&in_args[in_pos]; in_pos++; break; case GI_DIRECTION_OUT: atypes[i+offset] = &ffi_type_pointer; if (out_pos >= n_out_args) { g_set_error (error, G_INVOKE_ERROR, G_INVOKE_ERROR_ARGUMENT_MISMATCH, "Too few \"out\" arguments (handling out)"); goto out; } args[i+offset] = (gpointer)&out_args[out_pos]; out_pos++; break; case GI_DIRECTION_INOUT: atypes[i+offset] = &ffi_type_pointer; if (in_pos >= n_in_args) { g_set_error (error, G_INVOKE_ERROR, G_INVOKE_ERROR_ARGUMENT_MISMATCH, "Too few \"in\" arguments (handling inout)"); goto out; } if (out_pos >= n_out_args) { g_set_error (error, G_INVOKE_ERROR, G_INVOKE_ERROR_ARGUMENT_MISMATCH, "Too few \"out\" arguments (handling inout)"); goto out; } args[i+offset] = (gpointer)&in_args[in_pos]; in_pos++; out_pos++; break; default: g_assert_not_reached (); } g_base_info_unref ((GIBaseInfo *)ainfo); } if (throws) { args[n_invoke_args - 1] = &error_address; atypes[n_invoke_args - 1] = &ffi_type_pointer; } if (in_pos < n_in_args) { g_set_error (error, G_INVOKE_ERROR, G_INVOKE_ERROR_ARGUMENT_MISMATCH, "Too many \"in\" arguments (at end)"); goto out; } if (out_pos < n_out_args) { g_set_error (error, G_INVOKE_ERROR, G_INVOKE_ERROR_ARGUMENT_MISMATCH, "Too many \"out\" arguments (at end)"); goto out; } if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_invoke_args, rtype, atypes) != FFI_OK) goto out; g_return_val_if_fail (return_value, FALSE); /* See comment for GIFFIReturnValue above */ switch (rtag) { case GI_TYPE_TAG_FLOAT: return_value_p = &ffi_return_value.v_float; break; case GI_TYPE_TAG_DOUBLE: return_value_p = &ffi_return_value.v_double; break; case GI_TYPE_TAG_INT64: case GI_TYPE_TAG_UINT64: return_value_p = &ffi_return_value.v_uint64; break; default: return_value_p = &ffi_return_value.v_long; } ffi_call (&cif, function, return_value_p, args); if (local_error) { g_propagate_error (error, local_error); success = FALSE; } else { gi_type_info_extract_ffi_return_value (rinfo, &ffi_return_value, return_value); success = TRUE; } out: g_base_info_unref ((GIBaseInfo *)rinfo); return success; }