diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index d7b5dd8..cc1765d 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -626,11 +626,15 @@ _pygi_argument_to_array (GArgument  *arg,
 GArgument
 _pygi_argument_from_object (PyObject   *object,
                             GITypeInfo *type_info,
-                            GITransfer  transfer)
+                            GITransfer  transfer,
+			    GIArgInfo  *arg_info)
 {
     GArgument arg;
     GITypeTag type_tag;
 
+    GSList *call_free_list = NULL; /* list of PyGiCallbackInvokeInfo* */
+    GSList *data_for_notify = NULL; /* list of PyGiCallbackInfo* */
+
     type_tag = g_type_info_get_tag(type_info);
 
     switch (type_tag) {
@@ -844,7 +848,7 @@ _pygi_argument_from_object (PyObject   *object,
                     goto array_item_error;
                 }
 
-                item = _pygi_argument_from_object(py_item, item_type_info, item_transfer);
+                item = _pygi_argument_from_object(py_item, item_type_info, item_transfer, arg_info);
 
                 Py_DECREF(py_item);
 
@@ -880,22 +884,15 @@ array_item_error:
 
             switch (info_type) {
                 case GI_INFO_TYPE_CALLBACK:
-                {
-                    PyGICClosure *closure;
-
-                    Py_INCREF(object);
-
-                    closure = g_slice_new0(PyGICClosure);
-                    closure->info = (GICallableInfo *)g_base_info_ref(info);
-                    closure->function = object;
-                    closure->cif = g_slice_new0(ffi_cif);
-
-                    closure->closure = g_callable_info_prepare_closure(info, closure->cif, _pygi_closure_handle, closure);
-
-                    arg.v_pointer = closure->closure;
-
-                    break;
-                }
+		    {						
+			arg.v_pointer = _pygi_make_native_closure((GICallableInfo*)info,
+								  arg_info,
+								  object,
+								  &call_free_list,
+								  &destroy_notify_infos);
+			
+			break;
+		    }
                 case GI_INFO_TYPE_BOXED:
                 case GI_INFO_TYPE_STRUCT:
                 {
@@ -1021,7 +1018,7 @@ array_item_error:
                     goto list_item_error;
                 }
 
-                item = _pygi_argument_from_object(py_item, item_type_info, item_transfer);
+                item = _pygi_argument_from_object(py_item, item_type_info, item_transfer, arg_info);
 
                 Py_DECREF(py_item);
 
@@ -1120,12 +1117,12 @@ list_item_error:
                 py_key = PyList_GET_ITEM(keys, i);
                 py_value = PyList_GET_ITEM(values, i);
 
-                key = _pygi_argument_from_object(py_key, key_type_info, item_transfer);
+                key = _pygi_argument_from_object(py_key, key_type_info, item_transfer, arg_info);
                 if (PyErr_Occurred()) {
                     goto hash_table_item_error;
                 }
 
-                value = _pygi_argument_from_object(py_value, value_type_info, item_transfer);
+                value = _pygi_argument_from_object(py_value, value_type_info, item_transfer, arg_info);
                 if (PyErr_Occurred()) {
                     _pygi_argument_release(&key, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN);
                     goto hash_table_item_error;
diff --git a/gi/pygi-argument.h b/gi/pygi-argument.h
index c162f2f..0ed859b 100644
--- a/gi/pygi-argument.h
+++ b/gi/pygi-argument.h
@@ -31,6 +31,10 @@ G_BEGIN_DECLS
 
 /* Private */
 
+GSList* call_free_list;
+GSList *destroy_notify_infos;
+gint cur_arg_index;
+
 gint _pygi_g_type_info_check_object (GITypeInfo *type_info,
                                      PyObject   *object);
 
@@ -46,7 +50,8 @@ GArray* _pygi_argument_to_array (GArgument  *arg,
 
 GArgument _pygi_argument_from_object (PyObject   *object,
                                       GITypeInfo *type_info,
-                                      GITransfer  transfer);
+                                      GITransfer  transfer,
+				      GIArgInfo  *arg_info);
 
 PyObject* _pygi_argument_to_object (GArgument  *arg,
                                     GITypeInfo *type_info,
diff --git a/gi/pygi-closure.c b/gi/pygi-closure.c
index f4e1861..b140a48 100644
--- a/gi/pygi-closure.c
+++ b/gi/pygi-closure.c
@@ -21,7 +21,6 @@
 
 #include "pygi-private.h"
 
-
 void
 _pygi_closure_handle (ffi_cif *cif,
                       void    *result,
@@ -65,7 +64,103 @@ _pygi_closure_handle (ffi_cif *cif,
     Py_DECREF(py_args);
 
 end:
-    g_base_info_unref(return_type);
+    g_base_info_unref((GIBaseInfo*)return_type);
 
     PyGILState_Release(state);
+
+    /* If this was an async type closure we need to free it now that we have used it
+     */
+    if (closure->free_on_use)
+	_pygi_callback_invoke_closure_free(closure);
+
+}
+
+void _pygi_callback_notify_info_free(gpointer data)
+{
+
+    GSList* info;
+    for(info = data; info; info->next)
+	g_slice_free(PyGICallbackNotifyInfo, info->data);
+
+}
+void _pygi_callback_invoke_closure_free(gpointer data)
+{
+    PyGICClosure* invoke_closure = (PyGICClosure *)data;
+    
+    if (invoke_closure->info)
+	g_base_info_unref((GIBaseInfo*)invoke_closure->info);
+
+    munmap(invoke_closure->closure, sizeof(ffi_closure));
+    g_slice_free(ffi_cif, invoke_closure->cif);
+
+    if (!invoke_closure->is_destroy_notify)
+	Py_DECREF(invoke_closure->function);
+
+    g_slice_free(PyGICClosure, invoke_closure);
+}
+
+static void
+_pygi_destroy_notify_callback_closure(ffi_cif *cif,
+				      void *result,
+				      void **args,
+				      void *data)
+{
+    PyGICClosure *info = (PyGICClosure *)data;
+
+    _pygi_callback_invoke_closure_free(info->notify);
+    _pygi_callback_invoke_closure_free(info);    
+}
+
+
+static gboolean
+_pygi_destroy_notify_create(PyGICClosure* destroy_notify)
+{
+    static const ffi_type *destroy_notify_args[] = {&ffi_type_pointer};
+    ffi_status status;
+
+    g_assert(destroy_notify);
+
+    destroy_notify->is_destroy_notify = TRUE;
+
+    destroy_notify->closure = mmap(NULL, sizeof (ffi_closure),
+                         PROT_EXEC | PROT_READ | PROT_WRITE,
+                         MAP_ANON | MAP_PRIVATE, -1, sysconf (_SC_PAGE_SIZE));
+
+    if (!destroy_notify->closure) {
+        PyErr_SetString(PyExc_MemoryError, 
+			"mmap failed");
+        return FALSE;
+    }
+
+    destroy_notify->cif = g_slice_new(ffi_cif);
+
+    status = ffi_prep_cif(destroy_notify->cif, FFI_DEFAULT_ABI,
+                          1, &ffi_type_void,
+                          (ffi_type**)destroy_notify_args);
+    
+    if (status != FFI_OK) {
+        PyErr_SetString(PyExc_MemoryError, 
+			"ffi_prep_cif failed");
+        munmap(destroy_notify->closure, sizeof (ffi_closure));
+        return FALSE;
+    }
+
+    status = ffi_prep_closure(destroy_notify->closure, destroy_notify->cif,
+                              _pygi_destroy_notify_callback_closure, destroy_notify);
+
+    if (status != FFI_OK) {
+        PyErr_SetString(PyExc_MemoryError, 
+			"ffi_prep_closurefailed");
+        munmap(destroy_notify->closure, sizeof (ffi_closure));
+        return FALSE;
+    }
+
+    if (mprotect(destroy_notify->closure, sizeof (ffi_closure), PROT_READ | PROT_EXEC) == -1) {
+        PyErr_SetString(PyExc_MemoryError, 
+			"mprotect ffi_closure failed");
+        munmap(destroy_notify->closure, sizeof (ffi_closure));
+        return FALSE;
+    }
+
+    return TRUE;
 }
diff --git a/gi/pygi-closure.h b/gi/pygi-closure.h
index f64d7bd..67c02d0 100644
--- a/gi/pygi-closure.h
+++ b/gi/pygi-closure.h
@@ -21,26 +21,55 @@
 #define __PYGI_CLOSURE_H__
 
 #include <Python.h>
+#include <girffi.h>
 #include <ffi.h>
+#include <sys/mman.h>
 
 G_BEGIN_DECLS
 
 
 /* Private */
 
-typedef struct {
+typedef struct _PyGICClosure
+{
+    /* Need to keep a reference to the
+       notify callback such that when this destroy callback is called
+       (assuming this callback is a destroynotify)
+       it knows a reference to the actual callback */
+    struct PyGICClosure* notify;
+    
     GICallableInfo *info;
     PyObject *function;
     
     ffi_closure *closure;
     ffi_cif *cif;
+ 
+    gint arg_index;
+    gboolean free_on_use;
+    gboolean is_destroy_notify;
+    
 } PyGICClosure;
-
-
-void _pygi_closure_handle (ffi_cif *cif, 
-                           void    *result,
-                           void   **args,
-                           void    *data);
+ 
+typedef struct _PyGiCallbackNotifyInfo
+{
+    gint destroy_arg_index;
+    PyGICClosure *closure;
+} PyGICallbackNotifyInfo;
+ 
+ 
+void _pygi_handle_closure(ffi_cif *cif, void *result, void
+			  **args, void *userdata);
+ 
+void _pygi_callback_invoke_closure_free(gpointer user_data);
+ 
+void _pygi_callback_notify_info_free(gpointer user_data);
+ 
+gpointer
+_pygi_make_native_closure (GICallableInfo* info,
+			   GIArgInfo* arg_info,
+			   PyObject *function,
+			   GSList** call_free_list,
+			   GSList** destroy_notify_infos);
 
 G_END_DECLS
 
diff --git a/gi/pygi-info.c b/gi/pygi-info.c
index 18981a2..1999a53 100644
--- a/gi/pygi-info.c
+++ b/gi/pygi-info.c
@@ -547,6 +547,15 @@ _wrap_g_function_info_invoke (PyGIBaseInfo *self,
     args_is_auxiliary = g_newa(gboolean, n_args);
     memset(args_is_auxiliary, 0, sizeof(args_is_auxiliary) * n_args);
 
+
+    /* Initialize list of callbacks of scope 'call' that we will
+       free post function invokation */
+    call_free_list = NULL;
+
+    /* Initialize list of destroy indicies; metadata for callbacks
+       of scope 'notified' */
+    destroy_notify_infos = NULL;
+
     if (is_method) {
         /* The first argument is the instance. */
         n_in_args += 1;
@@ -827,7 +836,8 @@ _wrap_g_function_info_invoke (PyGIBaseInfo *self,
                 g_assert(py_args_pos < n_py_args);
                 py_arg = PyTuple_GET_ITEM(py_args, py_args_pos);
 
-                *args[i] = _pygi_argument_from_object(py_arg, arg_type_infos[i], transfer);
+		cur_arg_index = i;
+                *args[i] = _pygi_argument_from_object(py_arg, arg_type_infos[i], transfer, arg_infos[i]);
 
                 if (PyErr_Occurred()) {
                     /* TODO: release previous input arguments. */
@@ -1212,6 +1222,13 @@ _wrap_g_function_info_invoke (PyGIBaseInfo *self,
     }
 
 out:
+    /* Free any scope call callbacks */
+    g_slist_foreach(call_free_list, (GFunc)_pygi_callback_invoke_closure_free, NULL);
+    g_slist_free(call_free_list);
+
+    g_slist_foreach(destroy_notify_infos, (GFunc)_pygi_callback_notify_info_free, NULL);
+    g_slist_free(destroy_notify_infos);
+
     g_base_info_unref((GIBaseInfo *)return_type_info);
 
     for (i = 0; i < n_args; i++) {
@@ -1997,7 +2014,7 @@ _wrap_g_field_info_set_value (PyGIBaseInfo *self,
                     goto out;
                 }
 
-                value = _pygi_argument_from_object(py_value, field_type_info, GI_TRANSFER_NOTHING);
+                value = _pygi_argument_from_object(py_value, field_type_info, GI_TRANSFER_NOTHING, NULL);
                 if (PyErr_Occurred()) {
                     g_base_info_unref(info);
                     goto out;
@@ -2022,7 +2039,7 @@ _wrap_g_field_info_set_value (PyGIBaseInfo *self,
         g_base_info_unref(info);
     }
 
-    value = _pygi_argument_from_object(py_value, field_type_info, GI_TRANSFER_EVERYTHING);
+    value = _pygi_argument_from_object(py_value, field_type_info, GI_TRANSFER_EVERYTHING, NULL);
     if (PyErr_Occurred()) {
         goto out;
     }
