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



commit 12aa4e6376366ca9d758434f6544c9c70a1e5df8
Author: John (J5) Palmieri <johnp redhat com>
Date:   Tue Apr 12 14:48:16 2011 -0400

    [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

 gi/Makefile.am                |    4 ++-
 gi/pygi-cache.c               |   25 +++++++------
 gi/pygi-cache.h               |    5 ++-
 gi/pygi-invoke-ng.c           |   34 ++++++++++++++---
 gi/pygi-invoke-state-struct.h |   13 +++++++
 gi/pygi-marshal-cleanup.c     |   81 +++++++++++++++++++++++++++++++++++++++++
 gi/pygi-marshal-cleanup.h     |   43 ++++++++++++++++++++++
 gi/pygi-marshal.c             |    1 +
 8 files changed, 187 insertions(+), 19 deletions(-)
---
diff --git a/gi/Makefile.am b/gi/Makefile.am
index 8bd5057..500828d 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -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
diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c
index 323bda7..7a38db5 100644
--- a/gi/pygi-cache.c
+++ b/gi/pygi-cache.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
diff --git a/gi/pygi-cache.h b/gi/pygi-cache.h
index ec8df29..8023787 100644
--- a/gi/pygi-cache.h
+++ b/gi/pygi-cache.h
@@ -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;
diff --git a/gi/pygi-invoke-ng.c b/gi/pygi-invoke-ng.c
index c58a217..dc5bd70 100644
--- a/gi/pygi-invoke-ng.c
+++ b/gi/pygi-invoke-ng.c
@@ -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;
 }
diff --git a/gi/pygi-invoke-state-struct.h b/gi/pygi-invoke-state-struct.h
index 3147ee8..0643960 100644
--- a/gi/pygi-invoke-state-struct.h
+++ b/gi/pygi-invoke-state-struct.h
@@ -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;
 
diff --git a/gi/pygi-marshal-cleanup.c b/gi/pygi-marshal-cleanup.c
new file mode 100644
index 0000000..aaab7b3
--- /dev/null
+++ b/gi/pygi-marshal-cleanup.c
@@ -0,0 +1,81 @@
+/* -*- 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);
+}
+
diff --git a/gi/pygi-marshal-cleanup.h b/gi/pygi-marshal-cleanup.h
new file mode 100644
index 0000000..dc5d66c
--- /dev/null
+++ b/gi/pygi-marshal-cleanup.h
@@ -0,0 +1,43 @@
+/* -*- 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__ */
diff --git a/gi/pygi-marshal.c b/gi/pygi-marshal.c
index 62606b4..64a494e 100644
--- a/gi/pygi-marshal.c
+++ b/gi/pygi-marshal.c
@@ -31,6 +31,7 @@
 #include <pyglib-python-compat.h>
 
 #include "pygi-cache.h"
+#include "pygi-marshal-cleanup.h"
 
 /*** argument marshaling and validating routines ***/
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]