Commit 12aa4e63 authored by John (J5) Palmieri's avatar John (J5) Palmieri

[gi-invoke-ng] create new framework for cleaning up args

* we now have a state machine so we know what point in the marshalling process
  we are and which args need to be cleaned up
* call the cleanup functions after invoking the gi callable, after marshalling
  the out parameters and at any time an error occures
parent 1d64c3d3
......@@ -64,7 +64,9 @@ _gi_la_SOURCES += \
pygi-cache.h \
pygi-cache.c \
pygi-marshal.c \
pygi-marshal.h
pygi-marshal.h \
pygi-marshal-cleanup.c \
pygi-marshal-cleanup.h
else
_gi_la_SOURCES += \
pygi-invoke.c
......
......@@ -22,6 +22,7 @@
#include "pygi-info.h"
#include "pygi-cache.h"
#include "pygi-marshal.h"
#include "pygi-marshal-cleanup.h"
#include "pygi-type.h"
#include <girepository.h>
......@@ -540,7 +541,7 @@ _arg_cache_out_array_setup (PyGIArgCache *arg_cache,
if (seq_cache->len_arg_index >= 0) {
PyGIArgCache *aux_cache = callable_cache->args_cache[seq_cache->len_arg_index];
if (seq_cache->len_argindex < arg_index)
if (seq_cache->len_arg_index < arg_index)
callable_cache->n_out_aux_args++;
if (aux_cache != NULL) {
......@@ -637,11 +638,6 @@ _arg_cache_out_interface_union_setup (PyGIArgCache *arg_cache,
arg_cache->out_marshaller = _pygi_marshal_out_interface_struct;
}
static void
_g_slice_free_gvalue_func (GValue *value) {
g_slice_free (GValue, value);
}
static inline void
_arg_cache_in_interface_struct_setup (PyGIArgCache *arg_cache,
GIInterfaceInfo *iface_info,
......@@ -650,10 +646,12 @@ _arg_cache_in_interface_struct_setup (PyGIArgCache *arg_cache,
PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
arg_cache->in_marshaller = _pygi_marshal_in_interface_struct;
if (iface_cache->g_type == G_TYPE_VALUE)
arg_cache->cleanup = _g_slice_free_gvalue_func;
if (iface_cache->g_type == G_TYPE_VALUE &&
arg_cache->transfer == GI_TRANSFER_NOTHING &&
arg_cache->direction == GI_DIRECTION_IN)
arg_cache->cleanup = _pygi_marshal_cleanup_gvalue;
if (iface_cache->g_type == G_TYPE_CLOSURE)
arg_cache->cleanup = g_closure_unref;
arg_cache->cleanup = _pygi_marshal_cleanup_closure_unref;
}
static inline void
......@@ -664,6 +662,11 @@ _arg_cache_out_interface_struct_setup (PyGIArgCache *arg_cache,
PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache;
iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info);
arg_cache->out_marshaller = _pygi_marshal_out_interface_struct;
if (iface_cache->g_type == G_TYPE_VALUE &&
arg_cache->transfer != GI_TRANSFER_NOTHING &&
arg_cache->direction == GI_DIRECTION_OUT)
arg_cache->cleanup = _pygi_marshal_cleanup_gvalue;
}
static inline void
......@@ -671,8 +674,6 @@ _arg_cache_in_interface_object_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->in_marshaller = _pygi_marshal_in_interface_object;
if (transfer == GI_TRANSFER_EVERYTHING)
arg_cache->cleanup = (GDestroyNotify)g_object_unref;
}
static inline void
......@@ -680,6 +681,8 @@ _arg_cache_out_interface_object_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->out_marshaller = _pygi_marshal_out_interface_object;
if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
arg_cache->cleanup = _pygi_marshal_cleanup_object_unref;
}
static inline void
......
......@@ -44,6 +44,9 @@ typedef PyObject *(*PyGIMarshalOutFunc) (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
GIArgument *arg);
typedef void (*PyGIMarshalCleanupFunc) (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer *data);
typedef enum {
/* Not an AUX type */
PYGI_AUX_TYPE_NONE = 0,
......@@ -68,8 +71,8 @@ struct _PyGIArgCache
PyGIMarshalInFunc in_marshaller;
PyGIMarshalOutFunc out_marshaller;
GDestroyNotify cleanup;
PyGIMarshalCleanupFunc cleanup;
GDestroyNotify destroy_notify;
gssize c_arg_index;
......
......@@ -84,6 +84,7 @@ _invoke_state_init_from_callable_cache (PyGIInvokeState *state,
PyObject *py_args,
PyObject *kwargs)
{
state->stage = PYGI_INVOKE_STAGE_MARSHAL_IN_START;
state->py_in_args = py_args;
state->n_py_in_args = PySequence_Length (py_args);
......@@ -192,6 +193,8 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache)
PyGIArgCache *arg_cache = cache->args_cache[i];
PyObject *py_arg = NULL;
state->current_arg = in_count;
state->stage = PYGI_INVOKE_STAGE_MARSHAL_IN_START;
switch (arg_cache->direction) {
case GI_DIRECTION_IN:
state->args[i] = &(state->in_args[in_count]);
......@@ -290,6 +293,8 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache)
c_arg);
if (!success)
return FALSE;
state->stage = PYGI_INVOKE_STAGE_MARSHAL_IN_IDLE;
}
}
......@@ -305,7 +310,10 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache)
int total_out_args = cache->n_out_args;
gboolean has_return = FALSE;
state->current_arg = 0;
if (cache->return_cache) {
state->stage = PYGI_INVOKE_STAGE_MARSHAL_RETURN_START;
if (cache->is_constructor) {
if (state->return_arg.v_pointer == NULL) {
PyErr_SetString (PyExc_TypeError, "constructor returned NULL");
......@@ -320,6 +328,8 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache)
if (py_return == NULL)
return NULL;
state->stage = PYGI_INVOKE_STAGE_MARSHAL_RETURN_DONE;
if (cache->return_cache->type_tag != GI_TYPE_TAG_VOID) {
total_out_args++;
has_return = TRUE;
......@@ -332,13 +342,17 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache)
py_out = py_return;
} else if (total_out_args == 1) {
/* if we get here there is one out arg an no return */
state->stage = PYGI_INVOKE_STAGE_MARSHAL_OUT_START;
PyGIArgCache *arg_cache = (PyGIArgCache *)cache->out_args->data;
py_out = arg_cache->out_marshaller (state,
cache,
arg_cache,
state->args[arg_cache->c_arg_index]);
if (py_out == NULL)
return NULL;
state->stage = PYGI_INVOKE_STAGE_MARSHAL_OUT_IDLE;
} else {
int out_cache_index = 0;
int py_arg_index = 0;
GSList *cache_item = cache->out_args;
/* return a tuple */
......@@ -350,13 +364,19 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache)
for(; py_arg_index < total_out_args; py_arg_index++) {
PyGIArgCache *arg_cache = (PyGIArgCache *)cache_item->data;
state->stage = PYGI_INVOKE_STAGE_MARSHAL_OUT_START;
PyObject *py_obj = arg_cache->out_marshaller (state,
cache,
arg_cache,
state->args[arg_cache->c_arg_index]);
if (py_obj == NULL)
if (py_obj == NULL) {
Py_DECREF (py_out);
return NULL;
}
state->current_arg++;
state->stage = PYGI_INVOKE_STAGE_MARSHAL_OUT_IDLE;
PyTuple_SET_ITEM (py_out, py_arg_index, py_obj);
cache_item = cache_item->next;
......@@ -371,7 +391,7 @@ _wrap_g_callable_info_invoke (PyGIBaseInfo *self,
PyObject *kwargs)
{
PyGIInvokeState state = { 0, };
PyObject *ret;
PyObject *ret = NULL;
if (self->cache == NULL) {
self->cache = _pygi_callable_cache_new (self->info);
......@@ -386,11 +406,13 @@ _wrap_g_callable_info_invoke (PyGIBaseInfo *self,
if (!_invoke_callable (&state, self->cache, self->info))
goto err;
pygi_marshal_cleanup_args (&state, self->cache);
ret = _invoke_marshal_out_args (&state, self->cache);
_invoke_state_clear (&state, self->cache);
return ret;
state.stage = PYGI_INVOKE_STAGE_DONE;
err:
pygi_marshal_cleanup_args (&state, self->cache);
_invoke_state_clear (&state, self->cache);
return NULL;
return ret;
}
......@@ -7,11 +7,24 @@
G_BEGIN_DECLS
typedef enum {
PYGI_INVOKE_STAGE_MARSHAL_IN_START,
PYGI_INVOKE_STAGE_MARSHAL_IN_IDLE,
PYGI_INVOKE_STAGE_MARSHAL_RETURN_START,
PYGI_INVOKE_STAGE_MARSHAL_RETURN_DONE,
PYGI_INVOKE_STAGE_MARSHAL_OUT_START,
PYGI_INVOKE_STAGE_MARSHAL_OUT_IDLE,
PYGI_INVOKE_STAGE_DONE
} PyGIInvokeStage;
typedef struct _PyGIInvokeState
{
PyObject *py_in_args;
PyObject *constructor_class;
gssize n_py_in_args;
gssize current_arg;
PyGIInvokeStage stage;
GType implementor_gtype;
......
/* -*- Mode: C; c-basic-offset: 4 -*-
* vim: tabstop=4 shiftwidth=4 expandtab
*
* Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "pygi-marshal-cleanup.h"
#include <glib.h>
void
pygi_marshal_cleanup_args (PyGIInvokeState *state,
PyGICallableCache *cache)
{
switch (state->stage) {
case PYGI_INVOKE_STAGE_MARSHAL_IN_IDLE:
/* current_arg has been marshalled so increment to start with
next arg */
state->current_arg++;
case PYGI_INVOKE_STAGE_MARSHAL_IN_START:
/* we have not yet invoked so we only need to clean up
the in args */
break;
case PYGI_INVOKE_STAGE_MARSHAL_OUT_START:
/* we have not yet marshalled so decrement to end with previous
arg */
state->current_arg--;
case PYGI_INVOKE_STAGE_MARSHAL_OUT_IDLE:
case PYGI_INVOKE_STAGE_DONE:
/* In args should have already been cleaned up so only cleanup
out args */
case PYGI_INVOKE_STAGE_MARSHAL_RETURN_DONE:
break;
case PYGI_INVOKE_STAGE_MARSHAL_RETURN_START:
break;
}
}
void
_pygi_marshal_cleanup_gvalue (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data)
{
/*
if (arg_cache->direction == GI_DIRECTION_IN)
if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
g_slice_free (GValue, data);
*/
}
void
_pygi_marshal_cleanup_closure_unref (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data)
{
g_closure_unref ( (GClosure *)data);
}
void
_pygi_marshal_cleanup_object_unref (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data)
{
g_object_unref ( (GObject *)data);
}
/* -*- Mode: C; c-basic-offset: 4 -*-
* vim: tabstop=4 shiftwidth=4 expandtab
*
* Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#ifndef __PYGI_MARSHAL_CLEANUP_H__
#define __PYGI_MARSHAL_CLEANUP_H__
#include "pygi-private.h"
G_BEGIN_DECLS
void pygi_marshal_cleanup_args (PyGIInvokeState *state,
PyGICallableCache *cache);
void _pygi_marshal_cleanup_gvalue (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data);
void _pygi_marshal_cleanup_closure_unref (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data);
void _pygi_marshal_cleanup_object_unref (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data);
G_END_DECLS
#endif /* __PYGI_MARSHAL_CLEANUP_H__ */
......@@ -31,6 +31,7 @@
#include <pyglib-python-compat.h>
#include "pygi-cache.h"
#include "pygi-marshal-cleanup.h"
/*** argument marshaling and validating routines ***/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment