Commit dbbcf4a0 authored by John (J5) Palmieri's avatar John (J5) Palmieri
Browse files

[gi-invoke-ng] revamp cleanup framework to be orthogonal to cache setup

* cleanup now has symmetry with setup so there are now in and out cleanups
  for each type that needs to be cleaned up
* no longer use state machine but instead call different cleanup functions at
  different stages of invoke, making it easier to understand what happens at
  each stage
parent 198714dc
......@@ -467,7 +467,7 @@ _arg_cache_in_utf8_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->in_marshaller = _pygi_marshal_in_utf8;
arg_cache->cleanup = _pygi_marshal_cleanup_utf8;
arg_cache->in_cleanup = _pygi_marshal_cleanup_in_utf8;
}
static inline void
......@@ -475,7 +475,7 @@ _arg_cache_out_utf8_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->out_marshaller = _pygi_marshal_out_utf8;
arg_cache->cleanup = _pygi_marshal_cleanup_utf8;
arg_cache->out_cleanup = _pygi_marshal_cleanup_out_utf8;
}
static inline void
......@@ -483,7 +483,7 @@ _arg_cache_in_filename_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->in_marshaller = _pygi_marshal_in_filename;
arg_cache->cleanup = _pygi_marshal_cleanup_utf8;
arg_cache->in_cleanup = _pygi_marshal_cleanup_in_utf8;
}
static inline void
......@@ -491,7 +491,7 @@ _arg_cache_out_filename_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->out_marshaller = _pygi_marshal_out_filename;
arg_cache->cleanup = _pygi_marshal_cleanup_utf8;
arg_cache->out_cleanup = _pygi_marshal_cleanup_out_utf8;
}
static inline gboolean
......@@ -652,7 +652,9 @@ _arg_cache_in_interface_struct_setup (PyGIArgCache *arg_cache,
arg_cache->in_marshaller = _pygi_marshal_in_interface_struct;
if (iface_cache->g_type == G_TYPE_VALUE)
arg_cache->cleanup = _pygi_marshal_cleanup_gvalue;
arg_cache->in_cleanup = _pygi_marshal_cleanup_in_interface_struct_gvalue;
else if (iface_cache->is_foreign)
arg_cache->in_cleanup = _pygi_marshal_cleanup_in_interface_struct_foreign;
}
static inline void
......@@ -663,6 +665,9 @@ _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->is_foreign)
arg_cache->in_cleanup = _pygi_marshal_cleanup_out_interface_struct_foreign;
}
static inline void
......@@ -670,7 +675,7 @@ _arg_cache_in_interface_object_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->in_marshaller = _pygi_marshal_in_interface_object;
arg_cache->cleanup = _pygi_marshal_cleanup_object;
arg_cache->in_cleanup = _pygi_marshal_cleanup_in_interface_object;
}
static inline void
......@@ -678,7 +683,7 @@ _arg_cache_out_interface_object_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
arg_cache->out_marshaller = _pygi_marshal_out_interface_object;
arg_cache->cleanup = _pygi_marshal_cleanup_object;
arg_cache->out_cleanup = _pygi_marshal_cleanup_out_interface_object;
}
static inline void
......
......@@ -46,7 +46,8 @@ typedef PyObject *(*PyGIMarshalOutFunc) (PyGIInvokeState *state,
typedef void (*PyGIMarshalCleanupFunc) (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer *data);
gpointer data,
gboolean was_processed);
typedef enum {
/* Not an AUX type */
PYGI_AUX_TYPE_NONE = 0,
......@@ -72,7 +73,9 @@ struct _PyGIArgCache
PyGIMarshalInFunc in_marshaller;
PyGIMarshalOutFunc out_marshaller;
PyGIMarshalCleanupFunc cleanup;
PyGIMarshalCleanupFunc in_cleanup;
PyGIMarshalCleanupFunc out_cleanup;
GDestroyNotify destroy_notify;
gssize c_arg_index;
......
......@@ -74,7 +74,6 @@ _invoke_callable (PyGIInvokeState *state,
if (state->error != NULL) {
if (pyglib_error_check (&(state->error))) {
state->stage = PYGI_INVOKE_STAGE_NATIVE_INVOKE_FAILED;
/* even though we errored out, the call itself was successful,
so we assume the call processed all of the parameters */
pygi_marshal_cleanup_args_in_marshal_success (state, cache);
......@@ -91,7 +90,6 @@ _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);
......@@ -109,6 +107,7 @@ _invoke_state_init_from_callable_cache (PyGIInvokeState *state,
"Constructors require the class to be passed in as an argument, "
"No arguments passed to the %s constructor.",
cache->name);
return FALSE;
}
......@@ -200,8 +199,6 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache)
PyGIArgCache *arg_cache = cache->args_cache[i];
PyObject *py_arg = NULL;
state->current_arg = i;
state->stage = PYGI_INVOKE_STAGE_MARSHAL_IN_START;
switch (arg_cache->direction) {
case GI_DIRECTION_IN:
state->args[i] = &(state->in_args[in_count]);
......@@ -334,8 +331,6 @@ _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) {
......@@ -414,9 +409,6 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache)
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;
}
......
......@@ -50,6 +50,8 @@ typedef struct _PyGIInvokeState
GIArgument return_arg;
GError *error;
gboolean failed;
} PyGIInvokeState;
G_END_DECLS
......
......@@ -77,14 +77,45 @@ void
pygi_marshal_cleanup_args_in_marshal_success (PyGIInvokeState *state,
PyGICallableCache *cache)
{
int i;
/* For in success, call cleanup for all GI_DIRECTION_IN values only. */
for (i = 0; i < cache->n_args; i++) {
PyGIArgCache *arg_cache = cache->args_cache[i];
PyGIMarshalCleanupFunc cleanup_func = arg_cache->in_cleanup;
if (cleanup_func && arg_cache->direction == GI_DIRECTION_IN)
cleanup_func (state, arg_cache, state->args[i]->v_pointer, TRUE);
}
}
void
pygi_marshal_cleanup_args_invoke_success (PyGIInvokeState *state,
PyGICallableCache *cache)
pygi_marshal_cleanup_args_out_marshal_success (PyGIInvokeState *state,
PyGICallableCache *cache)
{
/* clean up the return if available */
if (cache->return_cache != NULL) {
PyGIMarshalCleanupFunc cleanup_func = cache->return_cache->out_cleanup;
if (cleanup_func)
cleanup_func (state,
cache->return_cache,
state->return_arg.v_pointer,
TRUE);
}
/* Now clean up args */
GSList *cache_item = cache->out_args;
while (cache_item) {
PyGIArgCache *arg_cache = (PyGIArgCache *) cache_item->data;
PyGIMarshalCleanupFunc cleanup_func = arg_cache->out_cleanup;
if (cleanup_func != NULL)
cleanup_func (state,
arg_cache,
state->args[arg_cache->c_arg_index]->v_pointer,
TRUE);
cache_item = cache_item->next;
}
}
void
......@@ -92,14 +123,14 @@ pygi_marshal_cleanup_args_in_parameter_fail (PyGIInvokeState *state,
PyGICallableCache *cache,
gssize failed_arg_index)
{
state->failed = TRUE;
}
void
pygi_marshal_cleanup_args_return_fail (PyGIInvokeState *state,
PyGICallableCache *cache)
{
state->failed = TRUE;
}
void
......@@ -107,203 +138,107 @@ pygi_marshal_cleanup_args_out_parameter_fail (PyGIInvokeState *state,
PyGICallableCache *cache,
gssize failed_out_arg_index)
{
state->failed = TRUE;
}
void
_pygi_marshal_cleanup_closure_unref (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data,
gboolean was_processed)
{
g_closure_unref ( (GClosure *)data);
}
void
pygi_marshal_cleanup_args (PyGIInvokeState *state,
PyGICallableCache *cache,
gboolean invoke_failure)
_pygi_marshal_cleanup_in_utf8 (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data,
gboolean was_processed)
{
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:
case PYGI_INVOKE_STAGE_NATIVE_INVOKE_FAILED:
case PYGI_INVOKE_STAGE_NATIVE_INVOKE_DONE:
{
gsize i;
/* we have not yet invoked so we only need to clean up
the in args and out caller allocates */
for (i = 0; i < state->current_arg; i++) {
PyGIArgCache *arg_cache = cache->args_cache[i];
PyGIMarshalCleanupFunc cleanup_func = arg_cache->cleanup;
/* FIXME: handle caller allocates */
if (invoke_failure &&
arg_cache->direction == GI_DIRECTION_OUT &&
arg_cache->is_caller_allocates) {
_cleanup_caller_allocates (state,
(PyGIInterfaceCache *) arg_cache,
state->args[i]->v_pointer);
} else if (cleanup_func != NULL &&
arg_cache->direction != GI_DIRECTION_OUT) {
cleanup_func (state, arg_cache, state->args[i]->v_pointer);
}
}
break;
}
case PYGI_INVOKE_STAGE_DONE:
case PYGI_INVOKE_STAGE_MARSHAL_RETURN_START:
/* clean up the return if not marshalled */
if (cache->return_cache != NULL) {
PyGIMarshalCleanupFunc cleanup_func =
cache->return_cache->cleanup;
if (cleanup_func)
cleanup_func (state,
cache->return_cache,
state->return_arg.v_pointer);
}
case PYGI_INVOKE_STAGE_MARSHAL_OUT_START:
case PYGI_INVOKE_STAGE_MARSHAL_OUT_IDLE:
case PYGI_INVOKE_STAGE_MARSHAL_RETURN_DONE:
{
/* Cleanup caller allocate args and any unmarshalled arg */
GSList *cache_item = cache->out_args;
gsize arg_index = 0;
if (state->stage == PYGI_INVOKE_STAGE_MARSHAL_OUT_START) {
/* we have not yet marshalled so decrement to end with
previous arg */
state->current_arg--;
}
/* clean up the args */
while (cache_item != NULL) {
PyGIArgCache *arg_cache = (PyGIArgCache *) cache_item->data;
PyGIMarshalCleanupFunc cleanup_func = arg_cache->cleanup;
if (arg_index > state->current_arg) {
if (cleanup_func != NULL)
cleanup_func (state,
arg_cache,
state->args[arg_cache->c_arg_index]->v_pointer);
if (arg_cache->is_caller_allocates)
_cleanup_caller_allocates (state,
(PyGIInterfaceCache *) arg_cache,
state->args[arg_cache->c_arg_index]->v_pointer);
}
arg_index++;
cache_item = cache_item->next;
}
break;
}
}
/* We strdup strings so always free if we have processed this
parameter for input */
if (was_processed)
g_free (data);
}
void
_pygi_marshal_cleanup_closure_unref (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data)
void
_pygi_marshal_cleanup_out_utf8 (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data,
gboolean was_processed)
{
g_closure_unref ( (GClosure *)data);
/* Python copies the string so we need to free it
if the interface is transfering ownership,
whether or not it has been processed yet */
if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
g_free (data);
}
void
_pygi_marshal_cleanup_utf8 (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data)
_pygi_marshal_cleanup_in_interface_object (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data,
gboolean was_processed)
{
/* For in or inout values before invoke we need to free this,
* but after invoke we we free only if transfer == GI_TRANSFER_NOTHING
* and this is not an inout value
*
* For out and inout values before invoke we do nothing but after invoke
* we free if transfer == GI_TRANSFER_EVERYTHING
*/
switch (state->stage) {
case PYGI_INVOKE_STAGE_MARSHAL_IN_START:
case PYGI_INVOKE_STAGE_MARSHAL_IN_IDLE:
g_free (data);
break;
case PYGI_INVOKE_STAGE_NATIVE_INVOKE_FAILED:
case PYGI_INVOKE_STAGE_NATIVE_INVOKE_DONE:
if (arg_cache->transfer == GI_TRANSFER_NOTHING &&
arg_cache->direction == GI_DIRECTION_IN)
g_free (data);
break;
case PYGI_INVOKE_STAGE_MARSHAL_RETURN_START:
case PYGI_INVOKE_STAGE_MARSHAL_RETURN_DONE:
case PYGI_INVOKE_STAGE_MARSHAL_OUT_START:
case PYGI_INVOKE_STAGE_MARSHAL_OUT_IDLE:
if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
g_free (data);
break;
default:
break;
}
/* If we processed the parameter but fail before invoking the method,
we need to remove the ref we added */
if (was_processed && state->failed && data != NULL &&
arg_cache->transfer == GI_TRANSFER_EVERYTHING)
g_object_unref (G_OBJECT(data));
}
void
_pygi_marshal_cleanup_object (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data)
_pygi_marshal_cleanup_out_interface_object (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data,
gboolean was_processed)
{
/* For in or inout values before invoke we need to unref
* only if transfer == GI_TRANSFER_EVERYTHING
*
* For out and inout values before invoke we do nothing but after invoke
* we unref if transfer == GI_TRANSFER_EVERYTHING
*/
switch (state->stage) {
case PYGI_INVOKE_STAGE_MARSHAL_IN_START:
case PYGI_INVOKE_STAGE_MARSHAL_IN_IDLE:
if (arg_cache->transfer == GI_TRANSFER_EVERYTHING &&
arg_cache->direction == GI_DIRECTION_IN)
g_object_unref (G_OBJECT(data));
break;
case PYGI_INVOKE_STAGE_NATIVE_INVOKE_FAILED:
case PYGI_INVOKE_STAGE_NATIVE_INVOKE_DONE:
break;
case PYGI_INVOKE_STAGE_MARSHAL_RETURN_START:
case PYGI_INVOKE_STAGE_MARSHAL_RETURN_DONE:
case PYGI_INVOKE_STAGE_MARSHAL_OUT_START:
case PYGI_INVOKE_STAGE_MARSHAL_OUT_IDLE:
if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
g_object_unref (G_OBJECT(data));
break;
default:
break;
}
/* If we error out and the object is not marshalled into a PyGObject
we must take care of removing the ref */
if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
g_object_unref (G_OBJECT(data));
}
void
_pygi_marshal_cleanup_gvalue (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data)
_pygi_marshal_cleanup_in_interface_struct_gvalue (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data,
gboolean was_processed)
{
if (was_processed) {
PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args,
arg_cache->py_arg_index);
GType py_object_type =
pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE);
if (py_object_type != G_TYPE_VALUE) {
g_value_unset ((GValue *) data);
g_slice_free (GValue, data);
}
}
}
void
_pygi_marshal_cleanup_in_interface_struct_foreign (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data,
gboolean was_processed)
{
if (state->failed && was_processed)
pygi_struct_foreign_release (
( (PyGIInterfaceCache *)arg_cache)->interface_info,
data);
}
void
_pygi_marshal_cleanup_out_interface_struct_foreign (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data,
gboolean was_processed)
{
/* For in or inout values before invoke we need to unset and slice_free
* After invoke we unset and free if transfer == GI_TRANSFER_NOTHING
*
* For out values before invoke we do nothing but after invoke
* we unset if transfer == GI_TRANSFER_EVERYTHING
*
*/
switch (state->stage) {
case PYGI_INVOKE_STAGE_MARSHAL_IN_START:
case PYGI_INVOKE_STAGE_MARSHAL_IN_IDLE:
g_value_unset ((GValue *) data);
g_slice_free (GValue, data);
break;
case PYGI_INVOKE_STAGE_NATIVE_INVOKE_FAILED:
case PYGI_INVOKE_STAGE_NATIVE_INVOKE_DONE:
break;
case PYGI_INVOKE_STAGE_MARSHAL_RETURN_START:
case PYGI_INVOKE_STAGE_MARSHAL_RETURN_DONE:
case PYGI_INVOKE_STAGE_MARSHAL_OUT_START:
case PYGI_INVOKE_STAGE_MARSHAL_OUT_IDLE:
if (arg_cache->transfer == GI_TRANSFER_EVERYTHING)
g_value_unset ((GValue *) data);
break;
default:
break;
}
if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
pygi_struct_foreign_release (
( (PyGIInterfaceCache *)arg_cache)->interface_info,
data);
}
......@@ -40,22 +40,35 @@ void pygi_marshal_cleanup_args_out_parameter_fail (PyGIInvokeState *state,
PyGICallableCache *cache,
gssize failed_out_arg_index);
void pygi_marshal_cleanup_args (PyGIInvokeState *state,
PyGICallableCache *cache,
gboolean invoke_failure);
void _pygi_marshal_cleanup_utf8 (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data);
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 (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data);
void _pygi_marshal_cleanup_in_utf8 (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data,
gboolean was_processed);
void _pygi_marshal_cleanup_out_utf8 (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data,
gboolean was_processed);
void _pygi_marshal_cleanup_in_interface_struct_gvalue (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data,
gboolean was_processed);
void _pygi_marshal_cleanup_in_interface_struct_foreign (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data,
gboolean was_processed);
void _pygi_marshal_cleanup_out_interface_struct_foreign (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data,
gboolean was_processed);
void _pygi_marshal_cleanup_in_interface_object (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data,
gboolean was_processed);
void _pygi_marshal_cleanup_out_interface_object (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
gpointer data,
gboolean was_processed);
G_END_DECLS
#endif /* __PYGI_MARSHAL_CLEANUP_H__ */
......@@ -722,8 +722,8 @@ _pygi_marshal_in_array (PyGIInvokeState *state,
g_array_insert_val (array_, i, item);
continue;
err:
if (sequence_cache->item_cache->cleanup != NULL) {
GDestroyNotify cleanup = sequence_cache->item_cache->cleanup;
if (sequence_cache->item_cache->in_cleanup != NULL) {
GDestroyNotify cleanup = sequence_cache->item_cache->in_cleanup;
/*for(j = 0; j < i; j++)
cleanup((gpointer)(array_->data[j]));*/
}
......@@ -815,8 +815,8 @@ _pygi_marshal_in_glist (PyGIInvokeState *state,
list_ = g_list_append (list_, item.v_pointer);
continue;
err:
if (sequence_cache->item_cache->cleanup != NULL) {
GDestroyNotify cleanup = sequence_cache->item_cache->cleanup;
if (sequence_cache->item_cache->in_cleanup != NULL) {
GDestroyNotify cleanup = sequence_cache->item_cache->in_cleanup;
}
g_list_free (list_);
......@@ -881,8 +881,8 @@ _pygi_marshal_in_gslist (PyGIInvokeState *state,
list_ = g_slist_append (list_, item.v_pointer);
continue;
err:
if (sequence_cache->item_cache->cleanup != NULL) {
GDestroyNotify cleanup = sequence_cache->item_cache->cleanup;
if (sequence_cache->item_cache->in_cleanup != NULL) {
GDestroyNotify cleanup = sequence_cache->item_cache->in_cleanup;
}
g_slist_free (list_);
......@@ -1217,12 +1217,11 @@ _pygi_marshal_in_interface_struct (PyGIInvokeState *state,
return FALSE;
}
value = g_slice_new0 (GValue);
/* if already a gvalue, use that, else marshal into gvalue */
if (object_type == G_TYPE_VALUE) {
value = (GValue *)( (PyGObject *)py_arg)->obj;
} else {
value = g_slice_new0 (GValue);
g_value_init (value, object_type);
if (pyg_value_from_pyobject (value, py_arg) < 0) {
g_slice_free (GValue, value);
......
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