Пример #1
0
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;
}
Пример #2
0
void
_pygi_closure_handle (ffi_cif *cif,
                      void    *result,
                      void   **args,
                      void    *data)
{
    PyGILState_STATE py_state;
    PyGICClosure *closure = data;
    PyObject *retval;
    gboolean success;
    PyGIInvokeState state = { 0, };

    /* Ignore closures when Python is not initialized. This can happen in cases
     * where calling Python implemented vfuncs can happen at shutdown time.
     * See: https://bugzilla.gnome.org/show_bug.cgi?id=722562 */
    if (!Py_IsInitialized()) {
        return;
    }

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

    if (closure->cache == NULL) {
        closure->cache = pygi_closure_cache_new ((GICallableInfo *) closure->info);

        if (closure->cache == NULL)
            goto end;
    }

    state.user_data = closure->user_data;

    _invoke_state_init_from_cache (&state, closure->cache, args);

    if (!_pygi_closure_convert_arguments (&state, closure->cache)) {
        _pygi_closure_clear_retvals (&state, closure->cache, result);
        goto end;
    }

    retval = PyObject_CallObject ( (PyObject *) closure->function, state.py_in_args);

    if (retval == NULL) {
        _pygi_closure_clear_retvals (&state, closure->cache, result);
        goto end;
    }

    pygi_marshal_cleanup_args_to_py_marshal_success (&state, closure->cache);
    success = _pygi_closure_set_out_arguments (&state, closure->cache, retval, result);

    if (!success) {
        pygi_marshal_cleanup_args_from_py_marshal_success (&state, closure->cache);
        _pygi_closure_clear_retvals (&state, closure->cache, result);
    }

    Py_DECREF (retval);

end:

    if (PyErr_Occurred ())
        PyErr_Print ();

    /* Now that the closure has finished we can make a decision about how
       to free it.  Scope call gets free'd at the end of wrap_g_function_info_invoke.
       Scope notified will be freed when the notify is called.
       Scope async closures free only their python data now and the closure later
       during the next creation of a closure. This minimizes potential ref leaks
       at least in regards to the python objects.
       (you can't free the closure you are currently using!)
    */
    switch (closure->scope) {
        case GI_SCOPE_TYPE_CALL:
        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 */
            _pygi_invoke_closure_clear_py_data(closure);
            async_free_list = g_slist_prepend (async_free_list, closure);
            break;
        default:
            g_error ("Invalid scope reached inside %s.  Possibly a bad annotation?",
                     g_base_info_get_name (closure->info));
    }

    _invoke_state_clear (&state);
    PyGILState_Release (py_state);
}